1 package gen
2
3 import (
4 "encoding"
5 "encoding/json"
6 "fmt"
7 "reflect"
8 "strconv"
9 "strings"
10
11 "github.com/mailru/easyjson"
12 )
13
14 func (g *Generator) getEncoderName(t reflect.Type) string {
15 return g.functionName("encode", t)
16 }
17
18 var primitiveEncoders = map[reflect.Kind]string{
19 reflect.String: "out.String(string(%v))",
20 reflect.Bool: "out.Bool(bool(%v))",
21 reflect.Int: "out.Int(int(%v))",
22 reflect.Int8: "out.Int8(int8(%v))",
23 reflect.Int16: "out.Int16(int16(%v))",
24 reflect.Int32: "out.Int32(int32(%v))",
25 reflect.Int64: "out.Int64(int64(%v))",
26 reflect.Uint: "out.Uint(uint(%v))",
27 reflect.Uint8: "out.Uint8(uint8(%v))",
28 reflect.Uint16: "out.Uint16(uint16(%v))",
29 reflect.Uint32: "out.Uint32(uint32(%v))",
30 reflect.Uint64: "out.Uint64(uint64(%v))",
31 reflect.Float32: "out.Float32(float32(%v))",
32 reflect.Float64: "out.Float64(float64(%v))",
33 }
34
35 var primitiveStringEncoders = map[reflect.Kind]string{
36 reflect.String: "out.String(string(%v))",
37 reflect.Int: "out.IntStr(int(%v))",
38 reflect.Int8: "out.Int8Str(int8(%v))",
39 reflect.Int16: "out.Int16Str(int16(%v))",
40 reflect.Int32: "out.Int32Str(int32(%v))",
41 reflect.Int64: "out.Int64Str(int64(%v))",
42 reflect.Uint: "out.UintStr(uint(%v))",
43 reflect.Uint8: "out.Uint8Str(uint8(%v))",
44 reflect.Uint16: "out.Uint16Str(uint16(%v))",
45 reflect.Uint32: "out.Uint32Str(uint32(%v))",
46 reflect.Uint64: "out.Uint64Str(uint64(%v))",
47 reflect.Uintptr: "out.UintptrStr(uintptr(%v))",
48 reflect.Float32: "out.Float32Str(float32(%v))",
49 reflect.Float64: "out.Float64Str(float64(%v))",
50 }
51
52
53 type fieldTags struct {
54 name string
55
56 omit bool
57 omitEmpty bool
58 noOmitEmpty bool
59 asString bool
60 required bool
61 intern bool
62 noCopy bool
63 }
64
65
66 func parseFieldTags(f reflect.StructField) fieldTags {
67 var ret fieldTags
68
69 for i, s := range strings.Split(f.Tag.Get("json"), ",") {
70 switch {
71 case i == 0 && s == "-":
72 ret.omit = true
73 case i == 0:
74 ret.name = s
75 case s == "omitempty":
76 ret.omitEmpty = true
77 case s == "!omitempty":
78 ret.noOmitEmpty = true
79 case s == "string":
80 ret.asString = true
81 case s == "required":
82 ret.required = true
83 case s == "intern":
84 ret.intern = true
85 case s == "nocopy":
86 ret.noCopy = true
87 }
88 }
89
90 return ret
91 }
92
93
94 func (g *Generator) genTypeEncoder(t reflect.Type, in string, tags fieldTags, indent int, assumeNonEmpty bool) error {
95 ws := strings.Repeat(" ", indent)
96
97 marshalerIface := reflect.TypeOf((*easyjson.Marshaler)(nil)).Elem()
98 if reflect.PtrTo(t).Implements(marshalerIface) {
99 fmt.Fprintln(g.out, ws+"("+in+").MarshalEasyJSON(out)")
100 return nil
101 }
102
103 marshalerIface = reflect.TypeOf((*json.Marshaler)(nil)).Elem()
104 if reflect.PtrTo(t).Implements(marshalerIface) {
105 fmt.Fprintln(g.out, ws+"out.Raw( ("+in+").MarshalJSON() )")
106 return nil
107 }
108
109 marshalerIface = reflect.TypeOf((*encoding.TextMarshaler)(nil)).Elem()
110 if reflect.PtrTo(t).Implements(marshalerIface) {
111 fmt.Fprintln(g.out, ws+"out.RawText( ("+in+").MarshalText() )")
112 return nil
113 }
114
115 err := g.genTypeEncoderNoCheck(t, in, tags, indent, assumeNonEmpty)
116 return err
117 }
118
119
120 func hasCustomMarshaler(t reflect.Type) bool {
121 t = reflect.PtrTo(t)
122 return t.Implements(reflect.TypeOf((*easyjson.Marshaler)(nil)).Elem()) ||
123 t.Implements(reflect.TypeOf((*json.Marshaler)(nil)).Elem()) ||
124 t.Implements(reflect.TypeOf((*encoding.TextMarshaler)(nil)).Elem())
125 }
126
127
128 func (g *Generator) genTypeEncoderNoCheck(t reflect.Type, in string, tags fieldTags, indent int, assumeNonEmpty bool) error {
129 ws := strings.Repeat(" ", indent)
130
131
132 if enc := primitiveStringEncoders[t.Kind()]; enc != "" && tags.asString {
133 fmt.Fprintf(g.out, ws+enc+"\n", in)
134 return nil
135 }
136
137 if enc := primitiveEncoders[t.Kind()]; enc != "" {
138 fmt.Fprintf(g.out, ws+enc+"\n", in)
139 return nil
140 }
141
142 switch t.Kind() {
143 case reflect.Slice:
144 elem := t.Elem()
145 iVar := g.uniqueVarName()
146 vVar := g.uniqueVarName()
147
148 if t.Elem().Kind() == reflect.Uint8 && elem.Name() == "uint8" {
149 if g.simpleBytes {
150 fmt.Fprintln(g.out, ws+"out.String(string("+in+"))")
151 } else {
152 fmt.Fprintln(g.out, ws+"out.Base64Bytes("+in+")")
153 }
154 } else {
155 if !assumeNonEmpty {
156 fmt.Fprintln(g.out, ws+"if "+in+" == nil && (out.Flags & jwriter.NilSliceAsEmpty) == 0 {")
157 fmt.Fprintln(g.out, ws+` out.RawString("null")`)
158 fmt.Fprintln(g.out, ws+"} else {")
159 } else {
160 fmt.Fprintln(g.out, ws+"{")
161 }
162 fmt.Fprintln(g.out, ws+" out.RawByte('[')")
163 fmt.Fprintln(g.out, ws+" for "+iVar+", "+vVar+" := range "+in+" {")
164 fmt.Fprintln(g.out, ws+" if "+iVar+" > 0 {")
165 fmt.Fprintln(g.out, ws+" out.RawByte(',')")
166 fmt.Fprintln(g.out, ws+" }")
167
168 if err := g.genTypeEncoder(elem, vVar, tags, indent+2, false); err != nil {
169 return err
170 }
171
172 fmt.Fprintln(g.out, ws+" }")
173 fmt.Fprintln(g.out, ws+" out.RawByte(']')")
174 fmt.Fprintln(g.out, ws+"}")
175 }
176
177 case reflect.Array:
178 elem := t.Elem()
179 iVar := g.uniqueVarName()
180
181 if t.Elem().Kind() == reflect.Uint8 && elem.Name() == "uint8" {
182 if g.simpleBytes {
183 fmt.Fprintln(g.out, ws+"out.String(string("+in+"[:]))")
184 } else {
185 fmt.Fprintln(g.out, ws+"out.Base64Bytes("+in+"[:])")
186 }
187 } else {
188 fmt.Fprintln(g.out, ws+"out.RawByte('[')")
189 fmt.Fprintln(g.out, ws+"for "+iVar+" := range "+in+" {")
190 fmt.Fprintln(g.out, ws+" if "+iVar+" > 0 {")
191 fmt.Fprintln(g.out, ws+" out.RawByte(',')")
192 fmt.Fprintln(g.out, ws+" }")
193
194 if err := g.genTypeEncoder(elem, "("+in+")["+iVar+"]", tags, indent+1, false); err != nil {
195 return err
196 }
197
198 fmt.Fprintln(g.out, ws+"}")
199 fmt.Fprintln(g.out, ws+"out.RawByte(']')")
200 }
201
202 case reflect.Struct:
203 enc := g.getEncoderName(t)
204 g.addType(t)
205
206 fmt.Fprintln(g.out, ws+enc+"(out, "+in+")")
207
208 case reflect.Ptr:
209 if !assumeNonEmpty {
210 fmt.Fprintln(g.out, ws+"if "+in+" == nil {")
211 fmt.Fprintln(g.out, ws+` out.RawString("null")`)
212 fmt.Fprintln(g.out, ws+"} else {")
213 }
214
215 if err := g.genTypeEncoder(t.Elem(), "*"+in, tags, indent+1, false); err != nil {
216 return err
217 }
218
219 if !assumeNonEmpty {
220 fmt.Fprintln(g.out, ws+"}")
221 }
222
223 case reflect.Map:
224 key := t.Key()
225 keyEnc, ok := primitiveStringEncoders[key.Kind()]
226 if !ok && !hasCustomMarshaler(key) {
227 return fmt.Errorf("map key type %v not supported: only string and integer keys and types implementing Marshaler interfaces are allowed", key)
228 }
229 tmpVar := g.uniqueVarName()
230
231 if !assumeNonEmpty {
232 fmt.Fprintln(g.out, ws+"if "+in+" == nil && (out.Flags & jwriter.NilMapAsEmpty) == 0 {")
233 fmt.Fprintln(g.out, ws+" out.RawString(`null`)")
234 fmt.Fprintln(g.out, ws+"} else {")
235 } else {
236 fmt.Fprintln(g.out, ws+"{")
237 }
238 fmt.Fprintln(g.out, ws+" out.RawByte('{')")
239 fmt.Fprintln(g.out, ws+" "+tmpVar+"First := true")
240 fmt.Fprintln(g.out, ws+" for "+tmpVar+"Name, "+tmpVar+"Value := range "+in+" {")
241 fmt.Fprintln(g.out, ws+" if "+tmpVar+"First { "+tmpVar+"First = false } else { out.RawByte(',') }")
242
243
244 if reflect.PtrTo(key).Implements(reflect.TypeOf((*encoding.TextMarshaler)(nil)).Elem()) {
245 fmt.Fprintln(g.out, ws+" "+fmt.Sprintf("out.RawText(("+tmpVar+"Name).MarshalText()"+")"))
246 } else if keyEnc != "" {
247 fmt.Fprintln(g.out, ws+" "+fmt.Sprintf(keyEnc, tmpVar+"Name"))
248 } else {
249 if err := g.genTypeEncoder(key, tmpVar+"Name", tags, indent+2, false); err != nil {
250 return err
251 }
252 }
253
254 fmt.Fprintln(g.out, ws+" out.RawByte(':')")
255
256 if err := g.genTypeEncoder(t.Elem(), tmpVar+"Value", tags, indent+2, false); err != nil {
257 return err
258 }
259
260 fmt.Fprintln(g.out, ws+" }")
261 fmt.Fprintln(g.out, ws+" out.RawByte('}')")
262 fmt.Fprintln(g.out, ws+"}")
263
264 case reflect.Interface:
265 if t.NumMethod() != 0 {
266 if g.interfaceIsEasyjsonMarshaller(t) {
267 fmt.Fprintln(g.out, ws+in+".MarshalEasyJSON(out)")
268 } else if g.interfaceIsJSONMarshaller(t) {
269 fmt.Fprintln(g.out, ws+"if m, ok := "+in+".(easyjson.Marshaler); ok {")
270 fmt.Fprintln(g.out, ws+" m.MarshalEasyJSON(out)")
271 fmt.Fprintln(g.out, ws+"} else {")
272 fmt.Fprintln(g.out, ws+in+".MarshalJSON(out)")
273 fmt.Fprintln(g.out, ws+"}")
274 } else {
275 return fmt.Errorf("interface type %v not supported: only interface{} and interfaces that implement json or easyjson Marshaling are allowed", t)
276 }
277 } else {
278 fmt.Fprintln(g.out, ws+"if m, ok := "+in+".(easyjson.Marshaler); ok {")
279 fmt.Fprintln(g.out, ws+" m.MarshalEasyJSON(out)")
280 fmt.Fprintln(g.out, ws+"} else if m, ok := "+in+".(json.Marshaler); ok {")
281 fmt.Fprintln(g.out, ws+" out.Raw(m.MarshalJSON())")
282 fmt.Fprintln(g.out, ws+"} else {")
283 fmt.Fprintln(g.out, ws+" out.Raw(json.Marshal("+in+"))")
284 fmt.Fprintln(g.out, ws+"}")
285 }
286 default:
287 return fmt.Errorf("don't know how to encode %v", t)
288 }
289 return nil
290 }
291
292 func (g *Generator) interfaceIsEasyjsonMarshaller(t reflect.Type) bool {
293 return t.Implements(reflect.TypeOf((*easyjson.Marshaler)(nil)).Elem())
294 }
295
296 func (g *Generator) interfaceIsJSONMarshaller(t reflect.Type) bool {
297 return t.Implements(reflect.TypeOf((*json.Marshaler)(nil)).Elem())
298 }
299
300 func (g *Generator) notEmptyCheck(t reflect.Type, v string) string {
301 optionalIface := reflect.TypeOf((*easyjson.Optional)(nil)).Elem()
302 if reflect.PtrTo(t).Implements(optionalIface) {
303 return "(" + v + ").IsDefined()"
304 }
305
306 switch t.Kind() {
307 case reflect.Slice, reflect.Map:
308 return "len(" + v + ") != 0"
309 case reflect.Interface, reflect.Ptr:
310 return v + " != nil"
311 case reflect.Bool:
312 return v
313 case reflect.String:
314 return v + ` != ""`
315 case reflect.Float32, reflect.Float64,
316 reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64,
317 reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
318
319 return v + " != 0"
320
321 default:
322
323 return "true"
324 }
325 }
326
327 func (g *Generator) genStructFieldEncoder(t reflect.Type, f reflect.StructField, first, firstCondition bool) (bool, error) {
328 jsonName := g.fieldNamer.GetJSONFieldName(t, f)
329 tags := parseFieldTags(f)
330
331 if tags.omit {
332 return firstCondition, nil
333 }
334
335 toggleFirstCondition := firstCondition
336
337 noOmitEmpty := (!tags.omitEmpty && !g.omitEmpty) || tags.noOmitEmpty
338 if noOmitEmpty {
339 fmt.Fprintln(g.out, " {")
340 toggleFirstCondition = false
341 } else {
342 fmt.Fprintln(g.out, " if", g.notEmptyCheck(f.Type, "in."+f.Name), "{")
343
344 }
345
346 if firstCondition {
347 fmt.Fprintf(g.out, " const prefix string = %q\n", ","+strconv.Quote(jsonName)+":")
348 if first {
349 if !noOmitEmpty {
350 fmt.Fprintln(g.out, " first = false")
351 }
352 fmt.Fprintln(g.out, " out.RawString(prefix[1:])")
353 } else {
354 fmt.Fprintln(g.out, " if first {")
355 fmt.Fprintln(g.out, " first = false")
356 fmt.Fprintln(g.out, " out.RawString(prefix[1:])")
357 fmt.Fprintln(g.out, " } else {")
358 fmt.Fprintln(g.out, " out.RawString(prefix)")
359 fmt.Fprintln(g.out, " }")
360 }
361 } else {
362 fmt.Fprintf(g.out, " const prefix string = %q\n", ","+strconv.Quote(jsonName)+":")
363 fmt.Fprintln(g.out, " out.RawString(prefix)")
364 }
365
366 if err := g.genTypeEncoder(f.Type, "in."+f.Name, tags, 2, !noOmitEmpty); err != nil {
367 return toggleFirstCondition, err
368 }
369 fmt.Fprintln(g.out, " }")
370 return toggleFirstCondition, nil
371 }
372
373 func (g *Generator) genEncoder(t reflect.Type) error {
374 switch t.Kind() {
375 case reflect.Slice, reflect.Array, reflect.Map:
376 return g.genSliceArrayMapEncoder(t)
377 default:
378 return g.genStructEncoder(t)
379 }
380 }
381
382 func (g *Generator) genSliceArrayMapEncoder(t reflect.Type) error {
383 switch t.Kind() {
384 case reflect.Slice, reflect.Array, reflect.Map:
385 default:
386 return fmt.Errorf("cannot generate encoder/decoder for %v, not a slice/array/map type", t)
387 }
388
389 fname := g.getEncoderName(t)
390 typ := g.getType(t)
391
392 fmt.Fprintln(g.out, "func "+fname+"(out *jwriter.Writer, in "+typ+") {")
393 err := g.genTypeEncoderNoCheck(t, "in", fieldTags{}, 1, false)
394 if err != nil {
395 return err
396 }
397 fmt.Fprintln(g.out, "}")
398 return nil
399 }
400
401 func (g *Generator) genStructEncoder(t reflect.Type) error {
402 if t.Kind() != reflect.Struct {
403 return fmt.Errorf("cannot generate encoder/decoder for %v, not a struct type", t)
404 }
405
406 fname := g.getEncoderName(t)
407 typ := g.getType(t)
408
409 fmt.Fprintln(g.out, "func "+fname+"(out *jwriter.Writer, in "+typ+") {")
410 fmt.Fprintln(g.out, " out.RawByte('{')")
411 fmt.Fprintln(g.out, " first := true")
412 fmt.Fprintln(g.out, " _ = first")
413
414 fs, err := getStructFields(t)
415 if err != nil {
416 return fmt.Errorf("cannot generate encoder for %v: %v", t, err)
417 }
418
419 firstCondition := true
420 for i, f := range fs {
421 firstCondition, err = g.genStructFieldEncoder(t, f, i == 0, firstCondition)
422
423 if err != nil {
424 return err
425 }
426 }
427
428 if hasUnknownsMarshaler(t) {
429 if !firstCondition {
430 fmt.Fprintln(g.out, " in.MarshalUnknowns(out, false)")
431 } else {
432 fmt.Fprintln(g.out, " in.MarshalUnknowns(out, first)")
433 }
434 }
435
436 fmt.Fprintln(g.out, " out.RawByte('}')")
437 fmt.Fprintln(g.out, "}")
438
439 return nil
440 }
441
442 func (g *Generator) genStructMarshaler(t reflect.Type) error {
443 switch t.Kind() {
444 case reflect.Slice, reflect.Array, reflect.Map, reflect.Struct:
445 default:
446 return fmt.Errorf("cannot generate encoder/decoder for %v, not a struct/slice/array/map type", t)
447 }
448
449 fname := g.getEncoderName(t)
450 typ := g.getType(t)
451
452 if !g.noStdMarshalers {
453 fmt.Fprintln(g.out, "// MarshalJSON supports json.Marshaler interface")
454 fmt.Fprintln(g.out, "func (v "+typ+") MarshalJSON() ([]byte, error) {")
455 fmt.Fprintln(g.out, " w := jwriter.Writer{}")
456 fmt.Fprintln(g.out, " "+fname+"(&w, v)")
457 fmt.Fprintln(g.out, " return w.Buffer.BuildBytes(), w.Error")
458 fmt.Fprintln(g.out, "}")
459 }
460
461 fmt.Fprintln(g.out, "// MarshalEasyJSON supports easyjson.Marshaler interface")
462 fmt.Fprintln(g.out, "func (v "+typ+") MarshalEasyJSON(w *jwriter.Writer) {")
463 fmt.Fprintln(g.out, " "+fname+"(w, v)")
464 fmt.Fprintln(g.out, "}")
465
466 return nil
467 }
468
View as plain text