...

Source file src/github.com/mailru/easyjson/gen/encoder.go

Documentation: github.com/mailru/easyjson/gen

     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  // fieldTags contains parsed version of json struct field tags.
    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  // parseFieldTags parses the json field tag into a structure.
    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  // genTypeEncoder generates code that encodes in of type t into the writer, but uses marshaler interface if implemented by t.
    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  // returns true if the type t implements one of the custom marshaler interfaces
   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  // genTypeEncoderNoCheck generates code that encodes in of type t into the writer.
   128  func (g *Generator) genTypeEncoderNoCheck(t reflect.Type, in string, tags fieldTags, indent int, assumeNonEmpty bool) error {
   129  	ws := strings.Repeat("  ", indent)
   130  
   131  	// Check whether type is primitive, needs to be done after interface check.
   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  		} // else assume the caller knows what they are doing and that the custom marshaler performs the translation from the key type to a string or integer
   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  		// NOTE: extra check for TextMarshaler. It overrides default methods.
   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  		// note: Array types don't have a useful empty value
   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  		// can be any in runtime, so toggleFirstCondition stay as is
   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