gojay

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

commit 28447855779c4df0f19d1840af686fe53b9e3838
parent c60a101913909d4969bb17bf7da824f2e197317d
Author: francoispqt <francois@parquet.ninja>
Date:   Sat, 26 Jan 2019 01:38:53 +0800

add comments, refactor code for code generator

Diffstat:
Mgojay/codegen/generator.go | 44++++++++++++++++++++++++++++++++++----------
Mgojay/codegen/generator_test.go | 4++--
Mgojay/codegen/options.go | 3+++
Mgojay/codegen/struct.go | 1-
Mgojay/codegen/test/annotated_struct/encoding.go | 46+++++++++++++++++++++++-----------------------
Mgojay/codegen/test/basic_struct/encoding.go | 4++--
Mgojay/codegen/test/embedded_struct/encoding.go | 106++++++++++++++++++++++++++++++++++++++++----------------------------------------
Mgojay/codegen/test/pooled_struct/encoding.go | 124++++++++++++++++++++++++++++++++++++++++----------------------------------------
Mgojay/gojaygen.go | 5+++--
9 files changed, 182 insertions(+), 155 deletions(-)

diff --git a/gojay/codegen/generator.go b/gojay/codegen/generator.go @@ -11,6 +11,9 @@ import ( "github.com/viant/toolbox" ) +const gojayPackage = "github.com/francoispqt/gojay" + +// Generator holds the content to generate the gojay code type Generator struct { fileInfo *toolbox.FileSetInfo types map[string]string @@ -27,14 +30,17 @@ type Generator struct { options *Options } +// Returns the type from the the fileInfo func (g *Generator) Type(typeName string) *toolbox.TypeInfo { return g.fileInfo.Type(typeName) } +// addImport adds an import package to be printed on the generated code func (g *Generator) addImport(pkg string) { g.imports[`"`+pkg+`"`] = true } +// we initiate the variables containing the code to be generated func (g *Generator) init() { g.filedInit = []string{} g.imports = map[string]bool{} @@ -42,27 +48,41 @@ func (g *Generator) init() { g.structTypes = map[string]string{} g.sliceTypes = map[string]string{} g.poolInit = map[string]string{} - g.addImport("github.com/francoispqt/gojay") + g.addImport(gojayPackage) + // if we want pools, add the sync package right away + if g.options.PoolObjects { + g.addImport("sync") + } } -func (g *Generator) Generate(options *Options) error { +// NewGenerator creates a new generator with the given options +func NewGenerator(options *Options) *Generator { + var g = &Generator{} + // first we validate the flags if err := options.Validate(); err != nil { - return err + panic(err) } g.options = options + // we initiate the values on the generator g.init() + return g +} - if options.PoolObjects { - g.addImport("sync") - } - if err := g.readPackageCode(options.Source); err != nil { +// Generate generates the gojay implementation code +func (g *Generator) Generate() error { + // first we read the code from which we should find the types + if err := g.readPackageCode(g.options.Source); err != nil { return err } - for _, rootType := range options.Types { + + // then we generate code for the types given + for _, rootType := range g.options.Types { if err := g.generateStructCode(rootType); err != nil { return err } } + + // g.Imports = strings.Join(toolbox.MapKeysToStringSlice(g.imports), "\n") return g.writeCode() } @@ -94,8 +114,6 @@ func (g *Generator) writeCode() error { return err } - fmt.Println(string(expandedCode)) - code, err := format.Source([]byte(expandedCode)) if err != nil { @@ -222,5 +240,11 @@ func (g *Generator) readPackageCode(pkgPath string) error { g.Pkg = filepath.Base(p) g.fileInfo, err = toolbox.NewFileSetInfo(p) } + + // if Pkg flag is set use it + if g.options.Pkg != "" { + g.Pkg = g.options.Pkg + } + return err } diff --git a/gojay/codegen/generator_test.go b/gojay/codegen/generator_test.go @@ -57,8 +57,8 @@ func TestGenerator_Generate(t *testing.T) { } for _, useCase := range useCases { - gen := &Generator{} - err := gen.Generate(useCase.options) + gen := NewGenerator(useCase.options) + err := gen.Generate() if useCase.hasError { assert.NotNil(t, err, useCase.description) continue diff --git a/gojay/codegen/options.go b/gojay/codegen/options.go @@ -15,6 +15,7 @@ type Options struct { Types []string PoolObjects bool TagName string + Pkg string } func (o *Options) Validate() error { @@ -33,6 +34,7 @@ const ( optionKeyTypes = "t" optionKeyTagName = "a" optionKeyPoolObjects = "p" + optionKeyPkg = "pkg" ) //NewOptionsWithFlagSet creates a new options for the supplide flagset @@ -45,6 +47,7 @@ func NewOptionsWithFlagSet(set *flag.FlagSet) *Options { result.PoolObjects = toolbox.AsBoolean(set.Lookup(optionKeyPoolObjects).Value.String()) result.TagName = set.Lookup(optionKeyTagName).Value.String() result.Types = strings.Split(set.Lookup(optionKeyTypes).Value.String(), ",") + result.Pkg = set.Lookup(optionKeyPkg).Value.String() if result.Source == "" { result.Source = url.NewResource(".").ParsedURL.Path } diff --git a/gojay/codegen/struct.go b/gojay/codegen/struct.go @@ -190,7 +190,6 @@ func (s *Struct) generateFieldDecoding(fields []*toolbox.FieldInfo) (string, []s return "", nil, err } } - // if is time.Time } else if _, k, ok := s.typedFieldDecode(field, field.Type); ok { templateKey = k } else { diff --git a/gojay/codegen/test/annotated_struct/encoding.go b/gojay/codegen/test/annotated_struct/encoding.go @@ -6,6 +6,27 @@ import ( "time" ) +type SubMessages []SubMessage + +func (s *SubMessages) UnmarshalJSONArray(dec *gojay.Decoder) error { + var value = SubMessage{} + if err := dec.Object(&value); err != nil { + return err + } + *s = append(*s, value) + return nil +} + +func (s SubMessages) MarshalJSONArray(enc *gojay.Encoder) { + for i := range s { + enc.Object(&s[i]) + } +} + +func (s SubMessages) IsNil() bool { + return len(s) == 0 +} + type Ints []int // UnmarshalJSONArray decodes JSON array elements into slice @@ -75,27 +96,6 @@ func (s SubMessagesPtr) IsNil() bool { return len(s) == 0 } -type SubMessages []SubMessage - -func (s *SubMessages) UnmarshalJSONArray(dec *gojay.Decoder) error { - var value = SubMessage{} - if err := dec.Object(&value); err != nil { - return err - } - *s = append(*s, value) - return nil -} - -func (s SubMessages) MarshalJSONArray(enc *gojay.Encoder) { - for i := range s { - enc.Object(&s[i]) - } -} - -func (s SubMessages) IsNil() bool { - return len(s) == 0 -} - // MarshalJSONObject implements MarshalerJSONObject func (m *SubMessage) MarshalJSONObject(enc *gojay.Encoder) { enc.IntKey("id", m.Id) @@ -124,7 +124,7 @@ func (m *SubMessage) UnmarshalJSONObject(dec *gojay.Decoder, k string) error { case "startDate": var format = "2006-01-02 15:04:05" var value = time.Time{} - err := dec.DecodeTime(&value, format) + err := dec.Time(&value, format) if err == nil { m.StartTime = value } @@ -133,7 +133,7 @@ func (m *SubMessage) UnmarshalJSONObject(dec *gojay.Decoder, k string) error { case "endDate": var format = "2006-01-02 15:04:05" var value = &time.Time{} - err := dec.DecodeTime(value, format) + err := dec.Time(value, format) if err == nil { m.EndTime = value } diff --git a/gojay/codegen/test/basic_struct/encoding.go b/gojay/codegen/test/basic_struct/encoding.go @@ -124,7 +124,7 @@ func (m *SubMessage) UnmarshalJSONObject(dec *gojay.Decoder, k string) error { case "StartTime": var format = time.RFC3339 var value = time.Time{} - err := dec.DecodeTime(&value, format) + err := dec.Time(&value, format) if err == nil { m.StartTime = value } @@ -133,7 +133,7 @@ func (m *SubMessage) UnmarshalJSONObject(dec *gojay.Decoder, k string) error { case "EndTime": var format = time.RFC3339 var value = &time.Time{} - err := dec.DecodeTime(value, format) + err := dec.Time(value, format) if err == nil { m.EndTime = value } diff --git a/gojay/codegen/test/embedded_struct/encoding.go b/gojay/codegen/test/embedded_struct/encoding.go @@ -6,27 +6,6 @@ import ( "time" ) -type SubMessages []SubMessage - -func (s *SubMessages) UnmarshalJSONArray(dec *gojay.Decoder) error { - var value = SubMessage{} - if err := dec.Object(&value); err != nil { - return err - } - *s = append(*s, value) - return nil -} - -func (s SubMessages) MarshalJSONArray(enc *gojay.Encoder) { - for i := range s { - enc.Object(&s[i]) - } -} - -func (s SubMessages) IsNil() bool { - return len(s) == 0 -} - type Ints []int // UnmarshalJSONArray decodes JSON array elements into slice @@ -96,6 +75,55 @@ func (s SubMessagesPtr) IsNil() bool { return len(s) == 0 } +type SubMessages []SubMessage + +func (s *SubMessages) UnmarshalJSONArray(dec *gojay.Decoder) error { + var value = SubMessage{} + if err := dec.Object(&value); err != nil { + return err + } + *s = append(*s, value) + return nil +} + +func (s SubMessages) MarshalJSONArray(enc *gojay.Encoder) { + for i := range s { + enc.Object(&s[i]) + } +} + +func (s SubMessages) IsNil() bool { + return len(s) == 0 +} + +// MarshalJSONObject implements MarshalerJSONObject +func (i *BaseId) MarshalJSONObject(enc *gojay.Encoder) { + enc.IntKey("Id", i.Id) + enc.StringKey("Name", i.Name) +} + +// IsNil checks if instance is nil +func (i *BaseId) IsNil() bool { + return i == nil +} + +// UnmarshalJSONObject implements gojay's UnmarshalerJSONObject +func (i *BaseId) UnmarshalJSONObject(dec *gojay.Decoder, k string) error { + + switch k { + case "Id": + return dec.Int(&i.Id) + + case "Name": + return dec.String(&i.Name) + + } + return nil +} + +// NKeys returns the number of keys to unmarshal +func (i *BaseId) NKeys() int { return 2 } + // MarshalJSONObject implements MarshalerJSONObject func (m *SubMessage) MarshalJSONObject(enc *gojay.Encoder) { enc.StringKey("Description", m.Description) @@ -120,7 +148,7 @@ func (m *SubMessage) UnmarshalJSONObject(dec *gojay.Decoder, k string) error { case "StartTime": var format = time.RFC3339 var value = time.Time{} - err := dec.DecodeTime(&value, format) + err := dec.Time(&value, format) if err == nil { m.StartTime = value } @@ -129,7 +157,7 @@ func (m *SubMessage) UnmarshalJSONObject(dec *gojay.Decoder, k string) error { case "EndTime": var format = time.RFC3339 var value = &time.Time{} - err := dec.DecodeTime(value, format) + err := dec.Time(value, format) if err == nil { m.EndTime = value } @@ -192,7 +220,7 @@ func (m *Message) UnmarshalJSONObject(dec *gojay.Decoder, k string) error { case "StartTime": var format = time.RFC3339 var value = time.Time{} - err := dec.DecodeTime(&value, format) + err := dec.Time(&value, format) if err == nil { m.StartTime = value } @@ -201,7 +229,7 @@ func (m *Message) UnmarshalJSONObject(dec *gojay.Decoder, k string) error { case "EndTime": var format = time.RFC3339 var value = &time.Time{} - err := dec.DecodeTime(value, format) + err := dec.Time(value, format) if err == nil { m.EndTime = value } @@ -278,31 +306,3 @@ func (m *Message) UnmarshalJSONObject(dec *gojay.Decoder, k string) error { // NKeys returns the number of keys to unmarshal func (m *Message) NKeys() int { return 14 } - -// MarshalJSONObject implements MarshalerJSONObject -func (i *BaseId) MarshalJSONObject(enc *gojay.Encoder) { - enc.IntKey("Id", i.Id) - enc.StringKey("Name", i.Name) -} - -// IsNil checks if instance is nil -func (i *BaseId) IsNil() bool { - return i == nil -} - -// UnmarshalJSONObject implements gojay's UnmarshalerJSONObject -func (i *BaseId) UnmarshalJSONObject(dec *gojay.Decoder, k string) error { - - switch k { - case "Id": - return dec.Int(&i.Id) - - case "Name": - return dec.String(&i.Name) - - } - return nil -} - -// NKeys returns the number of keys to unmarshal -func (i *BaseId) NKeys() int { return 2 } diff --git a/gojay/codegen/test/pooled_struct/encoding.go b/gojay/codegen/test/pooled_struct/encoding.go @@ -8,20 +8,20 @@ import ( ) func init() { - MessagePool = &sync.Pool{ + SubMessagePool = &sync.Pool{ New: func() interface{} { - return &Message{} + return &SubMessage{} }, } - SubMessagePool = &sync.Pool{ + MessagePool = &sync.Pool{ New: func() interface{} { - return &SubMessage{} + return &Message{} }, } } -var SubMessagePool *sync.Pool var MessagePool *sync.Pool +var SubMessagePool *sync.Pool type Ints []int @@ -114,6 +114,63 @@ func (s SubMessages) IsNil() bool { } // MarshalJSONObject implements MarshalerJSONObject +func (m *SubMessage) MarshalJSONObject(enc *gojay.Encoder) { + enc.IntKey("Id", m.Id) + enc.StringKey("Description", m.Description) + enc.TimeKey("StartTime", &m.StartTime, time.RFC3339) + if m.EndTime != nil { + enc.TimeKey("EndTime", m.EndTime, time.RFC3339) + } +} + +// IsNil checks if instance is nil +func (m *SubMessage) IsNil() bool { + return m == nil +} + +// UnmarshalJSONObject implements gojay's UnmarshalerJSONObject +func (m *SubMessage) UnmarshalJSONObject(dec *gojay.Decoder, k string) error { + + switch k { + case "Id": + return dec.Int(&m.Id) + + case "Description": + return dec.String(&m.Description) + + case "StartTime": + var format = time.RFC3339 + var value = time.Time{} + err := dec.Time(&value, format) + if err == nil { + m.StartTime = value + } + return err + + case "EndTime": + var format = time.RFC3339 + var value = &time.Time{} + err := dec.Time(value, format) + if err == nil { + m.EndTime = value + } + return err + + } + return nil +} + +// NKeys returns the number of keys to unmarshal +func (m *SubMessage) NKeys() int { return 4 } + +// Reset reset fields +func (m *SubMessage) Reset() { + m.Id = 0 + m.Description = "" + m.EndTime = nil +} + +// MarshalJSONObject implements MarshalerJSONObject func (m *Message) MarshalJSONObject(enc *gojay.Encoder) { enc.IntKey("Id", m.Id) enc.StringKey("Name", m.Name) @@ -242,60 +299,3 @@ func (m *Message) Reset() { m.IsTrue = nil m.Payload = nil } - -// MarshalJSONObject implements MarshalerJSONObject -func (m *SubMessage) MarshalJSONObject(enc *gojay.Encoder) { - enc.IntKey("Id", m.Id) - enc.StringKey("Description", m.Description) - enc.TimeKey("StartTime", &m.StartTime, time.RFC3339) - if m.EndTime != nil { - enc.TimeKey("EndTime", m.EndTime, time.RFC3339) - } -} - -// IsNil checks if instance is nil -func (m *SubMessage) IsNil() bool { - return m == nil -} - -// UnmarshalJSONObject implements gojay's UnmarshalerJSONObject -func (m *SubMessage) UnmarshalJSONObject(dec *gojay.Decoder, k string) error { - - switch k { - case "Id": - return dec.Int(&m.Id) - - case "Description": - return dec.String(&m.Description) - - case "StartTime": - var format = time.RFC3339 - var value = time.Time{} - err := dec.DecodeTime(&value, format) - if err == nil { - m.StartTime = value - } - return err - - case "EndTime": - var format = time.RFC3339 - var value = &time.Time{} - err := dec.DecodeTime(value, format) - if err == nil { - m.EndTime = value - } - return err - - } - return nil -} - -// NKeys returns the number of keys to unmarshal -func (m *SubMessage) NKeys() int { return 4 } - -// Reset reset fields -func (m *SubMessage) Reset() { - m.Id = 0 - m.Description = "" - m.EndTime = nil -} diff --git a/gojay/gojaygen.go b/gojay/gojaygen.go @@ -6,6 +6,7 @@ import ( "log" ) +var pkg = flag.String("pkg", "", "the package name of the generated file") var dst = flag.String("o", "", "destination file to output generated implementations") var src = flag.String("s", "", "source dir or file (absolute or relative path)") var types = flag.String("t", "", "types to generate") @@ -15,8 +16,8 @@ var poolObjects = flag.String("p", "", "generate code to reuse objects using syn func main() { flag.Parse() options := codegen.NewOptionsWithFlagSet(flag.CommandLine) - gen := &codegen.Generator{} - if err := gen.Generate(options); err != nil { + gen := codegen.NewGenerator(options) + if err := gen.Generate(); err != nil { log.Fatal(err) } }