commit f5750264fb7b954483282400685ca5a75d6f5537
parent 1492d642246881248a5e9466fa81e3362d1067e7
Author: francoispqt <francois@parquet.ninja>
Date: Mon, 18 Jun 2018 21:21:03 +0800
refactor generator, add tests and tag handling
Diffstat:
21 files changed, 1210 insertions(+), 497 deletions(-)
diff --git a/.travis.yml b/.travis.yml
@@ -6,6 +6,7 @@ go:
script:
- go get github.com/stretchr/testify
+ - go test ./gojay -race
- go test -race -coverprofile=coverage.txt -covermode=atomic
after_success:
diff --git a/gojay/Makefile b/gojay/Makefile
@@ -1,3 +1,11 @@
.PHONY: build
build:
- go build ./
-\ No newline at end of file
+ go build ./
+
+.PHONY: test
+test:
+ go test -race .
+
+.PHONY: cover
+cover:
+ go test -tags test -coverprofile=profile.out
+\ No newline at end of file
diff --git a/gojay/gen.go b/gojay/gen.go
@@ -3,17 +3,20 @@ package main
import (
"go/ast"
"log"
- "os"
+ "strings"
"text/template"
)
+const gojayAnnotation = "//gojay:json"
const genFileSuffix = "_gojay.go"
var pkgTpl *template.Template
var gojayImport = []byte("import \"github.com/francoispqt/gojay\"\n")
-type gen struct {
- f *os.File
+type Gen struct {
+ b *strings.Builder
+ pkg string
+ src string
genTypes map[string]*ast.TypeSpec
vis *vis
}
@@ -44,8 +47,18 @@ func parseTemplates(tpls templateList, pfx string) {
}
}
-func (g *gen) writePkg(pkg string) error {
- err := pkgTpl.Execute(g.f, struct {
+// NewGen returns a new generator
+func NewGen(p string) *Gen {
+ g := &Gen{
+ src: p,
+ b: &strings.Builder{},
+ genTypes: make(map[string]*ast.TypeSpec),
+ }
+ return g
+}
+
+func (g *Gen) writePkg(pkg string) error {
+ err := pkgTpl.Execute(g.b, struct {
PkgName string
}{
PkgName: pkg,
@@ -56,17 +69,17 @@ func (g *gen) writePkg(pkg string) error {
return nil
}
-func (g *gen) writeGojayImport() error {
- _, err := g.f.Write(gojayImport)
+func (g *Gen) writeGojayImport() error {
+ _, err := g.b.Write(gojayImport)
if err != nil {
return err
}
return nil
}
-func (g *gen) gen(pkg string) error {
+func (g *Gen) Gen() error {
// write package
- err := g.writePkg(pkg)
+ err := g.writePkg(g.pkg)
if err != nil {
return err
}
@@ -79,16 +92,19 @@ func (g *gen) gen(pkg string) error {
// generate interfaces implementations based on type
for _, s := range g.genTypes {
switch t := s.Type.(type) {
+ // is struct
case *ast.StructType:
err = g.genStruct(s.Name.String(), t)
if err != nil {
return err
}
+ // is array
case *ast.ArrayType:
err = g.genArray(s.Name.String(), t)
if err != nil {
return err
}
+ // is map
case *ast.MapType:
// TODO: generate for map type
}
diff --git a/gojay/gen_array.go b/gojay/gen_array.go
@@ -4,7 +4,7 @@ import (
"go/ast"
)
-func (g *gen) genArray(n string, s *ast.ArrayType) error {
+func (g *Gen) genArray(n string, s *ast.ArrayType) error {
err := g.arrGenUnmarshal(n, s)
if err != nil {
return err
diff --git a/gojay/gen_array_marshal.go b/gojay/gen_array_marshal.go
@@ -7,8 +7,8 @@ import (
func init() {}
-func (g *gen) arrGenIsNil(n string) error {
- err := arrMarshalTpl["isNil"].tpl.Execute(g.f, struct {
+func (g *Gen) arrGenIsNil(n string) error {
+ err := arrMarshalTpl["isNil"].tpl.Execute(g.b, struct {
TypeName string
}{
TypeName: n,
@@ -16,8 +16,8 @@ func (g *gen) arrGenIsNil(n string) error {
return err
}
-func (g *gen) arrGenMarshal(n string, s *ast.ArrayType) error {
- err := arrMarshalTpl["def"].tpl.Execute(g.f, struct {
+func (g *Gen) arrGenMarshal(n string, s *ast.ArrayType) error {
+ err := arrMarshalTpl["def"].tpl.Execute(g.b, struct {
TypeName string
}{
TypeName: n,
@@ -43,14 +43,14 @@ func (g *gen) arrGenMarshal(n string, s *ast.ArrayType) error {
return errors.New("Unknown type")
}
}
- _, err = g.f.Write([]byte("}\n"))
+ _, err = g.b.Write([]byte("}\n"))
if err != nil {
return err
}
return err
}
-func (g *gen) arrGenMarshalIdent(i *ast.Ident, ptr bool) error {
+func (g *Gen) arrGenMarshalIdent(i *ast.Ident, ptr bool) error {
switch i.String() {
case "string":
return g.arrMarshalString(ptr)
@@ -76,7 +76,7 @@ func (g *gen) arrGenMarshalIdent(i *ast.Ident, ptr bool) error {
return g.arrMarshalUint("8", ptr)
default:
// if ident is already in our spec list
- if sp, ok := g.vis.specs[i.Name]; ok {
+ if sp, ok := g.genTypes[i.Name]; ok {
return g.arrMarshalNonPrim(sp, ptr)
} else if i.Obj != nil {
// else check the obj infos
@@ -91,7 +91,7 @@ func (g *gen) arrGenMarshalIdent(i *ast.Ident, ptr bool) error {
}
}
-func (g *gen) arrMarshalNonPrim(sp *ast.TypeSpec, ptr bool) error {
+func (g *Gen) arrMarshalNonPrim(sp *ast.TypeSpec, ptr bool) error {
switch sp.Type.(type) {
case *ast.StructType:
return g.arrMarshalStruct(sp, ptr)
@@ -101,16 +101,16 @@ func (g *gen) arrMarshalNonPrim(sp *ast.TypeSpec, ptr bool) error {
return nil
}
-func (g *gen) arrMarshalString(ptr bool) error {
+func (g *Gen) arrMarshalString(ptr bool) error {
if ptr {
- err := arrMarshalTpl["stringPtr"].tpl.Execute(g.f, struct {
+ err := arrMarshalTpl["stringPtr"].tpl.Execute(g.b, struct {
Ptr string
}{""})
if err != nil {
return err
}
} else {
- err := arrMarshalTpl["string"].tpl.Execute(g.f, struct {
+ err := arrMarshalTpl["string"].tpl.Execute(g.b, struct {
Ptr string
}{"&"})
if err != nil {
@@ -120,16 +120,16 @@ func (g *gen) arrMarshalString(ptr bool) error {
return nil
}
-func (g *gen) arrMarshalBool(ptr bool) error {
+func (g *Gen) arrMarshalBool(ptr bool) error {
if ptr {
- err := arrMarshalTpl["bool"].tpl.Execute(g.f, struct {
+ err := arrMarshalTpl["bool"].tpl.Execute(g.b, struct {
Ptr string
}{""})
if err != nil {
return err
}
} else {
- err := arrMarshalTpl["bool"].tpl.Execute(g.f, struct {
+ err := arrMarshalTpl["bool"].tpl.Execute(g.b, struct {
Ptr string
}{"&"})
if err != nil {
@@ -139,9 +139,9 @@ func (g *gen) arrMarshalBool(ptr bool) error {
return nil
}
-func (g *gen) arrMarshalInt(intLen string, ptr bool) error {
+func (g *Gen) arrMarshalInt(intLen string, ptr bool) error {
if ptr {
- err := arrMarshalTpl["int"].tpl.Execute(g.f, struct {
+ err := arrMarshalTpl["int"].tpl.Execute(g.b, struct {
IntLen string
Ptr string
}{intLen, ""})
@@ -149,7 +149,7 @@ func (g *gen) arrMarshalInt(intLen string, ptr bool) error {
return err
}
} else {
- err := arrMarshalTpl["int"].tpl.Execute(g.f, struct {
+ err := arrMarshalTpl["int"].tpl.Execute(g.b, struct {
IntLen string
Ptr string
}{intLen, "&"})
@@ -160,9 +160,9 @@ func (g *gen) arrMarshalInt(intLen string, ptr bool) error {
return nil
}
-func (g *gen) arrMarshalUint(intLen string, ptr bool) error {
+func (g *Gen) arrMarshalUint(intLen string, ptr bool) error {
if ptr {
- err := arrMarshalTpl["uint"].tpl.Execute(g.f, struct {
+ err := arrMarshalTpl["uint"].tpl.Execute(g.b, struct {
IntLen string
Ptr string
}{intLen, ""})
@@ -170,7 +170,7 @@ func (g *gen) arrMarshalUint(intLen string, ptr bool) error {
return err
}
} else {
- err := arrMarshalTpl["uint"].tpl.Execute(g.f, struct {
+ err := arrMarshalTpl["uint"].tpl.Execute(g.b, struct {
IntLen string
Ptr string
}{intLen, "&"})
@@ -181,16 +181,16 @@ func (g *gen) arrMarshalUint(intLen string, ptr bool) error {
return nil
}
-func (g *gen) arrMarshalStruct(st *ast.TypeSpec, ptr bool) error {
+func (g *Gen) arrMarshalStruct(st *ast.TypeSpec, ptr bool) error {
if ptr {
- err := arrMarshalTpl["structPtr"].tpl.Execute(g.f, struct {
+ err := arrMarshalTpl["structPtr"].tpl.Execute(g.b, struct {
StructName string
}{st.Name.String()})
if err != nil {
return err
}
} else {
- err := arrMarshalTpl["struct"].tpl.Execute(g.f, struct {
+ err := arrMarshalTpl["struct"].tpl.Execute(g.b, struct {
StructName string
}{st.Name.String()})
if err != nil {
@@ -200,16 +200,16 @@ func (g *gen) arrMarshalStruct(st *ast.TypeSpec, ptr bool) error {
return nil
}
-func (g *gen) arrMarshalArr(st *ast.TypeSpec, ptr bool) error {
+func (g *Gen) arrMarshalArr(st *ast.TypeSpec, ptr bool) error {
if ptr {
- err := arrMarshalTpl["arrPtr"].tpl.Execute(g.f, struct {
+ err := arrMarshalTpl["arrPtr"].tpl.Execute(g.b, struct {
StructName string
}{st.Name.String()})
if err != nil {
return err
}
} else {
- err := arrMarshalTpl["arr"].tpl.Execute(g.f, struct {
+ err := arrMarshalTpl["arr"].tpl.Execute(g.b, struct {
StructName string
}{st.Name.String()})
if err != nil {
diff --git a/gojay/gen_array_test.go b/gojay/gen_array_test.go
@@ -0,0 +1,366 @@
+package main
+
+import (
+ "io"
+ "strings"
+ "testing"
+
+ "github.com/stretchr/testify/assert"
+)
+
+func TestGenArray(t *testing.T) {
+ testCases := map[string]struct {
+ input io.Reader
+ expectedResult string
+ }{
+ "basicStringSlice": {
+ input: strings.NewReader(`package test
+
+//gojay:json
+type StrSlice []string
+ `),
+ expectedResult: `package
+
+import "github.com/francoispqt/gojay"
+
+// UnmarshalJSONArray implements gojay's UnmarshalerJSONArray
+func (v *StrSlice) UnmarshalJSONArray(dec *gojay.Decoder) error {
+ var str string
+ if err := dec.String(&str); err != nil {
+ return err
+ }
+ *v = append(*v, str)
+ return nil
+}
+
+// MarshalJSONArray implements gojay's MarshalerJSONArray
+func (v *StrSlice) MarshalJSONArray(enc *gojay.Encoder) {
+ for _, s := range *v {
+ enc.String(s)
+ }
+}
+
+// IsNil implements gojay's MarshalerJSONArray
+func (v *StrSlice) IsNil() bool {
+ return *v == nil || len(*v) == 0
+}
+`,
+ },
+ "basicStringBool": {
+ input: strings.NewReader(`package test
+
+//gojay:json
+type BoolSlice []bool
+ `),
+ expectedResult: `package
+
+import "github.com/francoispqt/gojay"
+
+// UnmarshalJSONArray implements gojay's UnmarshalerJSONArray
+func (v *BoolSlice) UnmarshalJSONArray(dec *gojay.Decoder) error {
+ var b bool
+ if err := dec.Bool(&b); err != nil {
+ return err
+ }
+ *v = append(*v, b)
+ return nil
+}
+
+// MarshalJSONArray implements gojay's MarshalerJSONArray
+func (v *BoolSlice) MarshalJSONArray(enc *gojay.Encoder) {
+ for _, s := range *v {
+ enc.Bool(s)
+ }
+}
+
+// IsNil implements gojay's MarshalerJSONArray
+func (v *BoolSlice) IsNil() bool {
+ return *v == nil || len(*v) == 0
+}
+`,
+ },
+ "basicIntSlice": {
+ input: strings.NewReader(`package test
+
+//gojay:json
+type IntSlice []int
+ `),
+ expectedResult: `package
+
+import "github.com/francoispqt/gojay"
+
+// UnmarshalJSONArray implements gojay's UnmarshalerJSONArray
+func (v *IntSlice) UnmarshalJSONArray(dec *gojay.Decoder) error {
+ var i int
+ if err := dec.Int(&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.Int(s)
+ }
+}
+
+// IsNil implements gojay's MarshalerJSONArray
+func (v *IntSlice) IsNil() bool {
+ return *v == nil || len(*v) == 0
+}
+`,
+ },
+ "basicInt8Slice": {
+ input: strings.NewReader(`package test
+
+ //gojay:json
+ type IntSlice []int8
+ `),
+ expectedResult: `package
+
+import "github.com/francoispqt/gojay"
+
+// UnmarshalJSONArray implements gojay's UnmarshalerJSONArray
+func (v *IntSlice) UnmarshalJSONArray(dec *gojay.Decoder) error {
+ var i int8
+ if err := dec.Int8(&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.Int8(s)
+ }
+}
+
+// IsNil implements gojay's MarshalerJSONArray
+func (v *IntSlice) IsNil() bool {
+ return *v == nil || len(*v) == 0
+}
+`,
+ },
+ "basicInt16Slice": {
+ input: strings.NewReader(`package test
+
+//gojay:json
+type IntSlice []int16
+ `),
+ expectedResult: `package
+
+import "github.com/francoispqt/gojay"
+
+// UnmarshalJSONArray implements gojay's UnmarshalerJSONArray
+func (v *IntSlice) UnmarshalJSONArray(dec *gojay.Decoder) error {
+ var i int16
+ if err := dec.Int16(&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.Int16(s)
+ }
+}
+
+// IsNil implements gojay's MarshalerJSONArray
+func (v *IntSlice) IsNil() bool {
+ return *v == nil || len(*v) == 0
+}
+`,
+ },
+ "basicInt32Slice": {
+ input: strings.NewReader(`package test
+
+ //gojay:json
+ type IntSlice []int32
+ `),
+ expectedResult: `package
+
+import "github.com/francoispqt/gojay"
+
+// UnmarshalJSONArray implements gojay's UnmarshalerJSONArray
+func (v *IntSlice) UnmarshalJSONArray(dec *gojay.Decoder) error {
+ var i int32
+ if err := dec.Int32(&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.Int32(s)
+ }
+}
+
+// IsNil implements gojay's MarshalerJSONArray
+func (v *IntSlice) IsNil() bool {
+ return *v == nil || len(*v) == 0
+}
+`,
+ },
+ "basicInt64Slice": {
+ input: strings.NewReader(`package test
+
+ //gojay:json
+ type IntSlice []int64
+ `),
+ expectedResult: `package
+
+import "github.com/francoispqt/gojay"
+
+// UnmarshalJSONArray implements gojay's UnmarshalerJSONArray
+func (v *IntSlice) UnmarshalJSONArray(dec *gojay.Decoder) error {
+ var i int64
+ if err := dec.Int64(&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.Int64(s)
+ }
+}
+
+// IsNil implements gojay's MarshalerJSONArray
+func (v *IntSlice) IsNil() bool {
+ return *v == nil || len(*v) == 0
+}
+`,
+ },
+ "basicUint64Slice": {
+ input: strings.NewReader(`package test
+
+ //gojay:json
+ type IntSlice []uint64
+ `),
+ expectedResult: `package
+
+import "github.com/francoispqt/gojay"
+
+// UnmarshalJSONArray implements gojay's UnmarshalerJSONArray
+func (v *IntSlice) UnmarshalJSONArray(dec *gojay.Decoder) error {
+ var i uint64
+ if err := dec.Uint64(&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.Uint64(s)
+ }
+}
+
+// IsNil implements gojay's MarshalerJSONArray
+func (v *IntSlice) IsNil() bool {
+ return *v == nil || len(*v) == 0
+}
+`,
+ },
+ "basicStructSlice": {
+ input: strings.NewReader(`package test
+
+//gojay:json
+type StructSlice []*Struct
+
+type Struct struct{
+ Str string
+}
+ `),
+ expectedResult: `package
+
+import "github.com/francoispqt/gojay"
+
+// UnmarshalJSONArray implements gojay's UnmarshalerJSONArray
+func (v *StructSlice) UnmarshalJSONArray(dec *gojay.Decoder) error {
+ var s = &Struct{}
+ if err := dec.Object(s); err != nil {
+ return err
+ }
+ *v = append(*v, s)
+ return nil
+}
+
+// MarshalJSONArray implements gojay's MarshalerJSONArray
+func (v *StructSlice) MarshalJSONArray(enc *gojay.Encoder) {
+ for _, s := range *v {
+ enc.Object(s)
+ }
+}
+
+// IsNil implements gojay's MarshalerJSONArray
+func (v *StructSlice) IsNil() bool {
+ return *v == nil || len(*v) == 0
+}
+`,
+ },
+ "basicSliceSlice": {
+ input: strings.NewReader(`package test
+
+//gojay:json
+type SliceStrSlice []StrSlice
+
+type StrSlice []string
+ `),
+ expectedResult: `package
+
+import "github.com/francoispqt/gojay"
+
+// UnmarshalJSONArray implements gojay's UnmarshalerJSONArray
+func (v *SliceStrSlice) UnmarshalJSONArray(dec *gojay.Decoder) error {
+ var s = make(StrSlice, 0)
+ if err := dec.Array(&s); err != nil {
+ return err
+ }
+ *v = append(*v, s)
+ return nil
+}
+
+// MarshalJSONArray implements gojay's MarshalerJSONArray
+func (v *SliceStrSlice) MarshalJSONArray(enc *gojay.Encoder) {
+ for _, s := range *v {
+ enc.Array(s)
+ }
+}
+
+// IsNil implements gojay's MarshalerJSONArray
+func (v *SliceStrSlice) IsNil() bool {
+ return *v == nil || len(*v) == 0
+}
+`,
+ },
+ }
+ for n, testCase := range testCases {
+ t.Run(n, func(t *testing.T) {
+ g, err := MakeGenFromReader(testCase.input)
+ if err != nil {
+ t.Fatal(err)
+ }
+ err = g.Gen()
+ if err != nil {
+ t.Fatal(err)
+ }
+ assert.Equal(t, testCase.expectedResult, g.b.String())
+ })
+ }
+}
diff --git a/gojay/gen_array_unmarshal.go b/gojay/gen_array_unmarshal.go
@@ -5,8 +5,8 @@ import (
"go/ast"
)
-func (g *gen) arrGenUnmarshal(n string, s *ast.ArrayType) error {
- err := arrUnmarshalTpl["def"].tpl.Execute(g.f, struct {
+func (g *Gen) arrGenUnmarshal(n string, s *ast.ArrayType) error {
+ err := arrUnmarshalTpl["def"].tpl.Execute(g.b, struct {
TypeName string
}{
TypeName: n,
@@ -32,14 +32,14 @@ func (g *gen) arrGenUnmarshal(n string, s *ast.ArrayType) error {
return errors.New("Unknown type")
}
}
- _, err = g.f.Write(structUnmarshalClose)
+ _, err = g.b.Write(structUnmarshalClose)
if err != nil {
return err
}
return err
}
-func (g *gen) arrGenUnmarshalIdent(i *ast.Ident, ptr bool) error {
+func (g *Gen) arrGenUnmarshalIdent(i *ast.Ident, ptr bool) error {
switch i.String() {
case "string":
return g.arrUnmarshalString(ptr)
@@ -65,7 +65,7 @@ func (g *gen) arrGenUnmarshalIdent(i *ast.Ident, ptr bool) error {
return g.arrUnmarshalUint("8", ptr)
default:
// if ident is already in our spec list
- if sp, ok := g.vis.specs[i.Name]; ok {
+ if sp, ok := g.genTypes[i.Name]; ok {
return g.arrUnmarshalNonPrim(sp, ptr)
} else if i.Obj != nil {
// else check the obj infos
@@ -80,7 +80,7 @@ func (g *gen) arrGenUnmarshalIdent(i *ast.Ident, ptr bool) error {
}
}
-func (g *gen) arrUnmarshalNonPrim(sp *ast.TypeSpec, ptr bool) error {
+func (g *Gen) arrUnmarshalNonPrim(sp *ast.TypeSpec, ptr bool) error {
switch sp.Type.(type) {
case *ast.StructType:
return g.arrUnmarshalStruct(sp, ptr)
@@ -90,16 +90,16 @@ func (g *gen) arrUnmarshalNonPrim(sp *ast.TypeSpec, ptr bool) error {
return nil
}
-func (g *gen) arrUnmarshalString(ptr bool) error {
+func (g *Gen) arrUnmarshalString(ptr bool) error {
if ptr {
- err := arrUnmarshalTpl["stringPtr"].tpl.Execute(g.f, struct {
+ err := arrUnmarshalTpl["stringPtr"].tpl.Execute(g.b, struct {
Ptr string
}{""})
if err != nil {
return err
}
} else {
- err := arrUnmarshalTpl["string"].tpl.Execute(g.f, struct {
+ err := arrUnmarshalTpl["string"].tpl.Execute(g.b, struct {
Ptr string
}{"&"})
if err != nil {
@@ -109,16 +109,16 @@ func (g *gen) arrUnmarshalString(ptr bool) error {
return nil
}
-func (g *gen) arrUnmarshalBool(ptr bool) error {
+func (g *Gen) arrUnmarshalBool(ptr bool) error {
if ptr {
- err := arrUnmarshalTpl["bool"].tpl.Execute(g.f, struct {
+ err := arrUnmarshalTpl["bool"].tpl.Execute(g.b, struct {
Ptr string
}{""})
if err != nil {
return err
}
} else {
- err := arrUnmarshalTpl["bool"].tpl.Execute(g.f, struct {
+ err := arrUnmarshalTpl["bool"].tpl.Execute(g.b, struct {
Ptr string
}{"&"})
if err != nil {
@@ -128,9 +128,9 @@ func (g *gen) arrUnmarshalBool(ptr bool) error {
return nil
}
-func (g *gen) arrUnmarshalInt(intLen string, ptr bool) error {
+func (g *Gen) arrUnmarshalInt(intLen string, ptr bool) error {
if ptr {
- err := arrUnmarshalTpl["int"].tpl.Execute(g.f, struct {
+ err := arrUnmarshalTpl["int"].tpl.Execute(g.b, struct {
IntLen string
Ptr string
}{intLen, ""})
@@ -138,7 +138,7 @@ func (g *gen) arrUnmarshalInt(intLen string, ptr bool) error {
return err
}
} else {
- err := arrUnmarshalTpl["int"].tpl.Execute(g.f, struct {
+ err := arrUnmarshalTpl["int"].tpl.Execute(g.b, struct {
IntLen string
Ptr string
}{intLen, "&"})
@@ -149,9 +149,9 @@ func (g *gen) arrUnmarshalInt(intLen string, ptr bool) error {
return nil
}
-func (g *gen) arrUnmarshalUint(intLen string, ptr bool) error {
+func (g *Gen) arrUnmarshalUint(intLen string, ptr bool) error {
if ptr {
- err := arrUnmarshalTpl["uint"].tpl.Execute(g.f, struct {
+ err := arrUnmarshalTpl["uint"].tpl.Execute(g.b, struct {
IntLen string
Ptr string
}{intLen, ""})
@@ -159,7 +159,7 @@ func (g *gen) arrUnmarshalUint(intLen string, ptr bool) error {
return err
}
} else {
- err := arrUnmarshalTpl["uint"].tpl.Execute(g.f, struct {
+ err := arrUnmarshalTpl["uint"].tpl.Execute(g.b, struct {
IntLen string
Ptr string
}{intLen, "&"})
@@ -170,16 +170,16 @@ func (g *gen) arrUnmarshalUint(intLen string, ptr bool) error {
return nil
}
-func (g *gen) arrUnmarshalStruct(st *ast.TypeSpec, ptr bool) error {
+func (g *Gen) arrUnmarshalStruct(st *ast.TypeSpec, ptr bool) error {
if ptr {
- err := arrUnmarshalTpl["structPtr"].tpl.Execute(g.f, struct {
+ err := arrUnmarshalTpl["structPtr"].tpl.Execute(g.b, struct {
StructName string
}{st.Name.String()})
if err != nil {
return err
}
} else {
- err := arrUnmarshalTpl["struct"].tpl.Execute(g.f, struct {
+ err := arrUnmarshalTpl["struct"].tpl.Execute(g.b, struct {
StructName string
}{st.Name.String()})
if err != nil {
@@ -189,16 +189,16 @@ func (g *gen) arrUnmarshalStruct(st *ast.TypeSpec, ptr bool) error {
return nil
}
-func (g *gen) arrUnmarshalArr(st *ast.TypeSpec, ptr bool) error {
+func (g *Gen) arrUnmarshalArr(st *ast.TypeSpec, ptr bool) error {
if ptr {
- err := arrUnmarshalTpl["arrPtr"].tpl.Execute(g.f, struct {
+ err := arrUnmarshalTpl["arrPtr"].tpl.Execute(g.b, struct {
StructName string
}{st.Name.String()})
if err != nil {
return err
}
} else {
- err := arrUnmarshalTpl["arr"].tpl.Execute(g.f, struct {
+ err := arrUnmarshalTpl["arr"].tpl.Execute(g.b, struct {
StructName string
}{st.Name.String()})
if err != nil {
diff --git a/gojay/gen_parse.go b/gojay/gen_parse.go
@@ -0,0 +1,63 @@
+//+build !test
+
+package main
+
+import (
+ "go/ast"
+ "go/parser"
+ "go/token"
+ "os"
+)
+
+func (g *Gen) parse() error {
+ var f, err = os.Stat(g.src)
+ if err != nil {
+ return err
+ }
+ if f.IsDir() {
+ err = g.parseDir()
+ } else {
+ err = g.parseFile()
+ }
+ return err
+}
+
+func (g *Gen) parseDir() error {
+ // parse the given path
+ fset := token.NewFileSet()
+ pkgs, err := parser.ParseDir(fset, g.src, nil, parser.ParseComments)
+ if err != nil {
+ return err
+ }
+ // range across packages
+ for pkgName, pkg := range pkgs {
+ v := NewVisitor(g, pkgName)
+ g.pkg = pkgName
+ // range on files in package
+ for _, f := range pkg.Files {
+ ast.Walk(v, f)
+ if err != nil {
+ return err
+ }
+ }
+ g.vis = v
+ }
+ return nil
+}
+
+func (g *Gen) parseFile() error {
+ // parse the given path
+ fset := token.NewFileSet()
+ f, err := parser.ParseFile(fset, g.src, nil, parser.ParseComments)
+ if err != nil {
+ return err
+ }
+ g.pkg = f.Name.Name
+ v := NewVisitor(g, g.pkg)
+ ast.Walk(v, f)
+ if err != nil {
+ return err
+ }
+ g.vis = v
+ return nil
+}
diff --git a/gojay/gen_struct_marshal.go b/gojay/gen_struct_marshal.go
@@ -3,11 +3,10 @@ package main
import (
"errors"
"go/ast"
- "strings"
)
-func (g *gen) structGenIsNil(n string) error {
- err := structMarshalTpl["isNil"].tpl.Execute(g.f, struct {
+func (g *Gen) structGenIsNil(n string) error {
+ err := structMarshalTpl["isNil"].tpl.Execute(g.b, struct {
StructName string
}{
StructName: n,
@@ -15,8 +14,8 @@ func (g *gen) structGenIsNil(n string) error {
return err
}
-func (g *gen) structGenMarshalObj(n string, s *ast.StructType) (int, error) {
- err := structMarshalTpl["def"].tpl.Execute(g.f, struct {
+func (g *Gen) structGenMarshalObj(n string, s *ast.StructType) (int, error) {
+ err := structMarshalTpl["def"].tpl.Execute(g.b, struct {
StructName string
}{
StructName: n,
@@ -28,6 +27,10 @@ func (g *gen) structGenMarshalObj(n string, s *ast.StructType) (int, error) {
if len(s.Fields.List) > 0 {
// TODO: check tags
for _, field := range s.Fields.List {
+ // check if has hide tag
+ if field.Tag != nil && hasTagMarshalHide(field.Tag) {
+ continue
+ }
switch t := field.Type.(type) {
case *ast.Ident:
var err error
@@ -49,85 +52,93 @@ func (g *gen) structGenMarshalObj(n string, s *ast.StructType) (int, error) {
}
}
}
- _, err = g.f.Write([]byte("}\n"))
+ _, err = g.b.Write([]byte("}\n"))
if err != nil {
return 0, err
}
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, ptr bool) (int, error) {
+ var keyV = getStructFieldJSONKey(field)
+
switch i.String() {
case "string":
- var err = g.structMarshalString(field, ptr)
+ var err = g.structMarshalString(field, keyV, ptr)
if err != nil {
return 0, err
}
keys++
case "bool":
- var err = g.structMarshalBool(field, ptr)
+ var err = g.structMarshalBool(field, keyV, ptr)
if err != nil {
return 0, err
}
keys++
case "int":
- var err = g.structMarshalInt(field, "", ptr)
+ var err = g.structMarshalInt(field, keyV, "", ptr)
if err != nil {
return 0, err
}
keys++
case "int64":
- var err = g.structMarshalInt(field, "64", ptr)
+ var err = g.structMarshalInt(field, keyV, "64", ptr)
if err != nil {
return 0, err
}
keys++
case "int32":
- var err = g.structMarshalInt(field, "32", ptr)
+ var err = g.structMarshalInt(field, keyV, "32", ptr)
if err != nil {
return 0, err
}
keys++
case "int16":
- var err = g.structMarshalInt(field, "16", ptr)
+ var err = g.structMarshalInt(field, keyV, "16", ptr)
if err != nil {
return 0, err
}
keys++
case "int8":
- var err = g.structMarshalInt(field, "8", ptr)
+ var err = g.structMarshalInt(field, keyV, "8", ptr)
if err != nil {
return 0, err
}
keys++
case "uint64":
- var err = g.structMarshalUint(field, "64", ptr)
+ var err = g.structMarshalUint(field, keyV, "64", ptr)
if err != nil {
return 0, err
}
keys++
case "uint32":
- var err = g.structMarshalUint(field, "32", ptr)
+ var err = g.structMarshalUint(field, keyV, "32", ptr)
if err != nil {
return 0, err
}
keys++
case "uint16":
- var err = g.structMarshalUint(field, "16", ptr)
+ var err = g.structMarshalUint(field, keyV, "16", ptr)
if err != nil {
return 0, err
}
keys++
case "uint8":
- var err = g.structMarshalUint(field, "8", ptr)
+ var err = g.structMarshalUint(field, keyV, "8", ptr)
+ if err != nil {
+ return 0, err
+ }
+ keys++
+ case "float64":
+ var err = g.structMarshalFloat(field, keyV, "", ptr)
if err != nil {
return 0, err
}
keys++
default:
// if ident is already in our spec list
- if sp, ok := g.vis.specs[i.Name]; ok {
- err := g.structMarshalNonPrim(field, sp, ptr)
+ if sp, ok := g.genTypes[i.Name]; ok {
+ err := g.structMarshalNonPrim(field, keyV, sp, ptr)
if err != nil {
return 0, err
}
@@ -135,7 +146,7 @@ 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, t, ptr)
+ var err = g.structMarshalNonPrim(field, keyV, t, ptr)
if err != nil {
return 0, err
}
@@ -150,114 +161,132 @@ func (g *gen) structGenMarshalIdent(field *ast.Field, i *ast.Ident, keys int, pt
return keys, nil
}
-func (g *gen) structMarshalNonPrim(field *ast.Field, sp *ast.TypeSpec, ptr bool) error {
+func (g *Gen) structMarshalNonPrim(field *ast.Field, keyV string, sp *ast.TypeSpec, ptr bool) error {
switch sp.Type.(type) {
case *ast.StructType:
- return g.structMarshalStruct(field, sp, ptr)
+ return g.structMarshalStruct(field, keyV, sp, ptr)
case *ast.ArrayType:
- return g.structMarshalArr(field, sp, ptr)
+ return g.structMarshalArr(field, keyV, sp, ptr)
}
return nil
}
-func (g *gen) structMarshalString(field *ast.Field, ptr bool) error {
+func (g *Gen) structMarshalString(field *ast.Field, keyV string, ptr bool) error {
key := field.Names[0].String()
ptrStr := ""
if ptr {
ptrStr = "*"
}
- err := structMarshalTpl["string"].tpl.Execute(g.f, struct {
+ err := structMarshalTpl["string"].tpl.Execute(g.b, struct {
Field string
Key string
Ptr string
- }{key, strings.ToLower(key), ptrStr})
+ }{key, keyV, ptrStr})
if err != nil {
return err
}
return nil
}
-func (g *gen) structMarshalBool(field *ast.Field, ptr bool) error {
+func (g *Gen) structMarshalBool(field *ast.Field, keyV string, ptr bool) error {
key := field.Names[0].String()
ptrStr := ""
if ptr {
ptrStr = "*"
}
- err := structMarshalTpl["bool"].tpl.Execute(g.f, struct {
+ err := structMarshalTpl["bool"].tpl.Execute(g.b, struct {
Field string
Key string
Ptr string
- }{key, strings.ToLower(key), ptrStr})
+ }{key, keyV, ptrStr})
+ if err != nil {
+ return err
+ }
+ return nil
+}
+
+func (g *Gen) structMarshalInt(field *ast.Field, keyV string, intLen string, ptr bool) error {
+ 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})
if err != nil {
return err
}
return nil
}
-func (g *gen) structMarshalInt(field *ast.Field, intLen string, ptr bool) error {
+func (g *Gen) structMarshalUint(field *ast.Field, keyV string, intLen string, ptr bool) error {
key := field.Names[0].String()
ptrStr := ""
if ptr {
ptrStr = "*"
}
- err := structMarshalTpl["int"].tpl.Execute(g.f, struct {
+ err := structMarshalTpl["uint"].tpl.Execute(g.b, struct {
Field string
IntLen string
Key string
Ptr string
- }{key, intLen, strings.ToLower(key), ptrStr})
+ }{key, intLen, keyV, ptrStr})
if err != nil {
return err
}
return nil
}
-func (g *gen) structMarshalUint(field *ast.Field, intLen string, ptr bool) error {
+func (g *Gen) structMarshalFloat(field *ast.Field, keyV string, intLen string, ptr bool) error {
key := field.Names[0].String()
ptrStr := ""
if ptr {
ptrStr = "*"
}
- err := structMarshalTpl["uint"].tpl.Execute(g.f, struct {
+ err := structMarshalTpl["float"].tpl.Execute(g.b, struct {
Field string
IntLen string
Key string
Ptr string
- }{key, intLen, strings.ToLower(key), ptrStr})
+ }{key, intLen, keyV, ptrStr})
if err != nil {
return err
}
return nil
}
-func (g *gen) structMarshalStruct(field *ast.Field, st *ast.TypeSpec, ptr bool) error {
+func (g *Gen) structMarshalStruct(field *ast.Field, keyV string, st *ast.TypeSpec, ptr bool) error {
key := field.Names[0].String()
ptrStr := ""
if ptr {
ptrStr = "*"
}
- var err = structMarshalTpl["struct"].tpl.Execute(g.f, struct {
+ var err = structMarshalTpl["struct"].tpl.Execute(g.b, struct {
Key string
Field string
Ptr string
- }{strings.ToLower(key), key, ptrStr})
+ }{keyV, key, ptrStr})
if err != nil {
return err
}
return nil
}
-func (g *gen) structMarshalArr(field *ast.Field, st *ast.TypeSpec, ptr bool) error {
+func (g *Gen) structMarshalArr(field *ast.Field, keyV string, st *ast.TypeSpec, ptr bool) error {
key := field.Names[0].String()
ptrStr := ""
if ptr {
ptrStr = "*"
}
- var err = structMarshalTpl["arr"].tpl.Execute(g.f, struct {
+ var err = structMarshalTpl["arr"].tpl.Execute(g.b, struct {
Key string
Field string
Ptr string
- }{strings.ToLower(key), key, ptrStr})
+ }{keyV, key, ptrStr})
if err != nil {
return err
}
diff --git a/gojay/gen_struct_marshal_tpl.go b/gojay/gen_struct_marshal_tpl.go
@@ -20,6 +20,9 @@ func (v *{{.StructName}}) IsNil() bool { return v == nil }
"uint": &genTpl{
strTpl: "\tenc.Uint{{.IntLen}}Key(\"{{.Key}}\", {{.Ptr}}v.{{.Field}})\n",
},
+ "float": &genTpl{
+ strTpl: "\tenc.Float{{.IntLen}}Key(\"{{.Key}}\", {{.Ptr}}v.{{.Field}})\n",
+ },
"bool": &genTpl{
strTpl: "\tenc.BoolKey(\"{{.Key}}\", {{.Ptr}}v.{{.Field}})\n",
},
diff --git a/gojay/gen_struct_test.go b/gojay/gen_struct_test.go
@@ -0,0 +1,373 @@
+package main
+
+import (
+ "io"
+ "strings"
+ "testing"
+
+ "github.com/stretchr/testify/assert"
+)
+
+func TestGenStruct(t *testing.T) {
+ testCases := map[string]struct {
+ input io.Reader
+ expectedResult string
+ }{
+ "basicStruct": {
+ input: strings.NewReader(`package test
+
+//gojay:json
+type Struct struct{
+ Int int
+ Int8 int8
+ Int16 int16
+ Int32 int32
+ Int64 int64
+ Uint64 uint64
+ Float float64
+ Str string
+ Bool bool
+}
+ `),
+ 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 "int":
+ return dec.Int(&v.Int)
+ case "int8":
+ return dec.Int8(&v.Int8)
+ case "int16":
+ return dec.Int16(&v.Int16)
+ case "int32":
+ return dec.Int32(&v.Int32)
+ case "int64":
+ return dec.Int64(&v.Int64)
+ case "uint64":
+ return dec.Uint64(&v.Uint64)
+ case "float":
+ return dec.Float(&v.Float)
+ case "str":
+ return dec.String(&v.Str)
+ case "bool":
+ return dec.Bool(&v.Bool)
+ }
+ return nil
+}
+
+// NKeys returns the number of keys to unmarshal
+func (v *Struct) NKeys() int { return 9 }
+
+// MarshalJSONObject implements gojay's MarshalerJSONObject
+func (v *Struct) MarshalJSONObject(enc *gojay.Encoder) {
+ enc.IntKey("int", v.Int)
+ enc.Int8Key("int8", v.Int8)
+ enc.Int16Key("int16", v.Int16)
+ enc.Int32Key("int32", v.Int32)
+ enc.Int64Key("int64", v.Int64)
+ enc.Uint64Key("uint64", v.Uint64)
+ enc.FloatKey("float", v.Float)
+ enc.StringKey("str", v.Str)
+ enc.BoolKey("bool", v.Bool)
+}
+
+// IsNil returns wether the structure is nil value or not
+func (v *Struct) IsNil() bool { return v == nil }
+`,
+ },
+ "basicStructPtr": {
+ input: strings.NewReader(`package test
+
+//gojay:json
+type Struct struct{
+ Int *int
+ Str *string
+}
+ `),
+ 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 "int":
+ return dec.Int(v.Int)
+ case "str":
+ return dec.String(v.Str)
+ }
+ return nil
+}
+
+// NKeys returns the number of keys to unmarshal
+func (v *Struct) NKeys() int { return 2 }
+
+// MarshalJSONObject implements gojay's MarshalerJSONObject
+func (v *Struct) MarshalJSONObject(enc *gojay.Encoder) {
+ enc.IntKey("int", *v.Int)
+ enc.StringKey("str", *v.Str)
+}
+
+// IsNil returns wether the structure is nil value or not
+func (v *Struct) IsNil() bool { return v == nil }
+`,
+ },
+ "basicStructTags": {
+ input: strings.NewReader(`package test
+
+//gojay:json
+type Struct struct{
+ Int int ` + "`gojay:\"someInt\"`" + `
+ Str string ` + "`gojay:\"someStr\"`" + `
+}
+ `),
+ 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 "someInt":
+ return dec.Int(&v.Int)
+ case "someStr":
+ return dec.String(&v.Str)
+ }
+ return nil
+}
+
+// NKeys returns the number of keys to unmarshal
+func (v *Struct) NKeys() int { return 2 }
+
+// MarshalJSONObject implements gojay's MarshalerJSONObject
+func (v *Struct) MarshalJSONObject(enc *gojay.Encoder) {
+ enc.IntKey("someInt", v.Int)
+ enc.StringKey("someStr", v.Str)
+}
+
+// IsNil returns wether the structure is nil value or not
+func (v *Struct) IsNil() bool { return v == nil }
+`,
+ },
+ "basicStructTagsHideUnmarshal": {
+ input: strings.NewReader(`package test
+
+//gojay:json
+type Struct struct{
+ Int int ` + "`gojay:\"-u\"`" + `
+ Str string ` + "`gojay:\"-u\"`" + `
+}
+ `),
+ expectedResult: `package
+
+import "github.com/francoispqt/gojay"
+
+// UnmarshalJSONObject implements gojay's UnmarshalerJSONObject
+func (v *Struct) UnmarshalJSONObject(dec *gojay.Decoder, k string) error {
+ switch k {
+ }
+ return nil
+}
+
+// NKeys returns the number of keys to unmarshal
+func (v *Struct) NKeys() int { return 0 }
+
+// MarshalJSONObject implements gojay's MarshalerJSONObject
+func (v *Struct) MarshalJSONObject(enc *gojay.Encoder) {
+ enc.IntKey("int", v.Int)
+ enc.StringKey("str", v.Str)
+}
+
+// IsNil returns wether the structure is nil value or not
+func (v *Struct) IsNil() bool { return v == nil }
+`,
+ },
+ "basicStructTagsHideUnmarshal2": {
+ input: strings.NewReader(`package test
+
+//gojay:json
+type Struct struct{
+ Int int ` + "`gojay:\"someInt,-u\"`" + `
+ Str string ` + "`gojay:\"someStr,-u\"`" + `
+}
+ `),
+ expectedResult: `package
+
+import "github.com/francoispqt/gojay"
+
+// UnmarshalJSONObject implements gojay's UnmarshalerJSONObject
+func (v *Struct) UnmarshalJSONObject(dec *gojay.Decoder, k string) error {
+ switch k {
+ }
+ return nil
+}
+
+// NKeys returns the number of keys to unmarshal
+func (v *Struct) NKeys() int { return 0 }
+
+// MarshalJSONObject implements gojay's MarshalerJSONObject
+func (v *Struct) MarshalJSONObject(enc *gojay.Encoder) {
+ enc.IntKey("someInt", v.Int)
+ enc.StringKey("someStr", v.Str)
+}
+
+// IsNil returns wether the structure is nil value or not
+func (v *Struct) IsNil() bool { return v == nil }
+`,
+ },
+ "basicStructTagsHideUnmarshal3": {
+ input: strings.NewReader(`package test
+
+//gojay:json
+type Struct struct{
+ Int int ` + "`gojay:\"someInt,-m\"`" + `
+ Str string ` + "`gojay:\"someStr,-m\"`" + `
+}
+ `),
+ 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 "someInt":
+ return dec.Int(&v.Int)
+ case "someStr":
+ return dec.String(&v.Str)
+ }
+ return nil
+}
+
+// NKeys returns the number of keys to unmarshal
+func (v *Struct) NKeys() int { return 2 }
+
+// MarshalJSONObject implements gojay's MarshalerJSONObject
+func (v *Struct) MarshalJSONObject(enc *gojay.Encoder) {
+}
+
+// IsNil returns wether the structure is nil value or not
+func (v *Struct) IsNil() bool { return v == nil }
+`,
+ },
+ "basicStructTagsHideUnmarshal4": {
+ input: strings.NewReader(`package test
+
+//gojay:json
+type Struct struct{
+ Int int ` + "`gojay:\"-\"`" + `
+ Str string ` + "`gojay:\"-\"`" + `
+}
+ `),
+ expectedResult: `package
+
+import "github.com/francoispqt/gojay"
+
+// UnmarshalJSONObject implements gojay's UnmarshalerJSONObject
+func (v *Struct) UnmarshalJSONObject(dec *gojay.Decoder, k string) error {
+ switch k {
+ }
+ return nil
+}
+
+// NKeys returns the number of keys to unmarshal
+func (v *Struct) NKeys() int { return 0 }
+
+// MarshalJSONObject implements gojay's MarshalerJSONObject
+func (v *Struct) MarshalJSONObject(enc *gojay.Encoder) {
+}
+
+// IsNil returns wether the structure is nil value or not
+func (v *Struct) IsNil() bool { return v == nil }
+`,
+ },
+ "complexStructStructTag": {
+ input: strings.NewReader(`package test
+
+//gojay:json
+type Struct struct{
+ Struct Struct ` + "`gojay:\"someStruct\"`" + `
+}
+ `),
+ 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.ObjectKey("someStruct", v.Struct)
+}
+
+// IsNil returns wether the structure is nil value or not
+func (v *Struct) IsNil() bool { return v == nil }
+`,
+ },
+ "complexStructStructPtrTag": {
+ input: strings.NewReader(`package test
+
+//gojay:json
+type Struct struct{
+ Struct *Struct ` + "`gojay:\"someStruct\"`" + `
+}
+ `),
+ 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.ObjectKey("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) {
+ g, err := MakeGenFromReader(testCase.input)
+ if err != nil {
+ t.Fatal(err)
+ }
+ err = g.Gen()
+ if err != nil {
+ t.Fatal(err)
+ }
+ assert.Equal(t, testCase.expectedResult, g.b.String())
+ })
+ }
+}
diff --git a/gojay/gen_struct_unmarshal.go b/gojay/gen_struct_unmarshal.go
@@ -3,14 +3,13 @@ package main
import (
"errors"
"go/ast"
- "strings"
)
var structUnmarshalSwitchOpen = []byte("\tswitch k {\n")
var structUnmarshalClose = []byte("\treturn nil\n}\n")
-func (g *gen) structGenNKeys(n string, count int) error {
- err := structUnmarshalTpl["nKeys"].tpl.Execute(g.f, struct {
+func (g *Gen) structGenNKeys(n string, count int) error {
+ err := structUnmarshalTpl["nKeys"].tpl.Execute(g.b, struct {
NKeys int
StructName string
}{
@@ -20,8 +19,8 @@ func (g *gen) structGenNKeys(n string, count int) error {
return err
}
-func (g *gen) structGenUnmarshalObj(n string, s *ast.StructType) (int, error) {
- err := structUnmarshalTpl["def"].tpl.Execute(g.f, struct {
+func (g *Gen) structGenUnmarshalObj(n string, s *ast.StructType) (int, error) {
+ err := structUnmarshalTpl["def"].tpl.Execute(g.b, struct {
StructName string
}{
StructName: n,
@@ -32,10 +31,15 @@ func (g *gen) structGenUnmarshalObj(n string, s *ast.StructType) (int, error) {
keys := 0
if len(s.Fields.List) > 0 {
// open switch statement
- g.f.Write(structUnmarshalSwitchOpen)
-
+ g.b.Write(structUnmarshalSwitchOpen)
// TODO: check tags
+ // check type of field
+ // add accordingly
for _, field := range s.Fields.List {
+ // check if has hide tag
+ if field.Tag != nil && hasTagUnmarshalHide(field.Tag) {
+ continue
+ }
switch t := field.Type.(type) {
case *ast.Ident:
var err error
@@ -52,92 +56,100 @@ func (g *gen) structGenUnmarshalObj(n string, s *ast.StructType) (int, error) {
return 0, err
}
default:
- return 0, errors.New("Unknown type1")
+ return 0, errors.New("Unknown type")
}
}
}
// close switch statement
- g.f.Write([]byte("\t}\n"))
+ g.b.Write([]byte("\t}\n"))
}
- _, err = g.f.Write(structUnmarshalClose)
+ _, err = g.b.Write(structUnmarshalClose)
if err != nil {
return 0, err
}
return keys, nil
}
-func (g *gen) structGenUnmarshalIdent(field *ast.Field, i *ast.Ident, keys int, ptr bool) (int, error) {
+func (g *Gen) structGenUnmarshalIdent(field *ast.Field, i *ast.Ident, keys int, ptr bool) (int, error) {
+ var keyV = getStructFieldJSONKey(field)
+
switch i.String() {
case "string":
- var err = g.structUnmarshalString(field, ptr)
+ var err = g.structUnmarshalString(field, keyV, ptr)
if err != nil {
return 0, err
}
keys++
case "bool":
- var err = g.structUnmarshalBool(field, ptr)
+ var err = g.structUnmarshalBool(field, keyV, ptr)
if err != nil {
return 0, err
}
keys++
case "int":
- var err = g.structUnmarshalInt(field, "", ptr)
+ var err = g.structUnmarshalInt(field, keyV, "", ptr)
if err != nil {
return 0, err
}
keys++
case "int64":
- var err = g.structUnmarshalInt(field, "64", ptr)
+ var err = g.structUnmarshalInt(field, keyV, "64", ptr)
if err != nil {
return 0, err
}
keys++
case "int32":
- var err = g.structUnmarshalInt(field, "32", ptr)
+ var err = g.structUnmarshalInt(field, keyV, "32", ptr)
if err != nil {
return 0, err
}
keys++
case "int16":
- var err = g.structUnmarshalInt(field, "16", ptr)
+ var err = g.structUnmarshalInt(field, keyV, "16", ptr)
if err != nil {
return 0, err
}
keys++
case "int8":
- var err = g.structUnmarshalInt(field, "8", ptr)
+ var err = g.structUnmarshalInt(field, keyV, "8", ptr)
if err != nil {
return 0, err
}
keys++
case "uint64":
- var err = g.structUnmarshalUint(field, "64", ptr)
+ var err = g.structUnmarshalUint(field, keyV, "64", ptr)
if err != nil {
return 0, err
}
keys++
case "uint32":
- var err = g.structUnmarshalUint(field, "32", ptr)
+ var err = g.structUnmarshalUint(field, keyV, "32", ptr)
if err != nil {
return 0, err
}
keys++
case "uint16":
- var err = g.structUnmarshalUint(field, "16", ptr)
+ var err = g.structUnmarshalUint(field, keyV, "16", ptr)
if err != nil {
return 0, err
}
keys++
case "uint8":
- var err = g.structUnmarshalUint(field, "8", ptr)
+ var err = g.structUnmarshalUint(field, keyV, "8", ptr)
+ if err != nil {
+ return 0, err
+ }
+ keys++
+ case "float64":
+ var err = g.structUnmarshalFloat(field, keyV, "", ptr)
if err != nil {
return 0, err
}
keys++
default:
// if ident is already in our spec list
- if sp, ok := g.vis.specs[i.Name]; ok {
- err := g.structUnmarshalNonPrim(field, sp, ptr)
+ if sp, ok := g.genTypes[i.Name]; ok {
+ err := g.structUnmarshalNonPrim(field, keyV, sp, ptr)
if err != nil {
return 0, err
}
@@ -146,7 +158,7 @@ func (g *gen) structGenUnmarshalIdent(field *ast.Field, i *ast.Ident, keys int,
// else check the obj infos
switch t := i.Obj.Decl.(type) {
case *ast.TypeSpec:
- err := g.structUnmarshalNonPrim(field, t, ptr)
+ err := g.structUnmarshalNonPrim(field, keyV, t, ptr)
if err != nil {
return 0, err
}
@@ -161,26 +173,26 @@ func (g *gen) structGenUnmarshalIdent(field *ast.Field, i *ast.Ident, keys int,
return keys, nil
}
-func (g *gen) structUnmarshalNonPrim(field *ast.Field, sp *ast.TypeSpec, ptr bool) error {
+func (g *Gen) structUnmarshalNonPrim(field *ast.Field, keyV string, sp *ast.TypeSpec, ptr bool) error {
switch sp.Type.(type) {
case *ast.StructType:
- return g.structUnmarshalStruct(field, sp, ptr)
+ return g.structUnmarshalStruct(field, keyV, sp, ptr)
case *ast.ArrayType:
- return g.structUnmarshalArr(field, sp, ptr)
+ return g.structUnmarshalArr(field, keyV, sp, ptr)
}
return errors.New("Unknown type")
}
-func (g *gen) structUnmarshalString(field *ast.Field, ptr bool) error {
+func (g *Gen) structUnmarshalString(field *ast.Field, keyV string, ptr bool) error {
key := field.Names[0].String()
- err := structUnmarshalTpl["case"].tpl.Execute(g.f, struct {
+ err := structUnmarshalTpl["case"].tpl.Execute(g.b, struct {
Key string
- }{strings.ToLower(key)})
+ }{keyV})
if err != nil {
return err
}
if ptr {
- err = structUnmarshalTpl["string"].tpl.Execute(g.f, struct {
+ err = structUnmarshalTpl["string"].tpl.Execute(g.b, struct {
Field string
Ptr string
}{key, ""})
@@ -188,7 +200,7 @@ func (g *gen) structUnmarshalString(field *ast.Field, ptr bool) error {
return err
}
} else {
- err = structUnmarshalTpl["string"].tpl.Execute(g.f, struct {
+ err = structUnmarshalTpl["string"].tpl.Execute(g.b, struct {
Field string
Ptr string
}{key, "&"})
@@ -199,16 +211,16 @@ func (g *gen) structUnmarshalString(field *ast.Field, ptr bool) error {
return nil
}
-func (g *gen) structUnmarshalBool(field *ast.Field, ptr bool) error {
+func (g *Gen) structUnmarshalBool(field *ast.Field, keyV string, ptr bool) error {
key := field.Names[0].String()
- err := structUnmarshalTpl["case"].tpl.Execute(g.f, struct {
+ err := structUnmarshalTpl["case"].tpl.Execute(g.b, struct {
Key string
- }{strings.ToLower(key)})
+ }{keyV})
if err != nil {
return err
}
if ptr {
- err = structUnmarshalTpl["bool"].tpl.Execute(g.f, struct {
+ err = structUnmarshalTpl["bool"].tpl.Execute(g.b, struct {
Field string
Ptr string
}{key, ""})
@@ -216,7 +228,7 @@ func (g *gen) structUnmarshalBool(field *ast.Field, ptr bool) error {
return err
}
} else {
- err = structUnmarshalTpl["bool"].tpl.Execute(g.f, struct {
+ err = structUnmarshalTpl["bool"].tpl.Execute(g.b, struct {
Field string
Ptr string
}{key, "&"})
@@ -227,16 +239,46 @@ func (g *gen) structUnmarshalBool(field *ast.Field, ptr bool) error {
return nil
}
-func (g *gen) structUnmarshalInt(field *ast.Field, intLen string, ptr bool) error {
+func (g *Gen) structUnmarshalInt(field *ast.Field, keyV string, intLen string, ptr bool) error {
+ key := field.Names[0].String()
+ err := structUnmarshalTpl["case"].tpl.Execute(g.b, struct {
+ Key string
+ }{keyV})
+ if err != nil {
+ return err
+ }
+ if ptr {
+ err = structUnmarshalTpl["int"].tpl.Execute(g.b, struct {
+ Field string
+ IntLen string
+ Ptr string
+ }{key, intLen, ""})
+ if err != nil {
+ return err
+ }
+ } else {
+ err = structUnmarshalTpl["int"].tpl.Execute(g.b, struct {
+ Field string
+ IntLen string
+ Ptr string
+ }{key, intLen, "&"})
+ if err != nil {
+ return err
+ }
+ }
+ return nil
+}
+
+func (g *Gen) structUnmarshalUint(field *ast.Field, keyV string, intLen string, ptr bool) error {
key := field.Names[0].String()
- err := structUnmarshalTpl["case"].tpl.Execute(g.f, struct {
+ err := structUnmarshalTpl["case"].tpl.Execute(g.b, struct {
Key string
- }{strings.ToLower(key)})
+ }{keyV})
if err != nil {
return err
}
if ptr {
- err = structUnmarshalTpl["int"].tpl.Execute(g.f, struct {
+ err = structUnmarshalTpl["uint"].tpl.Execute(g.b, struct {
Field string
IntLen string
Ptr string
@@ -245,7 +287,7 @@ func (g *gen) structUnmarshalInt(field *ast.Field, intLen string, ptr bool) erro
return err
}
} else {
- err = structUnmarshalTpl["int"].tpl.Execute(g.f, struct {
+ err = structUnmarshalTpl["uint"].tpl.Execute(g.b, struct {
Field string
IntLen string
Ptr string
@@ -257,16 +299,16 @@ func (g *gen) structUnmarshalInt(field *ast.Field, intLen string, ptr bool) erro
return nil
}
-func (g *gen) structUnmarshalUint(field *ast.Field, intLen string, ptr bool) error {
+func (g *Gen) structUnmarshalFloat(field *ast.Field, keyV string, intLen string, ptr bool) error {
key := field.Names[0].String()
- err := structUnmarshalTpl["case"].tpl.Execute(g.f, struct {
+ err := structUnmarshalTpl["case"].tpl.Execute(g.b, struct {
Key string
- }{strings.ToLower(key)})
+ }{keyV})
if err != nil {
return err
}
if ptr {
- err = structUnmarshalTpl["uint"].tpl.Execute(g.f, struct {
+ err = structUnmarshalTpl["float"].tpl.Execute(g.b, struct {
Field string
IntLen string
Ptr string
@@ -275,7 +317,7 @@ func (g *gen) structUnmarshalUint(field *ast.Field, intLen string, ptr bool) err
return err
}
} else {
- err = structUnmarshalTpl["uint"].tpl.Execute(g.f, struct {
+ err = structUnmarshalTpl["float"].tpl.Execute(g.b, struct {
Field string
IntLen string
Ptr string
@@ -287,16 +329,16 @@ func (g *gen) structUnmarshalUint(field *ast.Field, intLen string, ptr bool) err
return nil
}
-func (g *gen) structUnmarshalStruct(field *ast.Field, st *ast.TypeSpec, ptr bool) error {
+func (g *Gen) structUnmarshalStruct(field *ast.Field, keyV string, st *ast.TypeSpec, ptr bool) error {
key := field.Names[0].String()
- err := structUnmarshalTpl["case"].tpl.Execute(g.f, struct {
+ err := structUnmarshalTpl["case"].tpl.Execute(g.b, struct {
Key string
- }{strings.ToLower(key)})
+ }{keyV})
if err != nil {
return err
}
if ptr {
- err = structUnmarshalTpl["struct"].tpl.Execute(g.f, struct {
+ err = structUnmarshalTpl["structPtr"].tpl.Execute(g.b, struct {
Field string
StructName string
}{key, st.Name.String()})
@@ -304,7 +346,7 @@ func (g *gen) structUnmarshalStruct(field *ast.Field, st *ast.TypeSpec, ptr bool
return err
}
} else {
- err = structUnmarshalTpl["struct"].tpl.Execute(g.f, struct {
+ err = structUnmarshalTpl["struct"].tpl.Execute(g.b, struct {
Field string
StructName string
}{key, st.Name.String()})
@@ -315,15 +357,15 @@ func (g *gen) structUnmarshalStruct(field *ast.Field, st *ast.TypeSpec, ptr bool
return nil
}
-func (g *gen) structUnmarshalArr(field *ast.Field, st *ast.TypeSpec, ptr bool) error {
+func (g *Gen) structUnmarshalArr(field *ast.Field, keyV string, st *ast.TypeSpec, ptr bool) error {
key := field.Names[0].String()
- err := structUnmarshalTpl["case"].tpl.Execute(g.f, struct {
+ err := structUnmarshalTpl["case"].tpl.Execute(g.b, struct {
Key string
- }{strings.ToLower(key)})
+ }{keyV})
if err != nil {
return err
}
- err = structUnmarshalTpl["arr"].tpl.Execute(g.f, struct {
+ err = structUnmarshalTpl["arr"].tpl.Execute(g.b, struct {
Field string
TypeName string
}{key, st.Name.String()})
diff --git a/gojay/gen_struct_unmarshal_tpl.go b/gojay/gen_struct_unmarshal_tpl.go
@@ -23,14 +23,24 @@ func (v *{{.StructName}}) NKeys() int { return {{.NKeys}} }
"uint": &genTpl{
strTpl: "\t\treturn dec.Uint{{.IntLen}}({{.Ptr}}v.{{.Field}})\n",
},
+ "float": &genTpl{
+ strTpl: "\t\treturn dec.Float{{.IntLen}}({{.Ptr}}v.{{.Field}})\n",
+ },
"bool": &genTpl{
strTpl: "\t\treturn dec.Bool({{.Ptr}}v.{{.Field}})\n",
},
"struct": &genTpl{
strTpl: ` if v.{{.Field}} == nil {
+ v.{{.Field}} = {{.StructName}}{}
+ }
+ return dec.Object(v.{{.Field}})
+`,
+ },
+ "structPtr": &genTpl{
+ strTpl: ` if v.{{.Field}} == nil {
v.{{.Field}} = &{{.StructName}}{}
}
- dec.Object(v.{{.Field}})
+ return dec.Object(v.{{.Field}})
`,
},
"arr": &genTpl{
@@ -38,7 +48,7 @@ func (v *{{.StructName}}) NKeys() int { return {{.NKeys}} }
arr := make({{.TypeName}}, 0)
v.{{.Field}} = &arr
}
- dec.Array(v.{{.Field}})
+ return dec.Array(v.{{.Field}})
`,
},
}
diff --git a/gojay/gen_stuct.go b/gojay/gen_stuct.go
@@ -2,9 +2,21 @@ package main
import (
"go/ast"
+ "strings"
)
-func (g *gen) genStruct(n string, s *ast.StructType) error {
+func getStructFieldJSONKey(field *ast.Field) string {
+ var keyV string
+ if field.Tag != nil {
+ keyV = tagKeyName(field.Tag)
+ }
+ if keyV == "" {
+ keyV = strings.ToLower(field.Names[0].String()[:1]) + field.Names[0].String()[1:]
+ }
+ return keyV
+}
+
+func (g *Gen) genStruct(n string, s *ast.StructType) error {
keys, err := g.structGenUnmarshalObj(n, s)
if err != nil {
return err
diff --git a/gojay/gen_tag.go b/gojay/gen_tag.go
@@ -0,0 +1,55 @@
+package main
+
+import (
+ "go/ast"
+ "log"
+
+ "github.com/fatih/structtag"
+)
+
+const gojayTag = "gojay"
+const hideTag = "-"
+const unmarshalHideTag = "-u"
+const marshalHideTag = "-m"
+
+func getGojayTagValue(tags *ast.BasicLit) (*structtag.Tag, error) {
+ t, err := structtag.Parse(tags.Value[1 : len(tags.Value)-1])
+ if err != nil {
+ return nil, err
+ }
+ v, err := t.Get(gojayTag)
+ if err != nil {
+ return nil, err
+ }
+ return v, nil
+}
+
+func hasTagUnmarshalHide(tags *ast.BasicLit) bool {
+ v, err := getGojayTagValue(tags)
+ if err != nil {
+ log.Print(err)
+ return false
+ }
+ return (v.Name == unmarshalHideTag || v.Name == hideTag) || v.HasOption(unmarshalHideTag)
+}
+
+func hasTagMarshalHide(tags *ast.BasicLit) bool {
+ v, err := getGojayTagValue(tags)
+ if err != nil {
+ log.Print(err)
+ return false
+ }
+ return (v.Name == marshalHideTag || v.Name == hideTag) || v.HasOption(marshalHideTag)
+}
+
+func tagKeyName(tags *ast.BasicLit) string {
+ v, err := getGojayTagValue(tags)
+ if err != nil {
+ log.Print(err)
+ return ""
+ }
+ if v.Name == hideTag || v.Name == unmarshalHideTag || v.Name == marshalHideTag {
+ return ""
+ }
+ return v.Name
+}
diff --git a/gojay/gen_test.go b/gojay/gen_test.go
@@ -0,0 +1,24 @@
+package main
+
+import (
+ "go/ast"
+ "go/parser"
+ "go/token"
+ "io"
+)
+
+func MakeGenFromReader(input io.Reader) (*Gen, error) {
+ g := NewGen("")
+ fset := token.NewFileSet()
+ f, err := parser.ParseFile(fset, "", input, parser.ParseComments)
+ if err != nil {
+ return nil, err
+ }
+ v := NewVisitor(g, g.pkg)
+ ast.Walk(v, f)
+ if err != nil {
+ return nil, err
+ }
+ g.vis = v
+ return g, nil
+}
diff --git a/gojay/main.go b/gojay/main.go
@@ -1,10 +1,9 @@
+//+build !test
+
package main
import (
- "errors"
- "go/ast"
- "go/parser"
- "go/token"
+ "flag"
"io/ioutil"
"log"
"os"
@@ -12,7 +11,8 @@ import (
"strings"
)
-const gojayAnnotation = "//gojay:json"
+var dst = flag.String("o", "", "destination file to output generated implementations")
+var src = flag.String("s", "", "source dir or file")
func hasAnnotation(fP string) bool {
b, err := ioutil.ReadFile(fP)
@@ -22,56 +22,54 @@ func hasAnnotation(fP string) bool {
return strings.Contains(string(b), gojayAnnotation)
}
+// getPath returns either the path given as argument or current working directory
func getPath() (string, error) {
- p := os.Args[1]
- return filepath.Abs(p)
-}
-
-func getFiles() ([]string, error) {
- if len(os.Args) < 2 {
- return nil, errors.New("Gojay generator takes one argument, 0 given")
- }
- p, err := getPath()
- if err != nil {
- return nil, err
- }
- files, err := ioutil.ReadDir(p)
- if err != nil {
- return nil, err
- }
- r := make([]string, 0)
- for _, f := range files {
- fP := filepath.Join(p, f.Name())
- if !f.IsDir() && strings.HasSuffix(f.Name(), ".go") && hasAnnotation(fP) {
- r = append(r, fP)
+ var err error
+ var p string
+ if *src != "" {
+ p, err = filepath.Abs(*src)
+ if err != nil {
+ return "", err
+ }
+ } else {
+ p, err = os.Getwd()
+ if err != nil {
+ return "", err
}
}
- return r, nil
+ return p, nil
}
func main() {
+ flag.Parse()
+ // get path
p, err := getPath()
if err != nil {
log.Fatal(err)
}
- // for _, f := range files {
- fset := token.NewFileSet()
- pkgs, err := parser.ParseDir(fset, p, nil, parser.ParseComments)
+ // parse source files
+ g := NewGen(p)
+ err = g.parse()
if err != nil {
log.Fatal(err)
+ return
}
- for pkgName, pkg := range pkgs {
- v := NewVisitor(pkgName)
- for fileName, f := range pkg.Files {
- v.file = fileName[:len(fileName)-3] + genFileSuffix
- ast.Walk(v, f)
- if err != nil {
- log.Fatal(err)
- }
- }
- err = v.gen()
+ // generate output
+ err = g.Gen()
+ if err != nil {
+ log.Fatal(err)
+ return
+ }
+ // if has dst file, write to file
+ if *dst != "" {
+ f, err := os.OpenFile(*dst, os.O_CREATE|os.O_TRUNC|os.O_WRONLY, 0600)
if err != nil {
log.Fatal(err)
+ return
}
+ f.WriteString(g.b.String())
+ return
}
+ // else just print to stdout
+ os.Stdout.WriteString(g.b.String())
}
diff --git a/gojay/tests/basic_slices_gojay.go b/gojay/tests/basic_slices_gojay.go
@@ -1,113 +0,0 @@
-package tests
-
-import "github.com/francoispqt/gojay"
-
-// UnmarshalJSONArray implements gojay's UnmarshalerJSONArray
-func (v *BoolSlice) UnmarshalJSONArray(dec *gojay.Decoder) error {
- var b bool
- if err := dec.Bool(&b); err != nil {
- return err
- }
- *v = append(*v, b)
- return nil
-}
-
-// MarshalJSONArray implements gojay's MarshalerJSONArray
-func (v *BoolSlice) MarshalJSONArray(enc *gojay.Encoder) {
- for _, s := range *v {
- enc.Bool(s)
- }
-}
-
-// IsNil implements gojay's MarshalerJSONArray
-func (v *BoolSlice) IsNil() bool {
- return *v == nil || len(*v) == 0
-}
-
-// UnmarshalJSONArray implements gojay's UnmarshalerJSONArray
-func (v *StructSlice) UnmarshalJSONArray(dec *gojay.Decoder) error {
- var s = &A{}
- if err := dec.Object(s); err != nil {
- return err
- }
- *v = append(*v, s)
- return nil
-}
-
-// MarshalJSONArray implements gojay's MarshalerJSONArray
-func (v *StructSlice) MarshalJSONArray(enc *gojay.Encoder) {
- for _, s := range *v {
- enc.Object(s)
- }
-}
-
-// IsNil implements gojay's MarshalerJSONArray
-func (v *StructSlice) IsNil() bool {
- return *v == nil || len(*v) == 0
-}
-
-// UnmarshalJSONArray implements gojay's UnmarshalerJSONArray
-func (v *SliceSlice) UnmarshalJSONArray(dec *gojay.Decoder) error {
- var s = make(StrSlice, 0)
- if err := dec.Array(&s); err != nil {
- return err
- }
- *v = append(*v, &s)
- return nil
-}
-
-// MarshalJSONArray implements gojay's MarshalerJSONArray
-func (v *SliceSlice) MarshalJSONArray(enc *gojay.Encoder) {
- for _, s := range *v {
- enc.Array(s)
- }
-}
-
-// IsNil implements gojay's MarshalerJSONArray
-func (v *SliceSlice) IsNil() bool {
- return *v == nil || len(*v) == 0
-}
-
-// UnmarshalJSONArray implements gojay's UnmarshalerJSONArray
-func (v *StrSlice) UnmarshalJSONArray(dec *gojay.Decoder) error {
- var str string
- if err := dec.String(&str); err != nil {
- return err
- }
- *v = append(*v, str)
- return nil
-}
-
-// MarshalJSONArray implements gojay's MarshalerJSONArray
-func (v *StrSlice) MarshalJSONArray(enc *gojay.Encoder) {
- for _, s := range *v {
- enc.String(s)
- }
-}
-
-// IsNil implements gojay's MarshalerJSONArray
-func (v *StrSlice) IsNil() bool {
- return *v == nil || len(*v) == 0
-}
-
-// UnmarshalJSONArray implements gojay's UnmarshalerJSONArray
-func (v *IntSlice) UnmarshalJSONArray(dec *gojay.Decoder) error {
- var i int
- if err := dec.Int(&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.Int(s)
- }
-}
-
-// IsNil implements gojay's MarshalerJSONArray
-func (v *IntSlice) IsNil() bool {
- return *v == nil || len(*v) == 0
-}
diff --git a/gojay/tests/basic_structs.go b/gojay/tests/basic_structs.go
@@ -2,7 +2,7 @@ package tests
//gojay:json
type A struct {
- Str string
+ Str string `gojay:"string"`
Bool bool
Int int
Int64 int64
diff --git a/gojay/tests/basic_structs_gojay.go b/gojay/tests/basic_structs_gojay.go
@@ -1,149 +0,0 @@
-package tests
-
-import "github.com/francoispqt/gojay"
-
-// UnmarshalJSONObject implements gojay's UnmarshalerJSONObject
-func (v *A) UnmarshalJSONObject(dec *gojay.Decoder, k string) error {
- switch k {
- case "str":
- return dec.String(&v.Str)
- case "bool":
- return dec.Bool(&v.Bool)
- case "int":
- return dec.Int(&v.Int)
- case "int64":
- return dec.Int64(&v.Int64)
- case "int32":
- return dec.Int32(&v.Int32)
- case "int16":
- return dec.Int16(&v.Int16)
- case "int8":
- return dec.Int8(&v.Int8)
- case "uint64":
- return dec.Uint64(&v.Uint64)
- case "uint32":
- return dec.Uint32(&v.Uint32)
- case "uint16":
- return dec.Uint16(&v.Uint16)
- case "uint8":
- return dec.Uint8(&v.Uint8)
- case "bval":
- if v.Bval == nil {
- v.Bval = &B{}
- }
- dec.Object(v.Bval)
- case "arrval":
- if v.Arrval == nil {
- arr := make(StrSlice, 0)
- v.Arrval = &arr
- }
- dec.Array(v.Arrval)
- }
- return nil
-}
-
-// NKeys returns the number of keys to unmarshal
-func (v *A) NKeys() int { return 13 }
-
-// MarshalJSONObject implements gojay's MarshalerJSONObject
-func (v *A) MarshalJSONObject(enc *gojay.Encoder) {
- enc.StringKey("str", v.Str)
- enc.BoolKey("bool", v.Bool)
- enc.IntKey("int", v.Int)
- enc.Int64Key("int64", v.Int64)
- enc.Int32Key("int32", v.Int32)
- enc.Int16Key("int16", v.Int16)
- enc.Int8Key("int8", v.Int8)
- enc.Uint64Key("uint64", v.Uint64)
- enc.Uint32Key("uint32", v.Uint32)
- enc.Uint16Key("uint16", v.Uint16)
- enc.Uint8Key("uint8", v.Uint8)
- enc.ObjectKey("bval", v.Bval)
- enc.ArrayKey("arrval", v.Arrval)
-}
-
-// IsNil returns wether the structure is nil value or not
-func (v *A) IsNil() bool { return v == nil }
-
-// UnmarshalJSONObject implements gojay's UnmarshalerJSONObject
-func (v *B) UnmarshalJSONObject(dec *gojay.Decoder, k string) error {
- switch k {
- case "str":
- return dec.String(&v.Str)
- case "bool":
- return dec.Bool(&v.Bool)
- case "int":
- return dec.Int(&v.Int)
- case "int64":
- return dec.Int64(&v.Int64)
- case "int32":
- return dec.Int32(&v.Int32)
- case "int16":
- return dec.Int16(&v.Int16)
- case "int8":
- return dec.Int8(&v.Int8)
- case "uint64":
- return dec.Uint64(&v.Uint64)
- case "uint32":
- return dec.Uint32(&v.Uint32)
- case "uint16":
- return dec.Uint16(&v.Uint16)
- case "uint8":
- return dec.Uint8(&v.Uint8)
- case "strptr":
- return dec.String(v.StrPtr)
- case "boolptr":
- return dec.Bool(v.BoolPtr)
- case "intptr":
- return dec.Int(v.IntPtr)
- case "int64ptr":
- return dec.Int64(v.Int64Ptr)
- case "int32ptr":
- return dec.Int32(v.Int32Ptr)
- case "int16ptr":
- return dec.Int16(v.Int16Ptr)
- case "int8ptr":
- return dec.Int8(v.Int8Ptr)
- case "uint64ptr":
- return dec.Uint64(v.Uint64Ptr)
- case "uint32ptr":
- return dec.Uint32(v.Uint32Ptr)
- case "uint16ptr":
- return dec.Uint16(v.Uint16Ptr)
- case "uint8ptr":
- return dec.Uint8(v.Uint8PTr)
- }
- return nil
-}
-
-// NKeys returns the number of keys to unmarshal
-func (v *B) NKeys() int { return 22 }
-
-// MarshalJSONObject implements gojay's MarshalerJSONObject
-func (v *B) MarshalJSONObject(enc *gojay.Encoder) {
- enc.StringKey("str", v.Str)
- enc.BoolKey("bool", v.Bool)
- enc.IntKey("int", v.Int)
- enc.Int64Key("int64", v.Int64)
- enc.Int32Key("int32", v.Int32)
- enc.Int16Key("int16", v.Int16)
- enc.Int8Key("int8", v.Int8)
- enc.Uint64Key("uint64", v.Uint64)
- enc.Uint32Key("uint32", v.Uint32)
- enc.Uint16Key("uint16", v.Uint16)
- enc.Uint8Key("uint8", v.Uint8)
- enc.StringKey("strptr", *v.StrPtr)
- enc.BoolKey("boolptr", *v.BoolPtr)
- enc.IntKey("intptr", *v.IntPtr)
- enc.Int64Key("int64ptr", *v.Int64Ptr)
- enc.Int32Key("int32ptr", *v.Int32Ptr)
- enc.Int16Key("int16ptr", *v.Int16Ptr)
- enc.Int8Key("int8ptr", *v.Int8Ptr)
- enc.Uint64Key("uint64ptr", *v.Uint64Ptr)
- enc.Uint32Key("uint32ptr", *v.Uint32Ptr)
- enc.Uint16Key("uint16ptr", *v.Uint16Ptr)
- enc.Uint8Key("uint8ptr", *v.Uint8PTr)
-}
-
-// IsNil returns wether the structure is nil value or not
-func (v *B) IsNil() bool { return v == nil }
diff --git a/gojay/visitor.go b/gojay/visitor.go
@@ -2,7 +2,6 @@ package main
import (
"go/ast"
- "os"
"strings"
)
@@ -17,9 +16,7 @@ func docContains(n *ast.CommentGroup, s string) bool {
type vis struct {
pkg string
- specs map[string]*ast.TypeSpec
- files map[string]map[string]*ast.TypeSpec
- file string
+ g *Gen
commentFound bool
}
@@ -38,11 +35,7 @@ func (v *vis) Visit(n ast.Node) (w ast.Visitor) {
return v
case *ast.TypeSpec:
if v.commentFound {
- v.specs[n.Name.Name] = n
- if v.files[v.file] == nil {
- v.files[v.file] = make(map[string]*ast.TypeSpec)
- }
- v.files[v.file][n.Name.Name] = n
+ v.g.genTypes[n.Name.Name] = n
}
v.commentFound = false
return v
@@ -53,27 +46,9 @@ func (v *vis) Visit(n ast.Node) (w ast.Visitor) {
return v
}
-func (v *vis) gen() error {
- for fileName, genTypes := range v.files {
- // open the file
- f, err := os.OpenFile(fileName, os.O_CREATE|os.O_TRUNC|os.O_WRONLY, 0777)
- if err != nil {
- return err
- }
- defer f.Close()
- g := &gen{f, genTypes, v}
- err = g.gen(v.pkg)
- if err != nil {
- return err
- }
- }
- return nil
-}
-
-func NewVisitor(pkgName string) *vis {
+func NewVisitor(g *Gen, pkgName string) *vis {
return &vis{
- pkg: pkgName,
- specs: make(map[string]*ast.TypeSpec),
- files: make(map[string]map[string]*ast.TypeSpec),
+ g: g,
+ pkg: pkgName,
}
}