mirror of
https://github.com/netbirdio/easyjson.git
synced 2026-05-22 18:44:42 -07:00
Add support for array types
Arrays are useful to decode into to keep the allocations down and thus the gc pressure low. The code allows the json to contain truncated arrays without raising an error, same as standard encoding/json. However excess elements in the json is an error.
This commit is contained in:
+41
-7
@@ -123,6 +123,40 @@ func (g *Generator) genTypeDecoderNoCheck(t reflect.Type, out string, tags field
|
||||
fmt.Fprintln(g.out, ws+"}")
|
||||
}
|
||||
|
||||
case reflect.Array:
|
||||
tmpVar := g.uniqueVarName()
|
||||
iterVar := g.uniqueVarName()
|
||||
elem := t.Elem()
|
||||
|
||||
if elem.Kind() == reflect.Uint8 {
|
||||
fmt.Fprintln(g.out, ws+"if in.IsNull() {")
|
||||
fmt.Fprintln(g.out, ws+" in.Skip()")
|
||||
fmt.Fprintln(g.out, ws+"} else {")
|
||||
fmt.Fprintln(g.out, ws+" copy("+out+"[:], in.Bytes())")
|
||||
fmt.Fprintln(g.out, ws+"}")
|
||||
|
||||
} else {
|
||||
|
||||
length := t.Len()
|
||||
|
||||
fmt.Fprintln(g.out, ws+"if in.IsNull() {")
|
||||
fmt.Fprintln(g.out, ws+" in.Skip()")
|
||||
fmt.Fprintln(g.out, ws+"} else {")
|
||||
fmt.Fprintln(g.out, ws+" in.Delim('[')")
|
||||
fmt.Fprintln(g.out, ws+" "+iterVar+" := 0")
|
||||
fmt.Fprintln(g.out, ws+" for !in.IsDelim(']') && "+iterVar+" < "+fmt.Sprint(length)+" {")
|
||||
fmt.Fprintln(g.out, ws+" var "+tmpVar+" "+g.getType(elem))
|
||||
|
||||
g.genTypeDecoder(elem, tmpVar, tags, indent+2)
|
||||
|
||||
fmt.Fprintln(g.out, ws+" "+out+"["+iterVar+"] = "+tmpVar)
|
||||
fmt.Fprintln(g.out, ws+" "+iterVar+"++")
|
||||
fmt.Fprintln(g.out, ws+" in.WantComma()")
|
||||
fmt.Fprintln(g.out, ws+" }")
|
||||
fmt.Fprintln(g.out, ws+" in.Delim(']')")
|
||||
fmt.Fprintln(g.out, ws+"}")
|
||||
}
|
||||
|
||||
case reflect.Struct:
|
||||
dec := g.getDecoderName(t)
|
||||
g.addType(t)
|
||||
@@ -287,16 +321,16 @@ func getStructFields(t reflect.Type) ([]reflect.StructField, error) {
|
||||
|
||||
func (g *Generator) genDecoder(t reflect.Type) error {
|
||||
switch t.Kind() {
|
||||
case reflect.Slice:
|
||||
return g.genSliceDecoder(t)
|
||||
case reflect.Slice, reflect.Array:
|
||||
return g.genSliceArrayDecoder(t)
|
||||
default:
|
||||
return g.genStructDecoder(t)
|
||||
}
|
||||
}
|
||||
|
||||
func (g *Generator) genSliceDecoder(t reflect.Type) error {
|
||||
if t.Kind() != reflect.Slice {
|
||||
return fmt.Errorf("cannot generate encoder/decoder for %v, not a slice type", t)
|
||||
func (g *Generator) genSliceArrayDecoder(t reflect.Type) error {
|
||||
if t.Kind() != reflect.Slice && t.Kind() != reflect.Array {
|
||||
return fmt.Errorf("cannot generate encoder/decoder for %v, not a slice or array type", t)
|
||||
}
|
||||
|
||||
fname := g.getDecoderName(t)
|
||||
@@ -378,8 +412,8 @@ func (g *Generator) genStructDecoder(t reflect.Type) error {
|
||||
}
|
||||
|
||||
func (g *Generator) genStructUnmarshaller(t reflect.Type) error {
|
||||
if t.Kind() != reflect.Struct && t.Kind() != reflect.Slice {
|
||||
return fmt.Errorf("cannot generate encoder/decoder for %v, not a struct/slice type", t)
|
||||
if t.Kind() != reflect.Struct && t.Kind() != reflect.Slice && t.Kind() != reflect.Array {
|
||||
return fmt.Errorf("cannot generate encoder/decoder for %v, not a struct/slice/array type", t)
|
||||
}
|
||||
|
||||
fname := g.getDecoderName(t)
|
||||
|
||||
+28
-8
@@ -137,6 +137,26 @@ func (g *Generator) genTypeEncoderNoCheck(t reflect.Type, in string, tags fieldT
|
||||
fmt.Fprintln(g.out, ws+"}")
|
||||
}
|
||||
|
||||
case reflect.Array:
|
||||
elem := t.Elem()
|
||||
iVar := g.uniqueVarName()
|
||||
vVar := g.uniqueVarName()
|
||||
|
||||
if t.Elem().Kind() == reflect.Uint8 {
|
||||
fmt.Fprintln(g.out, ws+"out.Base64Bytes("+in+"[:])")
|
||||
} else {
|
||||
fmt.Fprintln(g.out, ws+"out.RawByte('[')")
|
||||
fmt.Fprintln(g.out, ws+"for "+iVar+", "+vVar+" := range "+in+" {")
|
||||
fmt.Fprintln(g.out, ws+" if "+iVar+" > 0 {")
|
||||
fmt.Fprintln(g.out, ws+" out.RawByte(',')")
|
||||
fmt.Fprintln(g.out, ws+" }")
|
||||
|
||||
g.genTypeEncoder(elem, vVar, tags, indent+1)
|
||||
|
||||
fmt.Fprintln(g.out, ws+"}")
|
||||
fmt.Fprintln(g.out, ws+"out.RawByte(']')")
|
||||
}
|
||||
|
||||
case reflect.Struct:
|
||||
enc := g.getEncoderName(t)
|
||||
g.addType(t)
|
||||
@@ -195,7 +215,7 @@ func (g *Generator) notEmptyCheck(t reflect.Type, v string) string {
|
||||
}
|
||||
|
||||
switch t.Kind() {
|
||||
case reflect.Slice, reflect.Map:
|
||||
case reflect.Slice, reflect.Map: // note: Array types don't have a useful empty value
|
||||
return "len(" + v + ") != 0"
|
||||
case reflect.Interface, reflect.Ptr:
|
||||
return v + " != nil"
|
||||
@@ -242,16 +262,16 @@ func (g *Generator) genStructFieldEncoder(t reflect.Type, f reflect.StructField)
|
||||
|
||||
func (g *Generator) genEncoder(t reflect.Type) error {
|
||||
switch t.Kind() {
|
||||
case reflect.Slice:
|
||||
return g.genSliceEncoder(t)
|
||||
case reflect.Slice, reflect.Array:
|
||||
return g.genSliceArrayEncoder(t)
|
||||
default:
|
||||
return g.genStructEncoder(t)
|
||||
}
|
||||
}
|
||||
|
||||
func (g *Generator) genSliceEncoder(t reflect.Type) error {
|
||||
if t.Kind() != reflect.Slice {
|
||||
return fmt.Errorf("cannot generate encoder/decoder for %v, not a slice type", t)
|
||||
func (g *Generator) genSliceArrayEncoder(t reflect.Type) error {
|
||||
if t.Kind() != reflect.Slice && t.Kind() != reflect.Array {
|
||||
return fmt.Errorf("cannot generate encoder/decoder for %v, not a slice or array type", t)
|
||||
}
|
||||
|
||||
fname := g.getEncoderName(t)
|
||||
@@ -296,8 +316,8 @@ func (g *Generator) genStructEncoder(t reflect.Type) error {
|
||||
}
|
||||
|
||||
func (g *Generator) genStructMarshaller(t reflect.Type) error {
|
||||
if t.Kind() != reflect.Struct && t.Kind() != reflect.Slice {
|
||||
return fmt.Errorf("cannot generate encoder/decoder for %v, not a struct/slice type", t)
|
||||
if t.Kind() != reflect.Struct && t.Kind() != reflect.Slice && t.Kind() != reflect.Array {
|
||||
return fmt.Errorf("cannot generate encoder/decoder for %v, not a struct/slice/array type", t)
|
||||
}
|
||||
|
||||
fname := g.getEncoderName(t)
|
||||
|
||||
@@ -8,6 +8,7 @@ import (
|
||||
"path"
|
||||
"reflect"
|
||||
"sort"
|
||||
"strconv"
|
||||
"strings"
|
||||
"unicode"
|
||||
)
|
||||
@@ -233,6 +234,8 @@ func (g *Generator) getType(t reflect.Type) string {
|
||||
return "*" + g.getType(t.Elem())
|
||||
case reflect.Slice:
|
||||
return "[]" + g.getType(t.Elem())
|
||||
case reflect.Array:
|
||||
return "[" + strconv.Itoa(t.Len()) + "]" + g.getType(t.Elem())
|
||||
case reflect.Map:
|
||||
return "map[" + g.getType(t.Key()) + "]" + g.getType(t.Elem())
|
||||
}
|
||||
|
||||
@@ -31,6 +31,7 @@ var testCases = []struct {
|
||||
{&unexportedStructValue, unexportedStructString},
|
||||
{&excludedFieldValue, excludedFieldString},
|
||||
{&sliceValue, sliceString},
|
||||
{&arrayValue, arrayString},
|
||||
{&mapsValue, mapsString},
|
||||
{&deepNestValue, deepNestString},
|
||||
{&IntsValue, IntsString},
|
||||
|
||||
@@ -445,6 +445,27 @@ var sliceString = `{` +
|
||||
`"NilIntSlice":null` +
|
||||
`}`
|
||||
|
||||
type Arrays struct {
|
||||
ByteArray [3]byte
|
||||
EmptyByteArray [0]byte
|
||||
IntArray [5]int
|
||||
EmptyIntArray [0]int
|
||||
}
|
||||
|
||||
var arrayValue = Arrays{
|
||||
ByteArray: [3]byte{'a', 'b', 'c'},
|
||||
EmptyByteArray: [0]byte{},
|
||||
IntArray: [5]int{1, 2, 3, 4, 5},
|
||||
EmptyIntArray: [0]int{},
|
||||
}
|
||||
|
||||
var arrayString = `{` +
|
||||
`"ByteArray":"YWJj",` +
|
||||
`"EmptyByteArray":"",` +
|
||||
`"IntArray":[1,2,3,4,5],` +
|
||||
`"EmptyIntArray":[]` +
|
||||
`}`
|
||||
|
||||
type Str string
|
||||
|
||||
type Maps struct {
|
||||
|
||||
Reference in New Issue
Block a user