github.com/benma/gogen@v0.0.0-20160826115606-cf49914b915a/unmarshalmap/generator.go (about) 1 package unmarshalmap 2 3 import ( 4 "bytes" 5 "fmt" 6 "go/types" 7 "io" 8 "path/filepath" 9 "text/template" 10 11 "github.com/ernesto-jimenez/gogen/cleanimports" 12 "github.com/ernesto-jimenez/gogen/gogenutil" 13 "github.com/ernesto-jimenez/gogen/importer" 14 "github.com/ernesto-jimenez/gogen/imports" 15 ) 16 17 // Generator will generate the UnmarshalMap function 18 type Generator struct { 19 name string 20 targetName string 21 namePkg string 22 pkg *types.Package 23 target *types.Struct 24 } 25 26 // NewGenerator initializes a Generator 27 func NewGenerator(pkg, target string) (*Generator, error) { 28 var err error 29 if pkg == "" || pkg[0] == '.' { 30 pkg, err = filepath.Abs(filepath.Clean(pkg)) 31 if err != nil { 32 return nil, err 33 } 34 pkg = gogenutil.StripGopath(pkg) 35 } 36 p, err := importer.Default().Import(pkg) 37 if err != nil { 38 return nil, err 39 } 40 obj := p.Scope().Lookup(target) 41 if obj == nil { 42 return nil, fmt.Errorf("struct %s missing", target) 43 } 44 if _, ok := obj.Type().Underlying().(*types.Struct); !ok { 45 return nil, fmt.Errorf("%s should be an struct, was %s", target, obj.Type().Underlying()) 46 } 47 return &Generator{ 48 targetName: target, 49 pkg: p, 50 target: obj.Type().Underlying().(*types.Struct), 51 }, nil 52 } 53 54 func (g Generator) Fields() []Field { 55 numFields := g.target.NumFields() 56 fields := make([]Field, 0) 57 for i := 0; i < numFields; i++ { 58 f := Field{&g, g.target.Tag(i), g.target.Field(i)} 59 if f.Field() != "" { 60 fields = append(fields, f) 61 } 62 } 63 return fields 64 } 65 66 func (g Generator) qf(pkg *types.Package) string { 67 if g.pkg == pkg { 68 return "" 69 } 70 return pkg.Name() 71 } 72 73 func (g Generator) Name() string { 74 name := g.targetName 75 return name 76 } 77 78 func (g Generator) Package() string { 79 if g.namePkg != "" { 80 return g.namePkg 81 } 82 return g.pkg.Name() 83 } 84 85 func (g *Generator) SetPackage(name string) { 86 g.namePkg = name 87 } 88 89 func (g Generator) Imports() map[string]string { 90 imports := imports.New(g.Package()) 91 fields := g.Fields() 92 for i := 0; i < len(fields); i++ { 93 m := fields[i] 94 imports.AddImportsFrom(m.v.Type()) 95 imports.AddImportsFrom(m.UnderlyingType()) 96 if sub := m.UnderlyingTarget(); sub != nil { 97 fields = append(fields, sub.Fields()...) 98 } 99 } 100 return imports.Imports() 101 } 102 103 func (g Generator) Write(wr io.Writer) error { 104 var buf bytes.Buffer 105 if err := fnTmpl.Execute(&buf, g); err != nil { 106 return err 107 } 108 return cleanimports.Clean(wr, buf.Bytes()) 109 } 110 111 func (g Generator) WriteTest(wr io.Writer) error { 112 var buf bytes.Buffer 113 if err := testTmpl.Execute(&buf, g); err != nil { 114 return err 115 } 116 return cleanimports.Clean(wr, buf.Bytes()) 117 } 118 119 var ( 120 testTmpl = template.Must(template.New("test").Parse(`/* 121 * CODE GENERATED AUTOMATICALLY WITH github.com/ernesto-jimenez/gogen/unmarshalmap 122 * THIS FILE SHOULD NOT BE EDITED BY HAND 123 */ 124 125 package {{.Package}} 126 127 import ( 128 "testing" 129 test "github.com/ernesto-jimenez/gogen/unmarshalmap/testunmarshalmap" 130 ) 131 132 func Test{{.Name}}UnmarshalMap(t *testing.T) { 133 test.Run(t, &{{.Name}}{}) 134 } 135 `)) 136 fnTmpl = template.Must(template.New("func").Parse(`/* 137 * CODE GENERATED AUTOMATICALLY WITH github.com/ernesto-jimenez/gogen/unmarshalmap 138 * THIS FILE SHOULD NOT BE EDITED BY HAND 139 */ 140 141 package {{.Package}} 142 143 import ( 144 "fmt" 145 {{range $path, $name := .Imports}} 146 {{$name}} "{{$path}}"{{end}} 147 ) 148 149 {{define "UNMARSHALFIELDS"}} 150 {{range .Fields}} 151 {{if .IsAnonymous}} 152 // Anonymous {{.Name}} 153 if scoped := true; scoped { 154 var s *{{.Type}} = &s.{{.Name}} 155 // Fill object 156 {{template "UNMARSHALFIELDS" .UnderlyingTarget}} 157 } 158 {{else if .IsArrayOrSlice}} 159 // ArrayOrSlice {{.Name}} 160 {{if .UnderlyingIsBasic}} 161 if v, ok := m["{{.Field}}"].([]{{.UnderlyingType}}); ok { 162 {{if .IsSlice}} 163 s.{{.Name}} = make({{.Type}}, len(v)) 164 {{else}} 165 if len(s.{{.Name}}) < len(v) { 166 return fmt.Errorf("expected field {{.Field}} to be an array with %d elements, but got an array with %d", len(s.{{.Name}}), len(v)) 167 } 168 {{end}} 169 for i, el := range v { 170 s.{{.Name}}[i] = el 171 } 172 } else if v, ok := m["{{.Field}}"].([]interface{}); ok { 173 {{if .IsSlice}} 174 s.{{.Name}} = make({{.Type}}, len(v)) 175 {{else}} 176 if len(s.{{.Name}}) < len(v) { 177 return fmt.Errorf("expected field {{.Field}} to be an array with %d elements, but got an array with %d", len(s.{{.Name}}), len(v)) 178 } 179 {{end}} 180 for i, el := range v { 181 if v, ok := el.({{.UnderlyingType}}); ok { 182 s.{{.Name}}[i] = v 183 {{if .UnderlyingConvertibleFromFloat64}} 184 } else if m, ok := el.(float64); ok { 185 v := {{.UnderlyingType}}(m) 186 s.{{.Name}} = v 187 {{end}} 188 } else { 189 return fmt.Errorf("expected field {{.Field}}[%d] to be {{.UnderlyingType}} but got %T", i, el) 190 } 191 } 192 } else if v, exists := m["{{.Field}}"]; exists && v != nil { 193 return fmt.Errorf("expected field {{.Field}} to be []{{.UnderlyingType}} but got %T", m["{{.Field}}"]) 194 } 195 {{else}} 196 if v, ok := m["{{.Field}}"].([]interface{}); ok { 197 {{if .IsSlice}} 198 s.{{.Name}} = make({{.Type}}, len(v)) 199 {{else}} 200 if len(s.{{.Name}}) < len(v) { 201 return fmt.Errorf("expected field {{.Field}} to be an array with %d elements, but got an array with %d", len(s.{{.Name}}), len(v)) 202 } 203 {{end}} 204 prev := s 205 for i, el := range v { 206 var s *{{.UnderlyingTypeName}} 207 {{if .UnderlyingIsPointer}} 208 if el == nil { 209 continue 210 } 211 prev.{{.Name}}[i] = &{{.UnderlyingTypeName}}{} 212 s = prev.{{.Name}}[i] 213 {{else}} 214 s = &prev.{{.Name}}[i] 215 {{end}} 216 if m, ok := el.(map[string]interface{}); ok { 217 // Fill object 218 {{template "UNMARSHALFIELDS" .UnderlyingTarget}} 219 } 220 } 221 } else if v, exists := m["{{.Field}}"]; exists && v != nil { 222 return fmt.Errorf("expected field {{.Field}} to be []interface{} but got %T", m["{{.Field}}"]) 223 } 224 {{end}} 225 {{else if .IsPointer}} 226 // Pointer {{.Name}} 227 if p, ok := m["{{.Field}}"]; ok { 228 {{if .UnderlyingIsBasic}} 229 if m, ok := p.({{.UnderlyingType}}); ok { 230 s.{{.Name}} = &m 231 {{if .UnderlyingConvertibleFromFloat64}} 232 } else if m, ok := p.(float64); ok { 233 v := {{.UnderlyingType}}(m) 234 s.{{.Name}} = &v 235 {{end}} 236 } else if p == nil { 237 s.{{.Name}} = nil 238 } 239 {{else}} 240 if m, ok := p.(map[string]interface{}); ok { 241 if s.{{.Name}} == nil { 242 s.{{.Name}} = &{{.UnderlyingTypeName}}{} 243 } 244 s := s.{{.Name}} 245 {{template "UNMARSHALFIELDS" .UnderlyingTarget}} 246 } else if p == nil { 247 s.{{.Name}} = nil 248 } else { 249 return fmt.Errorf("expected field {{.Field}} to be map[string]interface{} but got %T", p) 250 } 251 {{end}} 252 } 253 {{else if .IsStruct}} 254 // Struct {{.Name}} 255 if m, ok := m["{{.Field}}"].(map[string]interface{}); ok { 256 var s *{{.Type}} = &s.{{.Name}} 257 // Fill object 258 {{template "UNMARSHALFIELDS" .UnderlyingTarget}} 259 } else if v, exists := m["{{.Field}}"]; exists && v != nil { 260 return fmt.Errorf("expected field {{.Field}} to be map[string]interface{} but got %T", m["{{.Field}}"]) 261 } 262 {{else}} 263 if v, ok := m["{{.Field}}"].({{.Type}}); ok { 264 s.{{.Name}} = v 265 {{if .ConvertibleFromFloat64}} 266 } else if p, ok := m["{{.Field}}"].(float64); ok { 267 v := {{.Type}}(p) 268 s.{{.Name}} = v 269 {{end}} 270 } else if v, exists := m["{{.Field}}"]; exists && v != nil { 271 return fmt.Errorf("expected field {{.Field}} to be {{.Type}} but got %T", m["{{.Field}}"]) 272 } 273 {{end}} 274 {{end}} 275 {{end}} 276 277 // UnmarshalMap takes a map and unmarshals the fieds into the struct 278 func (s *{{.Name}}) UnmarshalMap(m map[string]interface{}) error { 279 {{template "UNMARSHALFIELDS" .}} 280 return nil 281 } 282 `)) 283 )