Support json:"string" field tag.

This commit is contained in:
Victor Starodub
2016-04-18 15:40:08 +03:00
parent 5a0d3f3b2a
commit af01f9e8dc
5 changed files with 278 additions and 29 deletions
+24 -6
View File
@@ -34,7 +34,21 @@ var primitiveDecoders = map[reflect.Kind]string{
reflect.Float64: "in.Float64()",
}
func (g *Generator) genTypeDecoder(t reflect.Type, out string, indent int) error {
var primitiveStringDecoders = map[reflect.Kind]string{
reflect.Int: "in.IntStr()",
reflect.Int8: "in.Int8Str()",
reflect.Int16: "in.Int16Str()",
reflect.Int32: "in.Int32Str()",
reflect.Int64: "in.Int64Str()",
reflect.Uint: "in.UintStr()",
reflect.Uint8: "in.Uint8Str()",
reflect.Uint16: "in.Uint16Str()",
reflect.Uint32: "in.Uint32Str()",
reflect.Uint64: "in.Uint64Str()",
}
// genTypeDecoder generates decoding code for the type t.
func (g *Generator) genTypeDecoder(t reflect.Type, out string, tags fieldTags, indent int) error {
ws := strings.Repeat(" ", indent)
unmarshalerIface := reflect.TypeOf((*easyjson.Unmarshaler)(nil)).Elem()
@@ -52,7 +66,10 @@ func (g *Generator) genTypeDecoder(t reflect.Type, out string, indent int) error
}
// Check whether type is primitive, needs to be done after interface check.
if dec := primitiveDecoders[t.Kind()]; dec != "" {
if dec := primitiveStringDecoders[t.Kind()]; dec != "" && tags.asString {
fmt.Fprintln(g.out, ws+out+" = "+g.getType(t)+"("+dec+")")
return nil
} else if dec := primitiveDecoders[t.Kind()]; dec != "" {
fmt.Fprintln(g.out, ws+out+" = "+g.getType(t)+"("+dec+")")
return nil
}
@@ -76,7 +93,7 @@ func (g *Generator) genTypeDecoder(t reflect.Type, out string, indent int) error
fmt.Fprintln(g.out, ws+"for !in.IsDelim(']') {")
fmt.Fprintln(g.out, ws+" var "+tmpVar+" "+g.getType(elem))
g.genTypeDecoder(elem, tmpVar, indent+1)
g.genTypeDecoder(elem, tmpVar, tags, indent+1)
fmt.Fprintln(g.out, ws+" "+out+" = append("+out+", "+tmpVar+")")
fmt.Fprintln(g.out, ws+" in.WantComma()")
@@ -96,7 +113,7 @@ func (g *Generator) genTypeDecoder(t reflect.Type, out string, indent int) error
fmt.Fprintln(g.out, ws+"} else {")
fmt.Fprintln(g.out, ws+" "+out+" = new("+g.getType(t.Elem())+")")
g.genTypeDecoder(t.Elem(), "*"+out, indent+1)
g.genTypeDecoder(t.Elem(), "*"+out, tags, indent+1)
fmt.Fprintln(g.out, ws+"}")
@@ -123,7 +140,7 @@ func (g *Generator) genTypeDecoder(t reflect.Type, out string, indent int) error
fmt.Fprintln(g.out, ws+" in.WantColon()")
fmt.Fprintln(g.out, ws+" var "+tmpVar+" "+g.getType(elem))
g.genTypeDecoder(elem, tmpVar, indent+2)
g.genTypeDecoder(elem, tmpVar, tags, indent+2)
fmt.Fprintln(g.out, ws+" ("+out+")[key] = "+tmpVar)
fmt.Fprintln(g.out, ws+" in.WantComma()")
@@ -146,9 +163,10 @@ func (g *Generator) genTypeDecoder(t reflect.Type, out string, indent int) error
func (g *Generator) genStructFieldDecoder(t reflect.Type, f reflect.StructField) error {
jsonName := g.namer.GetJSONFieldName(t, f)
tags := parseFieldTags(f)
fmt.Fprintf(g.out, " case %q:\n", jsonName)
return g.genTypeDecoder(f.Type, "out."+f.Name, 3)
return g.genTypeDecoder(f.Type, "out."+f.Name, tags, 3)
}
func mergeStructFields(fields1, fields2 []reflect.StructField) (fields []reflect.StructField) {
+60 -23
View File
@@ -31,7 +31,53 @@ var primitiveEncoders = map[reflect.Kind]string{
reflect.Float64: "out.Float64(float64(%v))",
}
func (g *Generator) genTypeEncoder(t reflect.Type, in string, indent int) error {
var primitiveStringEncoders = map[reflect.Kind]string{
reflect.Int: "out.IntStr(int(%v))",
reflect.Int8: "out.Int8Str(int8(%v))",
reflect.Int16: "out.Int16Str(int16(%v))",
reflect.Int32: "out.Int32Str(int32(%v))",
reflect.Int64: "out.Int64Str(int64(%v))",
reflect.Uint: "out.UintStr(uint(%v))",
reflect.Uint8: "out.Uint8Str(uint8(%v))",
reflect.Uint16: "out.Uint16Str(uint16(%v))",
reflect.Uint32: "out.Uint32Str(uint32(%v))",
reflect.Uint64: "out.Uint64Str(uint64(%v))",
}
// fieldTags contains parsed version of json struct field tags.
type fieldTags struct {
name string
omit bool
omitEmpty bool
noOmitEmpty bool
asString bool
}
// parseFieldTags parses the json field tag into a structure.
func parseFieldTags(f reflect.StructField) fieldTags {
var ret fieldTags
for i, s := range strings.Split(f.Tag.Get("json"), ",") {
switch {
case i == 0 && s == "-":
ret.omit = true
case i == 0:
ret.name = s
case s == "omitempty":
ret.omitEmpty = true
case s == "!omitempty":
ret.noOmitEmpty = true
case s == "string":
ret.asString = true
}
}
return ret
}
// genTypeEncoder generates code that encodes in of type t into the writer.
func (g *Generator) genTypeEncoder(t reflect.Type, in string, tags fieldTags, indent int) error {
ws := strings.Repeat(" ", indent)
marshalerIface := reflect.TypeOf((*easyjson.Marshaler)(nil)).Elem()
@@ -47,7 +93,10 @@ func (g *Generator) genTypeEncoder(t reflect.Type, in string, indent int) error
}
// Check whether type is primitive, needs to be done after interface check.
if enc := primitiveEncoders[t.Kind()]; enc != "" {
if enc := primitiveStringEncoders[t.Kind()]; enc != "" && tags.asString {
fmt.Fprintf(g.out, ws+enc+"\n", in)
return nil
} else if enc := primitiveEncoders[t.Kind()]; enc != "" {
fmt.Fprintf(g.out, ws+enc+"\n", in)
return nil
}
@@ -64,7 +113,7 @@ func (g *Generator) genTypeEncoder(t reflect.Type, in string, indent int) error
fmt.Fprintln(g.out, ws+" out.RawByte(',')")
fmt.Fprintln(g.out, ws+" }")
g.genTypeEncoder(elem, vVar, indent+1)
g.genTypeEncoder(elem, vVar, tags, indent+1)
fmt.Fprintln(g.out, ws+"}")
fmt.Fprintln(g.out, ws+"out.RawByte(']')")
@@ -80,7 +129,7 @@ func (g *Generator) genTypeEncoder(t reflect.Type, in string, indent int) error
fmt.Fprintln(g.out, ws+` out.RawString("null")`)
fmt.Fprintln(g.out, ws+"} else {")
g.genTypeEncoder(t.Elem(), "*"+in, indent+1)
g.genTypeEncoder(t.Elem(), "*"+in, tags, indent+1)
fmt.Fprintln(g.out, ws+"}")
@@ -102,7 +151,7 @@ func (g *Generator) genTypeEncoder(t reflect.Type, in string, indent int) error
fmt.Fprintln(g.out, ws+" out.String(string("+tmpVar+"_name))")
fmt.Fprintln(g.out, ws+" out.RawByte(':')")
g.genTypeEncoder(t.Elem(), tmpVar+"_value", indent+2)
g.genTypeEncoder(t.Elem(), tmpVar+"_value", tags, indent+2)
fmt.Fprintln(g.out, ws+" }")
fmt.Fprintln(g.out, ws+" out.RawByte('}')")
@@ -148,28 +197,16 @@ func (g *Generator) notEmptyCheck(t reflect.Type, v string) string {
func (g *Generator) genStructFieldEncoder(t reflect.Type, f reflect.StructField) error {
jsonName := g.namer.GetJSONFieldName(t, f)
omitEmpty := g.omitEmpty
tags := parseFieldTags(f)
for i, s := range strings.Split(f.Tag.Get("json"), ",") {
if i == 0 {
if s == "-" {
return nil
}
continue
}
if s == "omitempty" {
omitEmpty = true
} else if s == "!omitempty" {
omitEmpty = false
}
if tags.omit {
return nil
}
if !omitEmpty {
if !tags.omitEmpty && !g.omitEmpty || tags.noOmitEmpty {
fmt.Fprintln(g.out, " if !first { out.RawByte(',') }")
fmt.Fprintln(g.out, " first = false")
fmt.Fprintf(g.out, " out.RawString(%q)\n", strconv.Quote(jsonName)+":")
return g.genTypeEncoder(f.Type, "in."+f.Name, 1)
return g.genTypeEncoder(f.Type, "in."+f.Name, tags, 1)
}
fmt.Fprintln(g.out, " if", g.notEmptyCheck(f.Type, "in."+f.Name), "{")
@@ -177,7 +214,7 @@ func (g *Generator) genStructFieldEncoder(t reflect.Type, f reflect.StructField)
fmt.Fprintln(g.out, " first = false")
fmt.Fprintf(g.out, " out.RawString(%q)\n", strconv.Quote(jsonName)+":")
if err := g.genTypeEncoder(f.Type, "in."+f.Name, 2); err != nil {
if err := g.genTypeEncoder(f.Type, "in."+f.Name, tags, 2); err != nil {
return err
}
fmt.Fprintln(g.out, " }")
+88
View File
@@ -663,6 +663,94 @@ func (r *Lexer) Int() int {
return int(r.Int64())
}
func (r *Lexer) Uint8Str() uint8 {
s := r.UnsafeString()
if !r.Ok() {
return 0
}
var n uint64
n, r.err = strconv.ParseUint(s, 10, 8)
return uint8(n)
}
func (r *Lexer) Uint16Str() uint16 {
s := r.UnsafeString()
if !r.Ok() {
return 0
}
var n uint64
n, r.err = strconv.ParseUint(s, 10, 16)
return uint16(n)
}
func (r *Lexer) Uint32Str() uint32 {
s := r.UnsafeString()
if !r.Ok() {
return 0
}
var n uint64
n, r.err = strconv.ParseUint(s, 10, 32)
return uint32(n)
}
func (r *Lexer) Uint64Str() uint64 {
s := r.UnsafeString()
if !r.Ok() {
return 0
}
var n uint64
n, r.err = strconv.ParseUint(s, 10, 64)
return n
}
func (r *Lexer) UintStr() uint {
return uint(r.Uint64Str())
}
func (r *Lexer) Int8Str() int8 {
s := r.UnsafeString()
if !r.Ok() {
return 0
}
var n int64
n, r.err = strconv.ParseInt(s, 10, 8)
return int8(n)
}
func (r *Lexer) Int16Str() int16 {
s := r.UnsafeString()
if !r.Ok() {
return 0
}
var n int64
n, r.err = strconv.ParseInt(s, 10, 16)
return int16(n)
}
func (r *Lexer) Int32Str() int32 {
s := r.UnsafeString()
if !r.Ok() {
return 0
}
var n int64
n, r.err = strconv.ParseInt(s, 10, 32)
return int32(n)
}
func (r *Lexer) Int64Str() int64 {
s := r.UnsafeString()
if !r.Ok() {
return 0
}
var n int64
n, r.err = strconv.ParseInt(s, 10, 64)
return n
}
func (r *Lexer) IntStr() int {
return int(r.Int64Str())
}
func (r *Lexer) Float32() float32 {
s := r.number()
if !r.Ok() {
+70
View File
@@ -108,6 +108,76 @@ func (w *Writer) Int64(n int64) {
w.Buffer.Buf = strconv.AppendInt(w.Buffer.Buf, n, 10)
}
func (w *Writer) Uint8Str(n uint8) {
w.Buffer.EnsureSpace(3)
w.Buffer.Buf = append(w.Buffer.Buf, '"')
w.Buffer.Buf = strconv.AppendUint(w.Buffer.Buf, uint64(n), 10)
w.Buffer.Buf = append(w.Buffer.Buf, '"')
}
func (w *Writer) Uint16Str(n uint16) {
w.Buffer.EnsureSpace(5)
w.Buffer.Buf = append(w.Buffer.Buf, '"')
w.Buffer.Buf = strconv.AppendUint(w.Buffer.Buf, uint64(n), 10)
w.Buffer.Buf = append(w.Buffer.Buf, '"')
}
func (w *Writer) Uint32Str(n uint32) {
w.Buffer.EnsureSpace(10)
w.Buffer.Buf = append(w.Buffer.Buf, '"')
w.Buffer.Buf = strconv.AppendUint(w.Buffer.Buf, uint64(n), 10)
w.Buffer.Buf = append(w.Buffer.Buf, '"')
}
func (w *Writer) UintStr(n uint) {
w.Buffer.EnsureSpace(20)
w.Buffer.Buf = append(w.Buffer.Buf, '"')
w.Buffer.Buf = strconv.AppendUint(w.Buffer.Buf, uint64(n), 10)
w.Buffer.Buf = append(w.Buffer.Buf, '"')
}
func (w *Writer) Uint64Str(n uint64) {
w.Buffer.EnsureSpace(20)
w.Buffer.Buf = append(w.Buffer.Buf, '"')
w.Buffer.Buf = strconv.AppendUint(w.Buffer.Buf, n, 10)
w.Buffer.Buf = append(w.Buffer.Buf, '"')
}
func (w *Writer) Int8Str(n int8) {
w.Buffer.EnsureSpace(4)
w.Buffer.Buf = append(w.Buffer.Buf, '"')
w.Buffer.Buf = strconv.AppendInt(w.Buffer.Buf, int64(n), 10)
w.Buffer.Buf = append(w.Buffer.Buf, '"')
}
func (w *Writer) Int16Str(n int16) {
w.Buffer.EnsureSpace(6)
w.Buffer.Buf = append(w.Buffer.Buf, '"')
w.Buffer.Buf = strconv.AppendInt(w.Buffer.Buf, int64(n), 10)
w.Buffer.Buf = append(w.Buffer.Buf, '"')
}
func (w *Writer) Int32Str(n int32) {
w.Buffer.EnsureSpace(11)
w.Buffer.Buf = append(w.Buffer.Buf, '"')
w.Buffer.Buf = strconv.AppendInt(w.Buffer.Buf, int64(n), 10)
w.Buffer.Buf = append(w.Buffer.Buf, '"')
}
func (w *Writer) IntStr(n int) {
w.Buffer.EnsureSpace(21)
w.Buffer.Buf = append(w.Buffer.Buf, '"')
w.Buffer.Buf = strconv.AppendInt(w.Buffer.Buf, int64(n), 10)
w.Buffer.Buf = append(w.Buffer.Buf, '"')
}
func (w *Writer) Int64Str(n int64) {
w.Buffer.EnsureSpace(21)
w.Buffer.Buf = append(w.Buffer.Buf, '"')
w.Buffer.Buf = strconv.AppendInt(w.Buffer.Buf, n, 10)
w.Buffer.Buf = append(w.Buffer.Buf, '"')
}
func (w *Writer) Float32(n float32) {
w.Buffer.EnsureSpace(20)
w.Buffer.Buf = strconv.AppendFloat(w.Buffer.Buf, float64(n), 'g', -1, 32)
+36
View File
@@ -25,6 +25,18 @@ type PrimitiveTypes struct {
Uint32 uint32
Uint64 uint64
IntString int `json:",string"`
Int8String int8 `json:",string"`
Int16String int16 `json:",string"`
Int32String int32 `json:",string"`
Int64String int64 `json:",string"`
UintString uint `json:",string"`
Uint8String uint8 `json:",string"`
Uint16String uint16 `json:",string"`
Uint32String uint32 `json:",string"`
Uint64String uint64 `json:",string"`
Float32 float32
Float64 float64
@@ -49,6 +61,18 @@ var primitiveTypesValue = PrimitiveTypes{
Uint32: math.MaxUint32,
Uint64: math.MaxUint64,
IntString: math.MinInt32,
Int8String: math.MinInt8,
Int16String: math.MinInt16,
Int32String: math.MinInt32,
Int64String: math.MinInt64,
UintString: math.MaxUint32,
Uint8String: math.MaxUint8,
Uint16String: math.MaxUint16,
Uint32String: math.MaxUint32,
Uint64String: math.MaxUint64,
Float32: 1.5,
Float64: math.MaxFloat64,
@@ -70,6 +94,18 @@ var primitiveTypesString = "{" +
`"Uint32":` + fmt.Sprint(math.MaxUint32) + `,` +
`"Uint64":` + fmt.Sprint(uint64(math.MaxUint64)) + `,` +
`"IntString":"` + fmt.Sprint(math.MinInt32) + `",` +
`"Int8String":"` + fmt.Sprint(math.MinInt8) + `",` +
`"Int16String":"` + fmt.Sprint(math.MinInt16) + `",` +
`"Int32String":"` + fmt.Sprint(math.MinInt32) + `",` +
`"Int64String":"` + fmt.Sprint(int64(math.MinInt64)) + `",` +
`"UintString":"` + fmt.Sprint(math.MaxUint32) + `",` +
`"Uint8String":"` + fmt.Sprint(math.MaxUint8) + `",` +
`"Uint16String":"` + fmt.Sprint(math.MaxUint16) + `",` +
`"Uint32String":"` + fmt.Sprint(math.MaxUint32) + `",` +
`"Uint64String":"` + fmt.Sprint(uint64(math.MaxUint64)) + `",` +
`"Float32":` + fmt.Sprint(1.5) + `,` +
`"Float64":` + fmt.Sprint(math.MaxFloat64) + `,` +