gojay

high performance JSON encoder/decoder with stream API for Golang
git clone git://git.lair.cx/gojay
Log | Files | Refs | README | LICENSE

commit af36826393b902b5c558dc49073c249e4fa2ebfe
parent ed06be23fa1713f994603eb28bfe7b59f9ae0f2b
Author: francoispqt <francois@parquet.ninja>
Date:   Thu, 31 May 2018 00:10:15 +0800

add struc field unmarshaling clean code

Diffstat:
Mgojay/gen_struct_unmarshal.go | 208+++++++++++++++++++++++++++++++++++++++++++++++++++++--------------------------
Dgojay/gojay | 0
Mgojay/tests/basic_structs.go | 1+
Mgojay/tests/basic_structs_gojay.go | 17+++++++++++------
4 files changed, 151 insertions(+), 75 deletions(-)

diff --git a/gojay/gen_struct_unmarshal.go b/gojay/gen_struct_unmarshal.go @@ -1,11 +1,15 @@ package main import ( + "errors" "go/ast" "html/template" "log" "os" + "reflect" "strings" + + "github.com/davecgh/go-spew/spew" ) var structUnmarshalDefTpl *template.Template @@ -14,6 +18,7 @@ var structUnmarshalStringTpl *template.Template var structUnmarshalIntTpl *template.Template var structUnmarshalUintTpl *template.Template var structUnmarshalBoolTpl *template.Template +var structUnmarshalStructTpl *template.Template var structNKeysTpl *template.Template @@ -27,8 +32,8 @@ var structUnmarshalClose = []byte("\treturn nil\n}\n") func init() { t, err := template.New("structUnmarshalDef"). - Parse("\n// UnmarshalJSONOject implements gojay's UnmarshalerJSONObject" + - "\nfunc (v *{{.StructName}}) UnmarshalJSONOject(dec *gojay.Decoder, k string) error {\n", + Parse("\n// UnmarshalJSONObject implements gojay's UnmarshalerJSONObject" + + "\nfunc (v *{{.StructName}}) UnmarshalJSONObject(dec *gojay.Decoder, k string) error {\n", ) if err != nil { log.Fatal(err) @@ -49,33 +54,46 @@ func init() { } structUnmarshalStringTpl = t - t, err = template.New("structUnmarshalCaseString"). + t, err = template.New("structUnmarshalCaseInt"). Parse("\t\treturn dec.Int{{.IntLen}}(&v.{{.Field}})\n") if err != nil { log.Fatal(err) } structUnmarshalIntTpl = t - t, err = template.New("structUnmarshalCaseString"). + t, err = template.New("structUnmarshalCaseUint"). Parse("\t\treturn dec.Uint{{.IntLen}}(&v.{{.Field}})\n") if err != nil { log.Fatal(err) } structUnmarshalUintTpl = t - t, err = template.New("structUnmarshalCaseString"). + t, err = template.New("structUnmarshalCaseBool"). Parse("\t\treturn dec.Bool(&v.{{.Field}})\n") if err != nil { log.Fatal(err) } structUnmarshalBoolTpl = t + t, err = template.New("structUnmarshalCaseStruct"). + Parse( + ` if v.{{.Field}} == nil { + v.{{.Field}} = &{{.StructName}}{} + } + dec.Object(v.{{.Field}}) +`) + if err != nil { + log.Fatal(err) + } + structUnmarshalStructTpl = t + t, err = template.New("structUnmarshalNKeys"). Parse(nKeysMethod) if err != nil { log.Fatal(err) } structNKeysTpl = t + } func (v *vis) structGenNKeys(f *os.File, n string, count int) error { @@ -107,74 +125,25 @@ func (v *vis) structGenUnmarshalObj(f *os.File, n string, s *ast.StructType) (in for _, field := range s.Fields.List { switch t := field.Type.(type) { case *ast.Ident: - switch t.String() { - case "string": - err = v.structUnmarshalString(f, field) - if err != nil { - return 0, err - } - keys++ - case "bool": - err = v.structUnmarshalBool(f, field) - if err != nil { - return 0, err - } - keys++ - case "int": - err = v.structUnmarshalInt(f, field, "") - if err != nil { - return 0, err - } - keys++ - case "int64": - err = v.structUnmarshalInt(f, field, "64") - if err != nil { - return 0, err - } - keys++ - case "int32": - err = v.structUnmarshalInt(f, field, "32") - if err != nil { - return 0, err - } - keys++ - case "int16": - err = v.structUnmarshalInt(f, field, "16") - if err != nil { - return 0, err - } - keys++ - case "int8": - err = v.structUnmarshalInt(f, field, "8") - if err != nil { - return 0, err - } - keys++ - case "uint64": - err = v.structUnmarshalUint(f, field, "64") - if err != nil { - return 0, err - } - keys++ - case "uint32": - err = v.structUnmarshalUint(f, field, "32") - if err != nil { - return 0, err - } - keys++ - case "uint16": - err = v.structUnmarshalUint(f, field, "16") - if err != nil { - return 0, err - } - keys++ - case "uint8": - err = v.structUnmarshalUint(f, field, "8") + var err error + keys, err = v.structGenUnmarshalIdent(f, field, t, keys) + if err != nil { + return 0, err + } + case *ast.StarExpr: + switch ptrExp := t.X.(type) { + case *ast.Ident: + var err error + keys, err = v.structGenUnmarshalIdent(f, field, ptrExp, keys) if err != nil { return 0, err } - keys++ + default: + spew.Println(reflect.TypeOf(ptrExp)) + spew.Println(ptrExp) } + default: + spew.Println(t) } } // close switch statement @@ -187,6 +156,89 @@ func (v *vis) structGenUnmarshalObj(f *os.File, n string, s *ast.StructType) (in return keys, nil } +func (v *vis) structGenUnmarshalIdent(f *os.File, field *ast.Field, i *ast.Ident, keys int) (int, error) { + switch i.String() { + case "string": + var err = v.structUnmarshalString(f, field) + if err != nil { + return 0, err + } + keys++ + case "bool": + var err = v.structUnmarshalBool(f, field) + if err != nil { + return 0, err + } + keys++ + case "int": + var err = v.structUnmarshalInt(f, field, "") + if err != nil { + return 0, err + } + keys++ + case "int64": + var err = v.structUnmarshalInt(f, field, "64") + if err != nil { + return 0, err + } + keys++ + case "int32": + var err = v.structUnmarshalInt(f, field, "32") + if err != nil { + return 0, err + } + keys++ + case "int16": + var err = v.structUnmarshalInt(f, field, "16") + if err != nil { + return 0, err + } + keys++ + case "int8": + var err = v.structUnmarshalInt(f, field, "8") + if err != nil { + return 0, err + } + keys++ + case "uint64": + var err = v.structUnmarshalUint(f, field, "64") + if err != nil { + return 0, err + } + keys++ + case "uint32": + var err = v.structUnmarshalUint(f, field, "32") + if err != nil { + return 0, err + } + keys++ + case "uint16": + var err = v.structUnmarshalUint(f, field, "16") + if err != nil { + return 0, err + } + keys++ + case "uint8": + var err = v.structUnmarshalUint(f, field, "8") + if err != nil { + return 0, err + } + keys++ + default: + switch t := i.Obj.Decl.(type) { + case *ast.TypeSpec: + var err = v.structUnmarshalStruct(f, field, t) + if err != nil { + return 0, err + } + keys++ + default: + return 0, errors.New("could not determine what to do with type " + i.String()) + } + } + return keys, nil +} + func (v *vis) structUnmarshalString(f *os.File, field *ast.Field) error { key := field.Names[0].String() err := structUnmarshalCaseTpl.Execute(f, struct { @@ -256,3 +308,21 @@ func (v *vis) structUnmarshalUint(f *os.File, field *ast.Field, intLen string) e } return nil } + +func (v *vis) structUnmarshalStruct(f *os.File, field *ast.Field, st *ast.TypeSpec) error { + key := field.Names[0].String() + err := structUnmarshalCaseTpl.Execute(f, struct { + Key string + }{strings.ToLower(key)}) + if err != nil { + return err + } + err = structUnmarshalStructTpl.Execute(f, struct { + Field string + StructName string + }{key, st.Name.String()}) + if err != nil { + return err + } + return nil +} diff --git a/gojay/gojay b/gojay/gojay Binary files differ. diff --git a/gojay/tests/basic_structs.go b/gojay/tests/basic_structs.go @@ -13,6 +13,7 @@ type A struct { Uint32 uint32 Uint16 uint16 Uint8 uint8 + Bval *B } //gojay:json diff --git a/gojay/tests/basic_structs_gojay.go b/gojay/tests/basic_structs_gojay.go @@ -1,9 +1,9 @@ -package tests +package tests import "github.com/francoispqt/gojay" -// UnmarshalJSONOject implements gojay's UnmarshalerJSONObject -func (v *A) UnmarshalJSONOject(dec *gojay.Decoder, k string) error { +// UnmarshalJSONObject implements gojay's UnmarshalerJSONObject +func (v *A) UnmarshalJSONObject(dec *gojay.Decoder, k string) error { switch k { case "str": return dec.String(&v.Str) @@ -27,12 +27,17 @@ func (v *A) UnmarshalJSONOject(dec *gojay.Decoder, k string) error { 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) } return nil } // NKeys returns the number of keys to unmarshal -func (v *A) NKeys() int { return 11 } +func (v *A) NKeys() int { return 12 } // MarshalJSONObject implements gojay's MarshalerJSONObject func (v *A) MarshalJSONOject(enc *gojay.Encoder) { @@ -52,8 +57,8 @@ func (v *A) MarshalJSONOject(enc *gojay.Encoder) { // IsNil returns wether the structure is nil value or not func (v *A) IsNil() bool { return v == nil } -// UnmarshalJSONOject implements gojay's UnmarshalerJSONObject -func (v *B) UnmarshalJSONOject(dec *gojay.Decoder, k string) error { +// UnmarshalJSONObject implements gojay's UnmarshalerJSONObject +func (v *B) UnmarshalJSONObject(dec *gojay.Decoder, k string) error { switch k { case "str": return dec.String(&v.Str)