commit 493ce7aea4e9bd569f393766eb51dd7ab9d9d91b
parent 2dc87fb620b38fc93f7bff16ee47e3ec1f6321c5
Author: francoispqt <francois@parquet.ninja>
Date: Sun, 24 Jun 2018 23:21:59 +0800
add float64 funcs, add omit empty tag handling
Diffstat:
26 files changed, 886 insertions(+), 200 deletions(-)
diff --git a/decode.go b/decode.go
@@ -294,7 +294,13 @@ func (dec *Decoder) AddUint64(v *uint64) error {
// AddFloat decodes the next key to a *float64.
// If next key value overflows float64, an InvalidUnmarshalError error will be returned.
func (dec *Decoder) AddFloat(v *float64) error {
- return dec.Float(v)
+ return dec.Float64(v)
+}
+
+// AddFloat64 decodes the next key to a *float64.
+// If next key value overflows float64, an InvalidUnmarshalError error will be returned.
+func (dec *Decoder) AddFloat64(v *float64) error {
+ return dec.Float64(v)
}
// AddFloat32 decodes the next key to a *float64.
@@ -428,6 +434,12 @@ func (dec *Decoder) Uint64(v *uint64) error {
// Float decodes the next key to a *float64.
// If next key value overflows float64, an InvalidUnmarshalError error will be returned.
func (dec *Decoder) Float(v *float64) error {
+ return dec.Float64(v)
+}
+
+// Float64 decodes the next key to a *float64.
+// If next key value overflows float64, an InvalidUnmarshalError error will be returned.
+func (dec *Decoder) Float64(v *float64) error {
err := dec.decodeFloat64(v)
if err != nil {
return err
diff --git a/decode_array.go b/decode_array.go
@@ -106,3 +106,23 @@ func (dec *Decoder) skipArray() (int, error) {
}
return 0, dec.raiseInvalidJSONErr(dec.cursor)
}
+
+// DecodeArrayFunc is a custom func type implementing UnarshaleArray.
+// Use it to cast a func(*Decoder) to Unmarshal an object.
+//
+// str := ""
+// dec := gojay.NewDecoder(io.Reader)
+// dec.DecodeArray(gojay.DecodeArrayFunc(func(dec *gojay.Decoder, k string) error {
+// return dec.AddString(&str)
+// }))
+type DecodeArrayFunc func(*Decoder) error
+
+// UnmarshalJSONArray implements UnarshalerArray.
+func (f DecodeArrayFunc) UnmarshalJSONArray(dec *Decoder) error {
+ return f(dec)
+}
+
+// IsNil implements UnarshalerArray.
+func (f DecodeArrayFunc) IsNil() bool {
+ return f == nil
+}
diff --git a/decode_array_test.go b/decode_array_test.go
@@ -566,3 +566,8 @@ func TestDecodeArrayNullError(t *testing.T) {
assert.NotNil(t, err, "err should not be nil")
assert.IsType(t, InvalidJSONError(""), err, "err should be of type InvalidJSONError")
}
+
+func TestDecoderArrayFunc(t *testing.T) {
+ var f DecodeArrayFunc
+ assert.True(t, f.IsNil())
+}
diff --git a/decode_number_float_test.go b/decode_number_float_test.go
@@ -620,3 +620,58 @@ func TestDecoderFloat32(t *testing.T) {
assert.IsType(t, InvalidJSONError(""), err, "err should be of type InvalidJSONError")
})
}
+
+func TestDecoderFloat64Field(t *testing.T) {
+ var testCasesBasic = []struct {
+ name string
+ json string
+ value float64
+ }{
+ {
+ name: "basic",
+ json: "[1]",
+ value: float64(1),
+ },
+ {
+ name: "big",
+ json: "[0]",
+ value: float64(0),
+ },
+ }
+ for _, testCase := range testCasesBasic {
+ t.Run(testCase.name, func(t *testing.T) {
+ var dec = NewDecoder(strings.NewReader(testCase.json))
+ var v float64
+ dec.DecodeArray(DecodeArrayFunc(func(dec *Decoder) error {
+ return dec.AddFloat64(&v)
+ }))
+ assert.Equal(t, testCase.value, v)
+ })
+ }
+ var testCasesBasicAlt = []struct {
+ name string
+ json string
+ value float64
+ }{
+ {
+ name: "basic",
+ json: "[1]",
+ value: float64(1),
+ },
+ {
+ name: "big",
+ json: "[0]",
+ value: float64(0),
+ },
+ }
+ for _, testCase := range testCasesBasicAlt {
+ t.Run(testCase.name, func(t *testing.T) {
+ var dec = NewDecoder(strings.NewReader(testCase.json))
+ var v float64
+ dec.DecodeArray(DecodeArrayFunc(func(dec *Decoder) error {
+ return dec.Float(&v)
+ }))
+ assert.Equal(t, testCase.value, v)
+ })
+ }
+}
diff --git a/encode_number_float.go b/encode_number_float.go
@@ -41,17 +41,61 @@ func (enc *Encoder) encodeFloat32(n float32) ([]byte, error) {
// AddFloat adds a float64 to be encoded, must be used inside a slice or array encoding (does not encode a key)
func (enc *Encoder) AddFloat(v float64) {
- enc.Float(v)
+ enc.Float64(v)
}
// AddFloatOmitEmpty adds a float64 to be encoded and skips it if its value is 0,
// must be used inside a slice or array encoding (does not encode a key).
func (enc *Encoder) AddFloatOmitEmpty(v float64) {
- enc.FloatOmitEmpty(v)
+ enc.Float64OmitEmpty(v)
}
// Float adds a float64 to be encoded, must be used inside a slice or array encoding (does not encode a key)
func (enc *Encoder) Float(v float64) {
+ enc.Float64(v)
+}
+
+// FloatOmitEmpty adds a float64 to be encoded and skips it if its value is 0,
+// must be used inside a slice or array encoding (does not encode a key).
+func (enc *Encoder) FloatOmitEmpty(v float64) {
+ enc.Float64OmitEmpty(v)
+}
+
+// AddFloatKey adds a float64 to be encoded, must be used inside an object as it will encode a key
+func (enc *Encoder) AddFloatKey(key string, v float64) {
+ enc.Float64Key(key, v)
+}
+
+// AddFloatKeyOmitEmpty adds a float64 to be encoded and skips it if its value is 0.
+// Must be used inside an object as it will encode a key
+func (enc *Encoder) AddFloatKeyOmitEmpty(key string, v float64) {
+ enc.Float64KeyOmitEmpty(key, v)
+}
+
+// FloatKey adds a float64 to be encoded, must be used inside an object as it will encode a key
+func (enc *Encoder) FloatKey(key string, v float64) {
+ enc.Float64Key(key, v)
+}
+
+// FloatKeyOmitEmpty adds a float64 to be encoded and skips it if its value is 0.
+// Must be used inside an object as it will encode a key
+func (enc *Encoder) FloatKeyOmitEmpty(key string, v float64) {
+ enc.Float64KeyOmitEmpty(key, v)
+}
+
+// AddFloat64 adds a float64 to be encoded, must be used inside a slice or array encoding (does not encode a key)
+func (enc *Encoder) AddFloat64(v float64) {
+ enc.Float(v)
+}
+
+// AddFloat64OmitEmpty adds a float64 to be encoded and skips it if its value is 0,
+// must be used inside a slice or array encoding (does not encode a key).
+func (enc *Encoder) AddFloat64OmitEmpty(v float64) {
+ enc.FloatOmitEmpty(v)
+}
+
+// Float64 adds a float64 to be encoded, must be used inside a slice or array encoding (does not encode a key)
+func (enc *Encoder) Float64(v float64) {
enc.grow(10)
r := enc.getPreviousRune()
if r != '[' {
@@ -60,9 +104,9 @@ func (enc *Encoder) Float(v float64) {
enc.buf = strconv.AppendFloat(enc.buf, v, 'f', -1, 64)
}
-// FloatOmitEmpty adds a float64 to be encoded and skips it if its value is 0,
+// Float64OmitEmpty adds a float64 to be encoded and skips it if its value is 0,
// must be used inside a slice or array encoding (does not encode a key).
-func (enc *Encoder) FloatOmitEmpty(v float64) {
+func (enc *Encoder) Float64OmitEmpty(v float64) {
if v == 0 {
return
}
@@ -74,19 +118,19 @@ func (enc *Encoder) FloatOmitEmpty(v float64) {
enc.buf = strconv.AppendFloat(enc.buf, v, 'f', -1, 64)
}
-// AddFloatKey adds a float64 to be encoded, must be used inside an object as it will encode a key
-func (enc *Encoder) AddFloatKey(key string, v float64) {
+// AddFloat64Key adds a float64 to be encoded, must be used inside an object as it will encode a key
+func (enc *Encoder) AddFloat64Key(key string, v float64) {
enc.FloatKey(key, v)
}
-// AddFloatKeyOmitEmpty adds a float64 to be encoded and skips it if its value is 0.
+// AddFloat64KeyOmitEmpty adds a float64 to be encoded and skips it if its value is 0.
// Must be used inside an object as it will encode a key
-func (enc *Encoder) AddFloatKeyOmitEmpty(key string, v float64) {
+func (enc *Encoder) AddFloat64KeyOmitEmpty(key string, v float64) {
enc.FloatKeyOmitEmpty(key, v)
}
-// FloatKey adds a float64 to be encoded, must be used inside an object as it will encode a key
-func (enc *Encoder) FloatKey(key string, value float64) {
+// Float64Key adds a float64 to be encoded, must be used inside an object as it will encode a key
+func (enc *Encoder) Float64Key(key string, value float64) {
r := enc.getPreviousRune()
if r != '{' {
enc.writeByte(',')
@@ -98,9 +142,9 @@ func (enc *Encoder) FloatKey(key string, value float64) {
enc.buf = strconv.AppendFloat(enc.buf, value, 'f', -1, 64)
}
-// FloatKeyOmitEmpty adds a float64 to be encoded and skips it if its value is 0.
+// Float64KeyOmitEmpty adds a float64 to be encoded and skips it if its value is 0.
// Must be used inside an object as it will encode a key
-func (enc *Encoder) FloatKeyOmitEmpty(key string, v float64) {
+func (enc *Encoder) Float64KeyOmitEmpty(key string, v float64) {
if v == 0 {
return
}
diff --git a/encode_number_float_test.go b/encode_number_float_test.go
@@ -0,0 +1,119 @@
+package gojay
+
+import (
+ "strings"
+ "testing"
+
+ "github.com/stretchr/testify/assert"
+)
+
+func TestEncoderFloat64(t *testing.T) {
+ var testCasesBasic = []struct {
+ name string
+ v float64
+ expectedJSON string
+ }{
+ {
+ name: "basic",
+ v: float64(1),
+ expectedJSON: "[1,1]",
+ },
+ {
+ name: "big",
+ v: float64(0),
+ expectedJSON: "[0,0]",
+ },
+ }
+ for _, testCase := range testCasesBasic {
+ t.Run(testCase.name, func(t *testing.T) {
+ var b = &strings.Builder{}
+ var enc = NewEncoder(b)
+ enc.Encode(EncodeArrayFunc(func(enc *Encoder) {
+ enc.Float64(testCase.v)
+ enc.AddFloat64(testCase.v)
+ }))
+ assert.Equal(t, testCase.expectedJSON, b.String())
+ })
+ }
+ var testCasesOmitEmpty = []struct {
+ name string
+ v float64
+ expectedJSON string
+ }{
+ {
+ name: "basic",
+ v: float64(1),
+ expectedJSON: "[1,1]",
+ },
+ {
+ name: "big",
+ v: float64(0),
+ expectedJSON: "[]",
+ },
+ }
+ for _, testCase := range testCasesOmitEmpty {
+ t.Run(testCase.name, func(t *testing.T) {
+ var b = &strings.Builder{}
+ var enc = NewEncoder(b)
+ enc.Encode(EncodeArrayFunc(func(enc *Encoder) {
+ enc.Float64OmitEmpty(testCase.v)
+ enc.AddFloat64OmitEmpty(testCase.v)
+ }))
+ assert.Equal(t, testCase.expectedJSON, b.String())
+ })
+ }
+ var testCasesKeyBasic = []struct {
+ name string
+ v float64
+ expectedJSON string
+ }{
+ {
+ name: "basic",
+ v: float64(1),
+ expectedJSON: `{"foo":1,"bar":1}`,
+ },
+ {
+ name: "big",
+ v: float64(0),
+ expectedJSON: `{"foo":0,"bar":0}`,
+ },
+ }
+ for _, testCase := range testCasesKeyBasic {
+ t.Run(testCase.name, func(t *testing.T) {
+ var b = &strings.Builder{}
+ var enc = NewEncoder(b)
+ enc.Encode(EncodeObjectFunc(func(enc *Encoder) {
+ enc.Float64Key("foo", testCase.v)
+ enc.AddFloat64Key("bar", testCase.v)
+ }))
+ assert.Equal(t, testCase.expectedJSON, b.String())
+ })
+ }
+ var testCasesKeyOmitEmpty = []struct {
+ name string
+ v float64
+ expectedJSON string
+ }{
+ {
+ name: "basic",
+ v: float64(1),
+ expectedJSON: `{"foo":1,"bar":1}`,
+ },
+ {
+ name: "big",
+ v: float64(0),
+ expectedJSON: "{}",
+ },
+ }
+ for _, testCase := range testCasesKeyOmitEmpty {
+ t.Run(testCase.name, func(t *testing.T) {
+ var b = &strings.Builder{}
+ var enc = NewEncoder(b)
+ enc.Encode(EncodeObjectFunc(func(enc *Encoder) {
+ enc.Float64KeyOmitEmpty("foo", testCase.v)
+ enc.AddFloat64KeyOmitEmpty("bar", testCase.v)
+ }))
+ assert.Equal(t, testCase.expectedJSON, b.String())
+ })
+ }
+}
diff --git a/encode_stream.go b/encode_stream.go
@@ -169,12 +169,17 @@ func (s *StreamEncoder) AddInt(value int) {
s.Encoder.writeByte(s.delimiter)
}
-// AddFloat adds a float64 to be encoded.
-func (s *StreamEncoder) AddFloat(value float64) {
+// AddFloat64 adds a float64 to be encoded.
+func (s *StreamEncoder) AddFloat64(value float64) {
s.buf = strconv.AppendFloat(s.buf, value, 'f', -1, 64)
s.Encoder.writeByte(s.delimiter)
}
+// AddFloat adds a float64 to be encoded.
+func (s *StreamEncoder) AddFloat(value float64) {
+ s.AddFloat64(value)
+}
+
// Non exposed
func consume(init *StreamEncoder, s *StreamEncoder, m MarshalerStream) {
diff --git a/gojay/Makefile b/gojay/Makefile
@@ -4,7 +4,7 @@ build:
.PHONY: test
test:
- go test -race .
+ go test -race -v .
.PHONY: cover
cover:
diff --git a/gojay/README.md b/gojay/README.md
@@ -58,4 +58,4 @@ type A struct {
SkipMarshal string `gojay:"skipMarshal,-m"`
Skip string `gojay:"-"`
}
-```
-\ No newline at end of file
+```
diff --git a/gojay/gen.go b/gojay/gen.go
@@ -9,6 +9,7 @@ import (
const gojayAnnotation = "//gojay:json"
const genFileSuffix = "_gojay.go"
+const omitEmptyFuncName = "OmitEmpty"
var pkgTpl *template.Template
var genHeader = []byte("// Code generated by GoJay. DO NOT EDIT.\n\n")
diff --git a/gojay/gen_array_marshal.go b/gojay/gen_array_marshal.go
@@ -2,7 +2,9 @@ package main
import (
"errors"
+ "fmt"
"go/ast"
+ "log"
)
func init() {}
@@ -40,7 +42,7 @@ func (g *Gen) arrGenMarshal(n string, s *ast.ArrayType) error {
return err
}
default:
- return errors.New("Unknown type")
+ return fmt.Errorf("Unknown type %s", n)
}
}
_, err = g.b.Write([]byte("}\n"))
@@ -53,27 +55,31 @@ func (g *Gen) arrGenMarshal(n string, s *ast.ArrayType) error {
func (g *Gen) arrGenMarshalIdent(i *ast.Ident, ptr bool) error {
switch i.String() {
case "string":
- return g.arrMarshalString(ptr)
+ g.arrMarshalString(ptr)
case "bool":
- return g.arrMarshalBool(ptr)
+ g.arrMarshalBool(ptr)
case "int":
- return g.arrMarshalInt("", ptr)
+ g.arrMarshalInt("", ptr)
case "int64":
- return g.arrMarshalInt("64", ptr)
+ g.arrMarshalInt("64", ptr)
case "int32":
- return g.arrMarshalInt("32", ptr)
+ g.arrMarshalInt("32", ptr)
case "int16":
- return g.arrMarshalInt("16", ptr)
+ g.arrMarshalInt("16", ptr)
case "int8":
- return g.arrMarshalInt("8", ptr)
+ g.arrMarshalInt("8", ptr)
case "uint64":
- return g.arrMarshalUint("64", ptr)
+ g.arrMarshalUint("64", ptr)
case "uint32":
- return g.arrMarshalUint("32", ptr)
+ g.arrMarshalUint("32", ptr)
case "uint16":
- return g.arrMarshalUint("16", ptr)
+ g.arrMarshalUint("16", ptr)
case "uint8":
- return g.arrMarshalUint("8", ptr)
+ g.arrMarshalUint("8", ptr)
+ case "float64":
+ g.arrMarshalFloat("64", ptr)
+ case "float32":
+ g.arrMarshalFloat("32", ptr)
default:
// if ident is already in our spec list
if sp, ok := g.genTypes[i.Name]; ok {
@@ -87,66 +93,65 @@ func (g *Gen) arrGenMarshalIdent(i *ast.Ident, ptr bool) error {
return errors.New("could not determine what to do with type " + i.String())
}
}
- return errors.New("Unknown type")
+ return fmt.Errorf("Unknown type %s", i.Name)
}
+ return nil
}
func (g *Gen) arrMarshalNonPrim(sp *ast.TypeSpec, ptr bool) error {
switch sp.Type.(type) {
case *ast.StructType:
- return g.arrMarshalStruct(sp, ptr)
+ g.arrMarshalStruct(sp, ptr)
case *ast.ArrayType:
- return g.arrMarshalArr(sp, ptr)
+ g.arrMarshalArr(sp, ptr)
}
return nil
}
-func (g *Gen) arrMarshalString(ptr bool) error {
+func (g *Gen) arrMarshalString(ptr bool) {
if ptr {
err := arrMarshalTpl["stringPtr"].tpl.Execute(g.b, struct {
Ptr string
}{""})
if err != nil {
- return err
+ log.Fatal(err)
}
} else {
err := arrMarshalTpl["string"].tpl.Execute(g.b, struct {
Ptr string
}{"&"})
if err != nil {
- return err
+ log.Fatal(err)
}
}
- return nil
}
-func (g *Gen) arrMarshalBool(ptr bool) error {
+func (g *Gen) arrMarshalBool(ptr bool) {
if ptr {
err := arrMarshalTpl["bool"].tpl.Execute(g.b, struct {
Ptr string
}{""})
if err != nil {
- return err
+ log.Fatal(err)
}
} else {
err := arrMarshalTpl["bool"].tpl.Execute(g.b, struct {
Ptr string
}{"&"})
if err != nil {
- return err
+ log.Fatal(err)
}
}
- return nil
}
-func (g *Gen) arrMarshalInt(intLen string, ptr bool) error {
+func (g *Gen) arrMarshalInt(intLen string, ptr bool) {
if ptr {
err := arrMarshalTpl["int"].tpl.Execute(g.b, struct {
IntLen string
Ptr string
}{intLen, ""})
if err != nil {
- return err
+ log.Fatal(err)
}
} else {
err := arrMarshalTpl["int"].tpl.Execute(g.b, struct {
@@ -154,20 +159,39 @@ func (g *Gen) arrMarshalInt(intLen string, ptr bool) error {
Ptr string
}{intLen, "&"})
if err != nil {
- return err
+ log.Fatal(err)
+ }
+ }
+}
+
+func (g *Gen) arrMarshalFloat(intLen string, ptr bool) {
+ if ptr {
+ err := arrMarshalTpl["float"].tpl.Execute(g.b, struct {
+ IntLen string
+ Ptr string
+ }{intLen, ""})
+ if err != nil {
+ log.Fatal(err)
+ }
+ } else {
+ err := arrMarshalTpl["float"].tpl.Execute(g.b, struct {
+ IntLen string
+ Ptr string
+ }{intLen, "&"})
+ if err != nil {
+ log.Fatal(err)
}
}
- return nil
}
-func (g *Gen) arrMarshalUint(intLen string, ptr bool) error {
+func (g *Gen) arrMarshalUint(intLen string, ptr bool) {
if ptr {
err := arrMarshalTpl["uint"].tpl.Execute(g.b, struct {
IntLen string
Ptr string
}{intLen, ""})
if err != nil {
- return err
+ log.Fatal(err)
}
} else {
err := arrMarshalTpl["uint"].tpl.Execute(g.b, struct {
@@ -175,46 +199,43 @@ func (g *Gen) arrMarshalUint(intLen string, ptr bool) error {
Ptr string
}{intLen, "&"})
if err != nil {
- return err
+ log.Fatal(err)
}
}
- return nil
}
-func (g *Gen) arrMarshalStruct(st *ast.TypeSpec, ptr bool) error {
+func (g *Gen) arrMarshalStruct(st *ast.TypeSpec, ptr bool) {
if ptr {
err := arrMarshalTpl["structPtr"].tpl.Execute(g.b, struct {
StructName string
}{st.Name.String()})
if err != nil {
- return err
+ log.Fatal(err)
}
} else {
err := arrMarshalTpl["struct"].tpl.Execute(g.b, struct {
StructName string
}{st.Name.String()})
if err != nil {
- return err
+ log.Fatal(err)
}
}
- return nil
}
-func (g *Gen) arrMarshalArr(st *ast.TypeSpec, ptr bool) error {
+func (g *Gen) arrMarshalArr(st *ast.TypeSpec, ptr bool) {
if ptr {
err := arrMarshalTpl["arrPtr"].tpl.Execute(g.b, struct {
StructName string
}{st.Name.String()})
if err != nil {
- return err
+ log.Fatal(err)
}
} else {
err := arrMarshalTpl["arr"].tpl.Execute(g.b, struct {
StructName string
}{st.Name.String()})
if err != nil {
- return err
+ log.Fatal(err)
}
}
- return nil
}
diff --git a/gojay/gen_array_marshal_tpl.go b/gojay/gen_array_marshal_tpl.go
@@ -31,6 +31,11 @@ var arrMarshalTpl = templateList{
"\t\tenc.Uint{{.IntLen}}(s)\n" +
"\t}\n",
},
+ "float": &genTpl{
+ strTpl: "\tfor _, s := range *v {\n" +
+ "\t\tenc.Float{{.IntLen}}(s)\n" +
+ "\t}\n",
+ },
"struct": &genTpl{
strTpl: "\tfor _, s := range *v {\n" +
"\t\tenc.Object(s)\n" +
diff --git a/gojay/gen_array_test.go b/gojay/gen_array_test.go
@@ -277,6 +277,72 @@ func (v *IntSlice) IsNil() bool {
}
`,
},
+ "basicFloatSlice": {
+ input: strings.NewReader(`package test
+
+//gojay:json
+type IntSlice []float64
+ `),
+ expectedResult: `package
+
+import "github.com/francoispqt/gojay"
+
+// UnmarshalJSONArray implements gojay's UnmarshalerJSONArray
+func (v *IntSlice) UnmarshalJSONArray(dec *gojay.Decoder) error {
+ var i float64
+ if err := dec.Float64(&i); err != nil {
+ return err
+ }
+ *v = append(*v, i)
+ return nil
+}
+
+// MarshalJSONArray implements gojay's MarshalerJSONArray
+func (v *IntSlice) MarshalJSONArray(enc *gojay.Encoder) {
+ for _, s := range *v {
+ enc.Float64(s)
+ }
+}
+
+// IsNil implements gojay's MarshalerJSONArray
+func (v *IntSlice) IsNil() bool {
+ return *v == nil || len(*v) == 0
+}
+`,
+ },
+ "basicFloat32Slice": {
+ input: strings.NewReader(`package test
+
+//gojay:json
+type IntSlice []float32
+ `),
+ expectedResult: `package
+
+import "github.com/francoispqt/gojay"
+
+// UnmarshalJSONArray implements gojay's UnmarshalerJSONArray
+func (v *IntSlice) UnmarshalJSONArray(dec *gojay.Decoder) error {
+ var i float32
+ if err := dec.Float32(&i); err != nil {
+ return err
+ }
+ *v = append(*v, i)
+ return nil
+}
+
+// MarshalJSONArray implements gojay's MarshalerJSONArray
+func (v *IntSlice) MarshalJSONArray(enc *gojay.Encoder) {
+ for _, s := range *v {
+ enc.Float32(s)
+ }
+}
+
+// IsNil implements gojay's MarshalerJSONArray
+func (v *IntSlice) IsNil() bool {
+ return *v == nil || len(*v) == 0
+}
+`,
+ },
"basicStructSlice": {
input: strings.NewReader(`package test
diff --git a/gojay/gen_array_unmarshal.go b/gojay/gen_array_unmarshal.go
@@ -2,7 +2,9 @@ package main
import (
"errors"
+ "fmt"
"go/ast"
+ "log"
)
func (g *Gen) arrGenUnmarshal(n string, s *ast.ArrayType) error {
@@ -29,7 +31,7 @@ func (g *Gen) arrGenUnmarshal(n string, s *ast.ArrayType) error {
return err
}
default:
- return errors.New("Unknown type")
+ return fmt.Errorf("Unknown type %s", n)
}
}
_, err = g.b.Write(structUnmarshalClose)
@@ -42,27 +44,31 @@ func (g *Gen) arrGenUnmarshal(n string, s *ast.ArrayType) error {
func (g *Gen) arrGenUnmarshalIdent(i *ast.Ident, ptr bool) error {
switch i.String() {
case "string":
- return g.arrUnmarshalString(ptr)
+ g.arrUnmarshalString(ptr)
case "bool":
- return g.arrUnmarshalBool(ptr)
+ g.arrUnmarshalBool(ptr)
case "int":
- return g.arrUnmarshalInt("", ptr)
+ g.arrUnmarshalInt("", ptr)
case "int64":
- return g.arrUnmarshalInt("64", ptr)
+ g.arrUnmarshalInt("64", ptr)
case "int32":
- return g.arrUnmarshalInt("32", ptr)
+ g.arrUnmarshalInt("32", ptr)
case "int16":
- return g.arrUnmarshalInt("16", ptr)
+ g.arrUnmarshalInt("16", ptr)
case "int8":
- return g.arrUnmarshalInt("8", ptr)
+ g.arrUnmarshalInt("8", ptr)
case "uint64":
- return g.arrUnmarshalUint("64", ptr)
+ g.arrUnmarshalUint("64", ptr)
case "uint32":
- return g.arrUnmarshalUint("32", ptr)
+ g.arrUnmarshalUint("32", ptr)
case "uint16":
- return g.arrUnmarshalUint("16", ptr)
+ g.arrUnmarshalUint("16", ptr)
case "uint8":
- return g.arrUnmarshalUint("8", ptr)
+ g.arrUnmarshalUint("8", ptr)
+ case "float64":
+ g.arrUnmarshalFloat("64", ptr)
+ case "float32":
+ g.arrUnmarshalFloat("32", ptr)
default:
// if ident is already in our spec list
if sp, ok := g.genTypes[i.Name]; ok {
@@ -76,66 +82,65 @@ func (g *Gen) arrGenUnmarshalIdent(i *ast.Ident, ptr bool) error {
return errors.New("could not determine what to do with type " + i.String())
}
}
- return errors.New("Unknown type")
+ return fmt.Errorf("Unknown type %s", i.Name)
}
+ return nil
}
func (g *Gen) arrUnmarshalNonPrim(sp *ast.TypeSpec, ptr bool) error {
switch sp.Type.(type) {
case *ast.StructType:
- return g.arrUnmarshalStruct(sp, ptr)
+ g.arrUnmarshalStruct(sp, ptr)
case *ast.ArrayType:
- return g.arrUnmarshalArr(sp, ptr)
+ g.arrUnmarshalArr(sp, ptr)
}
return nil
}
-func (g *Gen) arrUnmarshalString(ptr bool) error {
+func (g *Gen) arrUnmarshalString(ptr bool) {
if ptr {
err := arrUnmarshalTpl["stringPtr"].tpl.Execute(g.b, struct {
Ptr string
}{""})
if err != nil {
- return err
+ log.Fatal(err)
}
} else {
err := arrUnmarshalTpl["string"].tpl.Execute(g.b, struct {
Ptr string
}{"&"})
if err != nil {
- return err
+ log.Fatal(err)
}
}
- return nil
}
-func (g *Gen) arrUnmarshalBool(ptr bool) error {
+func (g *Gen) arrUnmarshalBool(ptr bool) {
if ptr {
err := arrUnmarshalTpl["bool"].tpl.Execute(g.b, struct {
Ptr string
}{""})
if err != nil {
- return err
+ log.Fatal(err)
}
} else {
err := arrUnmarshalTpl["bool"].tpl.Execute(g.b, struct {
Ptr string
}{"&"})
if err != nil {
- return err
+ log.Fatal(err)
}
}
- return nil
}
-func (g *Gen) arrUnmarshalInt(intLen string, ptr bool) error {
+func (g *Gen) arrUnmarshalInt(intLen string, ptr bool) {
if ptr {
err := arrUnmarshalTpl["int"].tpl.Execute(g.b, struct {
IntLen string
Ptr string
}{intLen, ""})
if err != nil {
- return err
+ log.Fatal(err)
}
} else {
err := arrUnmarshalTpl["int"].tpl.Execute(g.b, struct {
@@ -143,20 +148,19 @@ func (g *Gen) arrUnmarshalInt(intLen string, ptr bool) error {
Ptr string
}{intLen, "&"})
if err != nil {
- return err
+ log.Fatal(err)
}
}
- return nil
}
-func (g *Gen) arrUnmarshalUint(intLen string, ptr bool) error {
+func (g *Gen) arrUnmarshalUint(intLen string, ptr bool) {
if ptr {
err := arrUnmarshalTpl["uint"].tpl.Execute(g.b, struct {
IntLen string
Ptr string
}{intLen, ""})
if err != nil {
- return err
+ log.Fatal(err)
}
} else {
err := arrUnmarshalTpl["uint"].tpl.Execute(g.b, struct {
@@ -164,46 +168,63 @@ func (g *Gen) arrUnmarshalUint(intLen string, ptr bool) error {
Ptr string
}{intLen, "&"})
if err != nil {
- return err
+ log.Fatal(err)
+ }
+ }
+}
+
+func (g *Gen) arrUnmarshalFloat(intLen string, ptr bool) {
+ if ptr {
+ err := arrUnmarshalTpl["float"].tpl.Execute(g.b, struct {
+ IntLen string
+ Ptr string
+ }{intLen, ""})
+ if err != nil {
+ log.Fatal(err)
+ }
+ } else {
+ err := arrUnmarshalTpl["float"].tpl.Execute(g.b, struct {
+ IntLen string
+ Ptr string
+ }{intLen, "&"})
+ if err != nil {
+ log.Fatal(err)
}
}
- return nil
}
-func (g *Gen) arrUnmarshalStruct(st *ast.TypeSpec, ptr bool) error {
+func (g *Gen) arrUnmarshalStruct(st *ast.TypeSpec, ptr bool) {
if ptr {
err := arrUnmarshalTpl["structPtr"].tpl.Execute(g.b, struct {
StructName string
}{st.Name.String()})
if err != nil {
- return err
+ log.Fatal(err)
}
} else {
err := arrUnmarshalTpl["struct"].tpl.Execute(g.b, struct {
StructName string
}{st.Name.String()})
if err != nil {
- return err
+ log.Fatal(err)
}
}
- return nil
}
-func (g *Gen) arrUnmarshalArr(st *ast.TypeSpec, ptr bool) error {
+func (g *Gen) arrUnmarshalArr(st *ast.TypeSpec, ptr bool) {
if ptr {
err := arrUnmarshalTpl["arrPtr"].tpl.Execute(g.b, struct {
StructName string
}{st.Name.String()})
if err != nil {
- return err
+ log.Fatal(err)
}
} else {
err := arrUnmarshalTpl["arr"].tpl.Execute(g.b, struct {
StructName string
}{st.Name.String()})
if err != nil {
- return err
+ log.Fatal(err)
}
}
- return nil
}
diff --git a/gojay/gen_array_unmarshal_tpl.go b/gojay/gen_array_unmarshal_tpl.go
@@ -27,6 +27,12 @@ var arrUnmarshalTpl = templateList{
"\t\treturn err\n\t}\n" +
"\t*v = append(*v, i)\n",
},
+ "float": &genTpl{
+ strTpl: "\tvar i float{{.IntLen}}" +
+ "\n\tif err := dec.Float{{.IntLen}}(&i); err != nil {\n" +
+ "\t\treturn err\n\t}\n" +
+ "\t*v = append(*v, i)\n",
+ },
"bool": &genTpl{
strTpl: "\tvar b bool" +
"\n\tif err := dec.Bool(&b); err != nil {\n" +
diff --git a/gojay/gen_map_marshal.go b/gojay/gen_map_marshal.go
@@ -2,6 +2,7 @@ package main
import (
"errors"
+ "fmt"
"go/ast"
"log"
)
@@ -40,7 +41,7 @@ func (g *Gen) mapGenMarshalObj(n string, s *ast.MapType) error {
return err
}
default:
- return errors.New("Unknown type")
+ return fmt.Errorf("Unknown type %s", n)
}
}
_, err = g.b.Write([]byte("}\n"))
@@ -75,7 +76,9 @@ func (g *Gen) mapGenMarshalIdent(i *ast.Ident, ptr bool) error {
case "uint8":
g.mapMarshalUint("8", ptr)
case "float64":
- g.mapMarshalFloat("", ptr)
+ g.mapMarshalFloat("64", ptr)
+ case "float32":
+ g.mapMarshalFloat("32", ptr)
default:
// if ident is already in our spec list
if sp, ok := g.genTypes[i.Name]; ok {
@@ -88,7 +91,7 @@ func (g *Gen) mapGenMarshalIdent(i *ast.Ident, ptr bool) error {
return errors.New("could not determine what to do with type " + i.String())
}
} else {
- return errors.New("Unknown type")
+ return fmt.Errorf("Unknown type %s", i.Name)
}
}
return nil
diff --git a/gojay/gen_map_marshal_tpl.go b/gojay/gen_map_marshal_tpl.go
@@ -13,31 +13,31 @@ func (v {{.StructName}}) IsNil() bool { return v == nil || len(v) == 0 }
},
"string": &genTpl{
strTpl: ` for k, s := range v {
- enc.StringKey(k, s)
+ enc.StringKey(k, {{.Ptr}}s)
}
`,
},
"int": &genTpl{
strTpl: ` for k, s := range v {
- enc.Int{{.IntLen}}Key(k, s)
+ enc.Int{{.IntLen}}Key(k, {{.Ptr}}s)
}
`,
},
"uint": &genTpl{
strTpl: ` for k, s := range v {
- enc.Uint{{.IntLen}}Key(k, s)
+ enc.Uint{{.IntLen}}Key(k, {{.Ptr}}s)
}
`,
},
"float": &genTpl{
strTpl: ` for k, s := range v {
- enc.Float{{.IntLen}}Key(k, s)
+ enc.Float{{.IntLen}}Key(k, {{.Ptr}}s)
}
`,
},
"bool": &genTpl{
strTpl: ` for k, s := range v {
- enc.BoolKey(k, s)
+ enc.BoolKey(k, {{.Ptr}}s)
}
`,
},
diff --git a/gojay/gen_map_test.go b/gojay/gen_map_test.go
@@ -48,6 +48,40 @@ func (v StrMap) MarshalJSONObject(enc *gojay.Encoder) {
func (v StrMap) IsNil() bool { return v == nil || len(v) == 0 }
`,
},
+ "basicMapStringStringPtr": {
+ input: strings.NewReader(`package test
+
+//gojay:json
+type StrMap map[string]*string
+`),
+ expectedResult: `package
+
+import "github.com/francoispqt/gojay"
+
+// UnmarshalJSONObject implements gojay's UnmarshalerJSONObject
+func (v StrMap) UnmarshalJSONObject(dec *gojay.Decoder, k string) error {
+ var str string
+ if err := dec.String(&str); err != nil {
+ return err
+ }
+ v[k] = &str
+ return nil
+}
+
+// NKeys returns the number of keys to unmarshal
+func (v StrMap) NKeys() int { return 0 }
+
+// MarshalJSONObject implements gojay's MarshalerJSONObject
+func (v StrMap) MarshalJSONObject(enc *gojay.Encoder) {
+ for k, s := range v {
+ enc.StringKey(k, *s)
+ }
+}
+
+// IsNil returns wether the structure is nil value or not
+func (v StrMap) IsNil() bool { return v == nil || len(v) == 0 }
+`,
+ },
"basicMapStringInt": {
input: strings.NewReader(`package test
@@ -82,6 +116,40 @@ func (v IntMap) MarshalJSONObject(enc *gojay.Encoder) {
func (v IntMap) IsNil() bool { return v == nil || len(v) == 0 }
`,
},
+ "basicMapStringIntPtr": {
+ input: strings.NewReader(`package test
+
+//gojay:json
+type IntMap map[string]*int
+`),
+ expectedResult: `package
+
+import "github.com/francoispqt/gojay"
+
+// UnmarshalJSONObject implements gojay's UnmarshalerJSONObject
+func (v IntMap) UnmarshalJSONObject(dec *gojay.Decoder, k string) error {
+ var i int
+ if err := dec.Int(&i); err != nil {
+ return err
+ }
+ v[k] = &i
+ return nil
+}
+
+// NKeys returns the number of keys to unmarshal
+func (v IntMap) NKeys() int { return 0 }
+
+// MarshalJSONObject implements gojay's MarshalerJSONObject
+func (v IntMap) MarshalJSONObject(enc *gojay.Encoder) {
+ for k, s := range v {
+ enc.IntKey(k, *s)
+ }
+}
+
+// IsNil returns wether the structure is nil value or not
+func (v IntMap) IsNil() bool { return v == nil || len(v) == 0 }
+`,
+ },
"basicMapStringInt64": {
input: strings.NewReader(`package test
@@ -116,6 +184,40 @@ func (v IntMap) MarshalJSONObject(enc *gojay.Encoder) {
func (v IntMap) IsNil() bool { return v == nil || len(v) == 0 }
`,
},
+ "basicMapStringInt64Ptr": {
+ input: strings.NewReader(`package test
+
+//gojay:json
+type IntMap map[string]*int64
+`),
+ expectedResult: `package
+
+import "github.com/francoispqt/gojay"
+
+// UnmarshalJSONObject implements gojay's UnmarshalerJSONObject
+func (v IntMap) UnmarshalJSONObject(dec *gojay.Decoder, k string) error {
+ var i int64
+ if err := dec.Int64(&i); err != nil {
+ return err
+ }
+ v[k] = &i
+ return nil
+}
+
+// NKeys returns the number of keys to unmarshal
+func (v IntMap) NKeys() int { return 0 }
+
+// MarshalJSONObject implements gojay's MarshalerJSONObject
+func (v IntMap) MarshalJSONObject(enc *gojay.Encoder) {
+ for k, s := range v {
+ enc.Int64Key(k, *s)
+ }
+}
+
+// IsNil returns wether the structure is nil value or not
+func (v IntMap) IsNil() bool { return v == nil || len(v) == 0 }
+`,
+ },
"basicMapStringInt32": {
input: strings.NewReader(`package test
@@ -252,6 +354,40 @@ func (v IntMap) MarshalJSONObject(enc *gojay.Encoder) {
func (v IntMap) IsNil() bool { return v == nil || len(v) == 0 }
`,
},
+ "basicMapStringUint64Ptr": {
+ input: strings.NewReader(`package test
+
+//gojay:json
+type IntMap map[string]*uint64
+`),
+ expectedResult: `package
+
+import "github.com/francoispqt/gojay"
+
+// UnmarshalJSONObject implements gojay's UnmarshalerJSONObject
+func (v IntMap) UnmarshalJSONObject(dec *gojay.Decoder, k string) error {
+ var i uint64
+ if err := dec.Uint64(&i); err != nil {
+ return err
+ }
+ v[k] = &i
+ return nil
+}
+
+// NKeys returns the number of keys to unmarshal
+func (v IntMap) NKeys() int { return 0 }
+
+// MarshalJSONObject implements gojay's MarshalerJSONObject
+func (v IntMap) MarshalJSONObject(enc *gojay.Encoder) {
+ for k, s := range v {
+ enc.Uint64Key(k, *s)
+ }
+}
+
+// IsNil returns wether the structure is nil value or not
+func (v IntMap) IsNil() bool { return v == nil || len(v) == 0 }
+`,
+ },
"basicMapStringUint32": {
input: strings.NewReader(`package test
@@ -388,6 +524,40 @@ func (v BoolMap) MarshalJSONObject(enc *gojay.Encoder) {
func (v BoolMap) IsNil() bool { return v == nil || len(v) == 0 }
`,
},
+ "basicMapStringBoolPtr": {
+ input: strings.NewReader(`package test
+
+//gojay:json
+type BoolMap map[string]*bool
+`),
+ expectedResult: `package
+
+import "github.com/francoispqt/gojay"
+
+// UnmarshalJSONObject implements gojay's UnmarshalerJSONObject
+func (v BoolMap) UnmarshalJSONObject(dec *gojay.Decoder, k string) error {
+ var b bool
+ if err := dec.Bool(&b); err != nil {
+ return err
+ }
+ v[k] = &b
+ return nil
+}
+
+// NKeys returns the number of keys to unmarshal
+func (v BoolMap) NKeys() int { return 0 }
+
+// MarshalJSONObject implements gojay's MarshalerJSONObject
+func (v BoolMap) MarshalJSONObject(enc *gojay.Encoder) {
+ for k, s := range v {
+ enc.BoolKey(k, *s)
+ }
+}
+
+// IsNil returns wether the structure is nil value or not
+func (v BoolMap) IsNil() bool { return v == nil || len(v) == 0 }
+`,
+ },
"basicMapStringStruct": {
input: strings.NewReader(`package test
diff --git a/gojay/gen_map_unmarshal.go b/gojay/gen_map_unmarshal.go
@@ -2,6 +2,7 @@ package main
import (
"errors"
+ "fmt"
"go/ast"
"log"
)
@@ -42,7 +43,7 @@ func (g *Gen) mapGenUnmarshalObj(n string, s *ast.MapType) error {
return err
}
default:
- return errors.New("Unknown type")
+ return fmt.Errorf("Unknown type %s", n)
}
}
_, err = g.b.Write(structUnmarshalClose)
@@ -77,7 +78,9 @@ func (g *Gen) mapGenUnmarshalIdent(i *ast.Ident, ptr bool) error {
case "uint8":
g.mapUnmarshalUint("8", ptr)
case "float64":
- g.mapUnmarshalFloat("", ptr)
+ g.mapUnmarshalFloat("64", ptr)
+ case "float32":
+ g.mapUnmarshalFloat("32", ptr)
default:
// if ident is already in our spec list
if sp, ok := g.genTypes[i.Name]; ok {
@@ -97,7 +100,7 @@ func (g *Gen) mapGenUnmarshalIdent(i *ast.Ident, ptr bool) error {
return errors.New("could not determine what to do with type " + i.String())
}
} else {
- return errors.New("Unknown type")
+ return fmt.Errorf("Unknown type %s", i.Name)
}
}
return nil
@@ -119,14 +122,14 @@ func (g *Gen) mapUnmarshalString(ptr bool) {
if ptr {
err := mapUnmarshalTpl["string"].tpl.Execute(g.b, struct {
Ptr string
- }{""})
+ }{"&"})
if err != nil {
log.Fatal(err)
}
} else {
err := mapUnmarshalTpl["string"].tpl.Execute(g.b, struct {
Ptr string
- }{"&"})
+ }{""})
if err != nil {
log.Fatal(err)
}
@@ -137,14 +140,14 @@ func (g *Gen) mapUnmarshalBool(ptr bool) {
if ptr {
err := mapUnmarshalTpl["bool"].tpl.Execute(g.b, struct {
Ptr string
- }{""})
+ }{"&"})
if err != nil {
log.Fatal(err)
}
} else {
err := mapUnmarshalTpl["bool"].tpl.Execute(g.b, struct {
Ptr string
- }{"&"})
+ }{""})
if err != nil {
log.Fatal(err)
}
@@ -156,7 +159,7 @@ func (g *Gen) mapUnmarshalInt(intLen string, ptr bool) {
err := mapUnmarshalTpl["int"].tpl.Execute(g.b, struct {
IntLen string
Ptr string
- }{intLen, ""})
+ }{intLen, "&"})
if err != nil {
log.Fatal(err)
}
@@ -164,7 +167,7 @@ func (g *Gen) mapUnmarshalInt(intLen string, ptr bool) {
err := mapUnmarshalTpl["int"].tpl.Execute(g.b, struct {
IntLen string
Ptr string
- }{intLen, "&"})
+ }{intLen, ""})
if err != nil {
log.Fatal(err)
}
@@ -176,7 +179,7 @@ func (g *Gen) mapUnmarshalUint(intLen string, ptr bool) {
err := mapUnmarshalTpl["uint"].tpl.Execute(g.b, struct {
IntLen string
Ptr string
- }{intLen, ""})
+ }{intLen, "&"})
if err != nil {
log.Fatal(err)
}
@@ -184,7 +187,7 @@ func (g *Gen) mapUnmarshalUint(intLen string, ptr bool) {
err := mapUnmarshalTpl["uint"].tpl.Execute(g.b, struct {
IntLen string
Ptr string
- }{intLen, "&"})
+ }{intLen, ""})
if err != nil {
log.Fatal(err)
}
@@ -196,7 +199,7 @@ func (g *Gen) mapUnmarshalFloat(intLen string, ptr bool) {
err := mapUnmarshalTpl["float"].tpl.Execute(g.b, struct {
IntLen string
Ptr string
- }{intLen, ""})
+ }{intLen, "&"})
if err != nil {
log.Fatal(err)
}
@@ -204,7 +207,7 @@ func (g *Gen) mapUnmarshalFloat(intLen string, ptr bool) {
err := mapUnmarshalTpl["float"].tpl.Execute(g.b, struct {
IntLen string
Ptr string
- }{intLen, "&"})
+ }{intLen, ""})
if err != nil {
log.Fatal(err)
}
diff --git a/gojay/gen_map_unmarshal_tpl.go b/gojay/gen_map_unmarshal_tpl.go
@@ -16,7 +16,7 @@ func (v {{.StructName}}) NKeys() int { return {{.NKeys}} }
if err := dec.String(&str); err != nil {
return err
}
- v[k] = str
+ v[k] = {{.Ptr}}str
`,
},
"int": &genTpl{
@@ -24,7 +24,7 @@ func (v {{.StructName}}) NKeys() int { return {{.NKeys}} }
if err := dec.Int{{.IntLen}}(&i); err != nil {
return err
}
- v[k] = i
+ v[k] = {{.Ptr}}i
`,
},
"uint": &genTpl{
@@ -32,7 +32,7 @@ func (v {{.StructName}}) NKeys() int { return {{.NKeys}} }
if err := dec.Uint{{.IntLen}}(&i); err != nil {
return err
}
- v[k] = i
+ v[k] = {{.Ptr}}i
`,
},
"float": &genTpl{
@@ -40,7 +40,7 @@ func (v {{.StructName}}) NKeys() int { return {{.NKeys}} }
if err := dec.Float{{.IntLen}}(&i); err != nil {
return err
}
- v[k] = i
+ v[k] = {{.Ptr}}i
`,
},
"bool": &genTpl{
@@ -48,7 +48,7 @@ func (v {{.StructName}}) NKeys() int { return {{.NKeys}} }
if err := dec.Bool(&b); err != nil {
return err
}
- v[k] = b
+ v[k] = {{.Ptr}}b
`,
},
"struct": &genTpl{
diff --git a/gojay/gen_struct_marshal.go b/gojay/gen_struct_marshal.go
@@ -1,7 +1,7 @@
package main
import (
- "errors"
+ "fmt"
"go/ast"
"log"
)
@@ -29,13 +29,19 @@ func (g *Gen) structGenMarshalObj(n string, s *ast.StructType) (int, error) {
// TODO: check tags
for _, field := range s.Fields.List {
// check if has hide tag
- if field.Tag != nil && hasTagMarshalHide(field.Tag) {
- continue
+ var omitEmpty string
+ if field.Tag != nil {
+ if hasTagMarshalHide(field.Tag) {
+ continue
+ }
+ if hasTagOmitEmpty(field.Tag) {
+ omitEmpty = omitEmptyFuncName
+ }
}
switch t := field.Type.(type) {
case *ast.Ident:
var err error
- keys, err = g.structGenMarshalIdent(field, t, keys, false)
+ keys, err = g.structGenMarshalIdent(field, t, keys, omitEmpty, false)
if err != nil {
return 0, err
}
@@ -43,12 +49,12 @@ func (g *Gen) structGenMarshalObj(n string, s *ast.StructType) (int, error) {
switch ptrExp := t.X.(type) {
case *ast.Ident:
var err error
- keys, err = g.structGenMarshalIdent(field, ptrExp, keys, true)
+ keys, err = g.structGenMarshalIdent(field, ptrExp, keys, omitEmpty, true)
if err != nil {
return 0, err
}
default:
- return 0, errors.New("Unknown type")
+ return 0, fmt.Errorf("Unknown type %s", n)
}
}
}
@@ -60,50 +66,53 @@ func (g *Gen) structGenMarshalObj(n string, s *ast.StructType) (int, error) {
return keys, nil
}
-func (g *Gen) structGenMarshalIdent(field *ast.Field, i *ast.Ident, keys int, ptr bool) (int, error) {
+func (g *Gen) structGenMarshalIdent(field *ast.Field, i *ast.Ident, keys int, omitEmpty string, ptr bool) (int, error) {
var keyV = getStructFieldJSONKey(field)
switch i.String() {
case "string":
- g.structMarshalString(field, keyV, ptr)
+ g.structMarshalString(field, keyV, omitEmpty, ptr)
keys++
case "bool":
- g.structMarshalBool(field, keyV, ptr)
+ g.structMarshalBool(field, keyV, omitEmpty, ptr)
keys++
case "int":
- g.structMarshalInt(field, keyV, "", ptr)
+ g.structMarshalInt(field, keyV, "", omitEmpty, ptr)
keys++
case "int64":
- g.structMarshalInt(field, keyV, "64", ptr)
+ g.structMarshalInt(field, keyV, "64", omitEmpty, ptr)
keys++
case "int32":
- g.structMarshalInt(field, keyV, "32", ptr)
+ g.structMarshalInt(field, keyV, "32", omitEmpty, ptr)
keys++
case "int16":
- g.structMarshalInt(field, keyV, "16", ptr)
+ g.structMarshalInt(field, keyV, "16", omitEmpty, ptr)
keys++
case "int8":
- g.structMarshalInt(field, keyV, "8", ptr)
+ g.structMarshalInt(field, keyV, "8", omitEmpty, ptr)
keys++
case "uint64":
- g.structMarshalUint(field, keyV, "64", ptr)
+ g.structMarshalUint(field, keyV, "64", omitEmpty, ptr)
keys++
case "uint32":
- g.structMarshalUint(field, keyV, "32", ptr)
+ g.structMarshalUint(field, keyV, "32", omitEmpty, ptr)
keys++
case "uint16":
- g.structMarshalUint(field, keyV, "16", ptr)
+ g.structMarshalUint(field, keyV, "16", omitEmpty, ptr)
keys++
case "uint8":
- g.structMarshalUint(field, keyV, "8", ptr)
+ g.structMarshalUint(field, keyV, "8", omitEmpty, ptr)
keys++
case "float64":
- g.structMarshalFloat(field, keyV, "", ptr)
+ g.structMarshalFloat(field, keyV, "64", omitEmpty, ptr)
+ keys++
+ case "float32":
+ g.structMarshalFloat(field, keyV, "32", omitEmpty, ptr)
keys++
default:
// if ident is already in our spec list
if sp, ok := g.genTypes[i.Name]; ok {
- err := g.structMarshalNonPrim(field, keyV, sp, ptr)
+ err := g.structMarshalNonPrim(field, keyV, sp, omitEmpty, ptr)
if err != nil {
return 0, err
}
@@ -111,139 +120,166 @@ func (g *Gen) structGenMarshalIdent(field *ast.Field, i *ast.Ident, keys int, pt
} else if i.Obj != nil {
switch t := i.Obj.Decl.(type) {
case *ast.TypeSpec:
- var err = g.structMarshalNonPrim(field, keyV, t, ptr)
+ var err = g.structMarshalNonPrim(field, keyV, t, omitEmpty, ptr)
if err != nil {
return 0, err
}
keys++
default:
- return 0, errors.New("could not determine what to do with type " + i.String())
+ g.structMarshalAny(field, keyV, sp, ptr)
+ keys++
}
} else {
- return 0, errors.New("Unknown type")
+ g.structMarshalAny(field, keyV, sp, ptr)
+ keys++
}
}
return keys, nil
}
-func (g *Gen) structMarshalNonPrim(field *ast.Field, keyV string, sp *ast.TypeSpec, ptr bool) error {
+func (g *Gen) structMarshalNonPrim(field *ast.Field, keyV string, sp *ast.TypeSpec, omitEmpty string, ptr bool) error {
switch sp.Type.(type) {
case *ast.StructType:
- g.structMarshalStruct(field, keyV, sp, ptr)
+ g.structMarshalStruct(field, keyV, sp, omitEmpty, ptr)
return nil
case *ast.ArrayType:
- g.structMarshalArr(field, keyV, sp, ptr)
+ g.structMarshalArr(field, keyV, sp, omitEmpty, ptr)
return nil
+ default:
+ g.structMarshalAny(field, keyV, sp, ptr)
}
return nil
}
-func (g *Gen) structMarshalString(field *ast.Field, keyV string, ptr bool) {
+func (g *Gen) structMarshalString(field *ast.Field, keyV string, omitEmpty string, ptr bool) {
key := field.Names[0].String()
ptrStr := ""
if ptr {
ptrStr = "*"
}
err := structMarshalTpl["string"].tpl.Execute(g.b, struct {
- Field string
- Key string
- Ptr string
- }{key, keyV, ptrStr})
+ Field string
+ Key string
+ OmitEmpty string
+ Ptr string
+ }{key, keyV, omitEmpty, ptrStr})
if err != nil {
log.Fatal(err)
}
}
-func (g *Gen) structMarshalBool(field *ast.Field, keyV string, ptr bool) {
+func (g *Gen) structMarshalBool(field *ast.Field, keyV string, omitEmpty string, ptr bool) {
key := field.Names[0].String()
ptrStr := ""
if ptr {
ptrStr = "*"
}
err := structMarshalTpl["bool"].tpl.Execute(g.b, struct {
- Field string
- Key string
- Ptr string
- }{key, keyV, ptrStr})
+ Field string
+ Key string
+ OmitEmpty string
+ Ptr string
+ }{key, keyV, omitEmpty, ptrStr})
if err != nil {
log.Fatal(err)
}
}
-func (g *Gen) structMarshalInt(field *ast.Field, keyV string, intLen string, ptr bool) {
+func (g *Gen) structMarshalInt(field *ast.Field, keyV string, intLen string, omitEmpty string, ptr bool) {
key := field.Names[0].String()
ptrStr := ""
if ptr {
ptrStr = "*"
}
err := structMarshalTpl["int"].tpl.Execute(g.b, struct {
- Field string
- IntLen string
- Key string
- Ptr string
- }{key, intLen, keyV, ptrStr})
+ Field string
+ IntLen string
+ Key string
+ OmitEmpty string
+ Ptr string
+ }{key, intLen, keyV, omitEmpty, ptrStr})
if err != nil {
log.Fatal(err)
}
}
-func (g *Gen) structMarshalUint(field *ast.Field, keyV string, intLen string, ptr bool) {
+func (g *Gen) structMarshalUint(field *ast.Field, keyV string, intLen string, omitEmpty string, ptr bool) {
key := field.Names[0].String()
ptrStr := ""
if ptr {
ptrStr = "*"
}
err := structMarshalTpl["uint"].tpl.Execute(g.b, struct {
- Field string
- IntLen string
- Key string
- Ptr string
- }{key, intLen, keyV, ptrStr})
+ Field string
+ IntLen string
+ Key string
+ OmitEmpty string
+ Ptr string
+ }{key, intLen, keyV, omitEmpty, ptrStr})
if err != nil {
log.Fatal(err)
}
}
-func (g *Gen) structMarshalFloat(field *ast.Field, keyV string, intLen string, ptr bool) {
+func (g *Gen) structMarshalFloat(field *ast.Field, keyV string, intLen string, omitEmpty string, ptr bool) {
key := field.Names[0].String()
ptrStr := ""
if ptr {
ptrStr = "*"
}
err := structMarshalTpl["float"].tpl.Execute(g.b, struct {
- Field string
- IntLen string
- Key string
- Ptr string
- }{key, intLen, keyV, ptrStr})
+ Field string
+ IntLen string
+ Key string
+ OmitEmpty string
+ Ptr string
+ }{key, intLen, keyV, omitEmpty, ptrStr})
if err != nil {
log.Fatal(err)
}
}
-func (g *Gen) structMarshalStruct(field *ast.Field, keyV string, st *ast.TypeSpec, ptr bool) {
+func (g *Gen) structMarshalStruct(field *ast.Field, keyV string, st *ast.TypeSpec, omitEmpty string, ptr bool) {
key := field.Names[0].String()
ptrStr := ""
if ptr {
ptrStr = "*"
}
var err = structMarshalTpl["struct"].tpl.Execute(g.b, struct {
- Key string
- Field string
- Ptr string
- }{keyV, key, ptrStr})
+ Key string
+ Field string
+ OmitEmpty string
+ Ptr string
+ }{keyV, key, omitEmpty, ptrStr})
if err != nil {
log.Fatal(err)
}
}
-func (g *Gen) structMarshalArr(field *ast.Field, keyV string, st *ast.TypeSpec, ptr bool) {
+func (g *Gen) structMarshalArr(field *ast.Field, keyV string, st *ast.TypeSpec, omitEmpty string, ptr bool) {
key := field.Names[0].String()
ptrStr := ""
if ptr {
ptrStr = "*"
}
var err = structMarshalTpl["arr"].tpl.Execute(g.b, struct {
+ Key string
+ Field string
+ OmitEmpty string
+ Ptr string
+ }{keyV, key, omitEmpty, ptrStr})
+ if err != nil {
+ log.Fatal(err)
+ }
+}
+
+func (g *Gen) structMarshalAny(field *ast.Field, keyV string, st *ast.TypeSpec, ptr bool) {
+ key := field.Names[0].String()
+ ptrStr := ""
+ if ptr {
+ ptrStr = "*"
+ }
+ var err = structMarshalTpl["any"].tpl.Execute(g.b, struct {
Key string
Field string
Ptr string
diff --git a/gojay/gen_struct_marshal_tpl.go b/gojay/gen_struct_marshal_tpl.go
@@ -12,25 +12,28 @@ func (v *{{.StructName}}) IsNil() bool { return v == nil }
`,
},
"string": &genTpl{
- strTpl: "\tenc.StringKey(\"{{.Key}}\", {{.Ptr}}v.{{.Field}})\n",
+ strTpl: "\tenc.StringKey{{.OmitEmpty}}(\"{{.Key}}\", {{.Ptr}}v.{{.Field}})\n",
},
"int": &genTpl{
- strTpl: "\tenc.Int{{.IntLen}}Key(\"{{.Key}}\", {{.Ptr}}v.{{.Field}})\n",
+ strTpl: "\tenc.Int{{.IntLen}}Key{{.OmitEmpty}}(\"{{.Key}}\", {{.Ptr}}v.{{.Field}})\n",
},
"uint": &genTpl{
- strTpl: "\tenc.Uint{{.IntLen}}Key(\"{{.Key}}\", {{.Ptr}}v.{{.Field}})\n",
+ strTpl: "\tenc.Uint{{.IntLen}}Key{{.OmitEmpty}}(\"{{.Key}}\", {{.Ptr}}v.{{.Field}})\n",
},
"float": &genTpl{
- strTpl: "\tenc.Float{{.IntLen}}Key(\"{{.Key}}\", {{.Ptr}}v.{{.Field}})\n",
+ strTpl: "\tenc.Float{{.IntLen}}Key{{.OmitEmpty}}(\"{{.Key}}\", {{.Ptr}}v.{{.Field}})\n",
},
"bool": &genTpl{
- strTpl: "\tenc.BoolKey(\"{{.Key}}\", {{.Ptr}}v.{{.Field}})\n",
+ strTpl: "\tenc.BoolKey{{.OmitEmpty}}(\"{{.Key}}\", {{.Ptr}}v.{{.Field}})\n",
},
"struct": &genTpl{
- strTpl: "\tenc.ObjectKey(\"{{.Key}}\", v.{{.Field}})\n",
+ strTpl: "\tenc.ObjectKey{{.OmitEmpty}}(\"{{.Key}}\", v.{{.Field}})\n",
},
"arr": &genTpl{
- strTpl: "\tenc.ArrayKey(\"{{.Key}}\", v.{{.Field}})\n",
+ strTpl: "\tenc.ArrayKey{{.OmitEmpty}}(\"{{.Key}}\", v.{{.Field}})\n",
+ },
+ "any": &genTpl{
+ strTpl: "\tenc.AnyKey(\"{{.Key}}\", v.{{.Field}})\n",
},
}
diff --git a/gojay/gen_struct_test.go b/gojay/gen_struct_test.go
@@ -27,9 +27,11 @@ type Struct struct{
Uint16 uint16
Uint32 uint32
Uint64 uint64
- Float float64
+ Float64 float64
+ Float32 float32
Str string
Bool bool
+ Unknown UnknownType
}
`),
expectedResult: `package
@@ -57,18 +59,22 @@ func (v *Struct) UnmarshalJSONObject(dec *gojay.Decoder, k string) error {
return dec.Uint32(&v.Uint32)
case "uint64":
return dec.Uint64(&v.Uint64)
- case "float":
- return dec.Float(&v.Float)
+ case "float64":
+ return dec.Float64(&v.Float64)
+ case "float32":
+ return dec.Float32(&v.Float32)
case "str":
return dec.String(&v.Str)
case "bool":
return dec.Bool(&v.Bool)
+ case "unknown":
+ return dec.Any(&v.Unknown)
}
return nil
}
// NKeys returns the number of keys to unmarshal
-func (v *Struct) NKeys() int { return 12 }
+func (v *Struct) NKeys() int { return 14 }
// MarshalJSONObject implements gojay's MarshalerJSONObject
func (v *Struct) MarshalJSONObject(enc *gojay.Encoder) {
@@ -81,9 +87,11 @@ func (v *Struct) MarshalJSONObject(enc *gojay.Encoder) {
enc.Uint16Key("uint16", v.Uint16)
enc.Uint32Key("uint32", v.Uint32)
enc.Uint64Key("uint64", v.Uint64)
- enc.FloatKey("float", v.Float)
+ enc.Float64Key("float64", v.Float64)
+ enc.Float32Key("float32", v.Float32)
enc.StringKey("str", v.Str)
enc.BoolKey("bool", v.Bool)
+ enc.AnyKey("unknown", v.Unknown)
}
// IsNil returns wether the structure is nil value or not
@@ -368,6 +376,42 @@ func (v *Struct) MarshalJSONObject(enc *gojay.Encoder) {
func (v *Struct) IsNil() bool { return v == nil }
`,
},
+ "complexStructStructPtrTagOmitEmpty": {
+ input: strings.NewReader(`package test
+
+//gojay:json
+type Struct struct{
+ Struct *Struct ` + "`gojay:\"someStruct,omitempty\"`" + `
+}
+ `),
+ expectedResult: `package
+
+import "github.com/francoispqt/gojay"
+
+// UnmarshalJSONObject implements gojay's UnmarshalerJSONObject
+func (v *Struct) UnmarshalJSONObject(dec *gojay.Decoder, k string) error {
+ switch k {
+ case "someStruct":
+ if v.Struct == nil {
+ v.Struct = &Struct{}
+ }
+ return dec.Object(v.Struct)
+ }
+ return nil
+}
+
+// NKeys returns the number of keys to unmarshal
+func (v *Struct) NKeys() int { return 1 }
+
+// MarshalJSONObject implements gojay's MarshalerJSONObject
+func (v *Struct) MarshalJSONObject(enc *gojay.Encoder) {
+ enc.ObjectKeyOmitEmpty("someStruct", v.Struct)
+}
+
+// IsNil returns wether the structure is nil value or not
+func (v *Struct) IsNil() bool { return v == nil }
+`,
+ },
}
for n, testCase := range testCases {
t.Run(n, func(t *testing.T) {
diff --git a/gojay/gen_struct_unmarshal.go b/gojay/gen_struct_unmarshal.go
@@ -1,7 +1,7 @@
package main
import (
- "errors"
+ "fmt"
"go/ast"
"log"
)
@@ -57,7 +57,7 @@ func (g *Gen) structGenUnmarshalObj(n string, s *ast.StructType) (int, error) {
return 0, err
}
default:
- return 0, errors.New("Unknown type")
+ return 0, fmt.Errorf("Unknown type %s", n)
}
}
}
@@ -109,7 +109,10 @@ func (g *Gen) structGenUnmarshalIdent(field *ast.Field, i *ast.Ident, keys int,
g.structUnmarshalUint(field, keyV, "8", ptr)
keys++
case "float64":
- g.structUnmarshalFloat(field, keyV, "", ptr)
+ g.structUnmarshalFloat(field, keyV, "64", ptr)
+ keys++
+ case "float32":
+ g.structUnmarshalFloat(field, keyV, "32", ptr)
keys++
default:
// if ident is already in our spec list
@@ -129,10 +132,12 @@ func (g *Gen) structGenUnmarshalIdent(field *ast.Field, i *ast.Ident, keys int,
}
keys++
default:
- return 0, errors.New("could not determine what to do with type " + i.String())
+ g.structUnmarshalAny(field, keyV, sp, ptr)
+ keys++
}
} else {
- return 0, errors.New("Unknown type")
+ g.structUnmarshalAny(field, keyV, sp, ptr)
+ keys++
}
}
return keys, nil
@@ -146,8 +151,10 @@ func (g *Gen) structUnmarshalNonPrim(field *ast.Field, keyV string, sp *ast.Type
case *ast.ArrayType:
g.structUnmarshalArr(field, keyV, sp, ptr)
return nil
+ default:
+ g.structUnmarshalAny(field, keyV, sp, ptr)
+ return nil
}
- return errors.New("Unknown type")
}
func (g *Gen) structUnmarshalString(field *ast.Field, keyV string, ptr bool) {
@@ -344,3 +351,28 @@ func (g *Gen) structUnmarshalArr(field *ast.Field, keyV string, st *ast.TypeSpec
}
}
}
+
+func (g *Gen) structUnmarshalAny(field *ast.Field, keyV string, st *ast.TypeSpec, ptr bool) {
+ key := field.Names[0].String()
+ err := structUnmarshalTpl["case"].tpl.Execute(g.b, struct {
+ Key string
+ }{keyV})
+ if err != nil {
+ log.Fatal(err)
+ }
+ if ptr {
+ err = structUnmarshalTpl["anyPtr"].tpl.Execute(g.b, struct {
+ Field string
+ }{key})
+ if err != nil {
+ log.Fatal(err)
+ }
+ } else {
+ err = structUnmarshalTpl["any"].tpl.Execute(g.b, struct {
+ Field string
+ }{key})
+ if err != nil {
+ log.Fatal(err)
+ }
+ }
+}
diff --git a/gojay/gen_struct_unmarshal_tpl.go b/gojay/gen_struct_unmarshal_tpl.go
@@ -59,6 +59,12 @@ func (v *{{.StructName}}) NKeys() int { return {{.NKeys}} }
return dec.Array(v.{{.Field}})
`,
},
+ "any": &genTpl{
+ strTpl: "\t\treturn dec.Any(&v.{{.Field}})\n",
+ },
+ "anyPtr": &genTpl{
+ strTpl: "\t\treturn dec.Any(v.{{.Field}})\n",
+ },
}
func init() {
diff --git a/gojay/gen_tag.go b/gojay/gen_tag.go
@@ -11,6 +11,7 @@ const gojayTag = "gojay"
const hideTag = "-"
const unmarshalHideTag = "-u"
const marshalHideTag = "-m"
+const omitEmptyTag = "omitempty"
func getGojayTagValue(tags *ast.BasicLit) (*structtag.Tag, error) {
t, err := structtag.Parse(tags.Value[1 : len(tags.Value)-1])
@@ -42,6 +43,15 @@ func hasTagMarshalHide(tags *ast.BasicLit) bool {
return (v.Name == marshalHideTag || v.Name == hideTag) || v.HasOption(marshalHideTag)
}
+func hasTagOmitEmpty(tags *ast.BasicLit) bool {
+ v, err := getGojayTagValue(tags)
+ if err != nil {
+ log.Print(err)
+ return false
+ }
+ return v.Name == omitEmptyTag || v.HasOption(omitEmptyTag)
+}
+
func tagKeyName(tags *ast.BasicLit) string {
v, err := getGojayTagValue(tags)
if err != nil {