diff --git a/Makefile b/Makefile index cc5ebbad..40349fd2 100644 --- a/Makefile +++ b/Makefile @@ -52,6 +52,7 @@ generate: build bin/easyjson -build_tags=use_easyjson -disable_members_unescape ./benchmark/data.go bin/easyjson -disallow_unknown_fields ./tests/disallow_unknown.go bin/easyjson -disable_members_unescape ./tests/members_unescaped.go + bin/easyjson -float_format='f' ./tests/float_format.go test: generate go test \ diff --git a/README.md b/README.md index 943b9e4c..f2ea3ec8 100644 --- a/README.md +++ b/README.md @@ -53,35 +53,37 @@ for more information and features. ```txt Usage of easyjson: -all - generate marshaler/unmarshalers for all structs in a file + generate marshaler/unmarshalers for all structs in a file -build_tags string build tags to add to generated file - -gen_build_flags string - build flags when running the generator while bootstrapping -byte use simple bytes instead of Base64Bytes for slice of bytes + -disable_members_unescape + don't perform unescaping of member names to improve performance + -disallow_unknown_fields + return error if any unknown field in json appeared + -float_format string + float format to be used in json writer + -gen_build_flags string + build flags when running the generator while bootstrapping -leave_temps - do not delete temporary files + do not delete temporary files + -lower_camel_case + use lowerCamelCase names instead of CamelCase by default -no_std_marshalers - don't generate MarshalJSON/UnmarshalJSON funcs + don't generate MarshalJSON/UnmarshalJSON funcs -noformat - do not run 'gofmt -w' on output file + do not run 'gofmt -w' on output file -omit_empty - omit empty fields by default + omit empty fields by default -output_filename string - specify the filename of the output + specify the filename of the output -pkg - process the whole package instead of just the given file + process the whole package instead of just the given file -snake_case - use snake_case names instead of CamelCase by default - -lower_camel_case - use lowerCamelCase instead of CamelCase by default + use snake_case names instead of CamelCase by default -stubs - only generate stubs for marshaler/unmarshaler funcs - -disallow_unknown_fields - return error if some unknown field in json appeared - -disable_members_unescape - disable unescaping of \uXXXX string sequences in member names + only generate stubs for marshaler/unmarshaler funcs ``` Using `-all` will generate marshalers/unmarshalers for all Go structs in the diff --git a/bootstrap/bootstrap.go b/bootstrap/bootstrap.go index 5755beea..c17b4e61 100644 --- a/bootstrap/bootstrap.go +++ b/bootstrap/bootstrap.go @@ -36,6 +36,7 @@ type Generator struct { OutName string BuildTags string GenBuildFlags string + FloatFmt string StubsOnly bool LeaveTemps bool @@ -116,6 +117,9 @@ func (g *Generator) writeMain() (path string, err error) { if g.BuildTags != "" { fmt.Fprintf(f, " g.SetBuildTags(%q)\n", g.BuildTags) } + if g.FloatFmt != "" { + fmt.Fprintf(f, " g.SetFloatFmt(%q)\n", g.FloatFmt) + } if g.SnakeCase { fmt.Fprintln(f, " g.UseSnakeCase()") } diff --git a/easyjson/main.go b/easyjson/main.go index d337c846..68c1456e 100644 --- a/easyjson/main.go +++ b/easyjson/main.go @@ -18,6 +18,7 @@ import ( var buildTags = flag.String("build_tags", "", "build tags to add to generated file") var genBuildFlags = flag.String("gen_build_flags", "", "build flags when running the generator while bootstrapping") +var floatFmt = flag.String("float_format", "", "float format to be used in json writer") var snakeCase = flag.Bool("snake_case", false, "use snake_case names instead of CamelCase by default") var lowerCamelCase = flag.Bool("lower_camel_case", false, "use lowerCamelCase names instead of CamelCase by default") var noStdMarshalers = flag.Bool("no_std_marshalers", false, "don't generate MarshalJSON/UnmarshalJSON funcs") @@ -68,6 +69,11 @@ func generate(fname string) (err error) { trimmedGenBuildFlags = strings.TrimSpace(*genBuildFlags) } + var trimmedFloatFmt string + if *floatFmt != "" { + trimmedFloatFmt = strings.TrimSpace(*floatFmt) + } + g := bootstrap.Generator{ BuildTags: trimmedBuildTags, GenBuildFlags: trimmedGenBuildFlags, @@ -85,6 +91,7 @@ func generate(fname string) (err error) { StubsOnly: *stubs, NoFormat: *noformat, SimpleBytes: *simpleBytes, + FloatFmt: trimmedFloatFmt, } if err := g.Run(); err != nil { diff --git a/gen/encoder.go b/gen/encoder.go index ed6d6ad5..0730da64 100644 --- a/gen/encoder.go +++ b/gen/encoder.go @@ -452,7 +452,7 @@ func (g *Generator) genStructMarshaler(t reflect.Type) error { if !g.noStdMarshalers { fmt.Fprintln(g.out, "// MarshalJSON supports json.Marshaler interface") fmt.Fprintln(g.out, "func (v "+typ+") MarshalJSON() ([]byte, error) {") - fmt.Fprintln(g.out, " w := jwriter.Writer{}") + fmt.Fprintf(g.out, " w := jwriter.Writer{FloatFmt:\"%s\"}\n", g.floatFmt) fmt.Fprintln(g.out, " "+fname+"(&w, v)") fmt.Fprintln(g.out, " return w.Buffer.BuildBytes(), w.Error") fmt.Fprintln(g.out, "}") diff --git a/gen/generator.go b/gen/generator.go index 79f4d6f7..191c6de0 100644 --- a/gen/generator.go +++ b/gen/generator.go @@ -39,6 +39,7 @@ type Generator struct { fieldNamer FieldNamer simpleBytes bool skipMemberNameUnescaping bool + floatFmt string // package path to local alias map for tracking imports imports map[string]string @@ -133,6 +134,11 @@ func (g *Generator) SimpleBytes() { g.simpleBytes = true } +// SetFloatFmt sets the format for formatting float numbers using strconv. +func (g *Generator) SetFloatFmt(fmt string) { + g.floatFmt = fmt +} + // addTypes requests to generate encoding/decoding funcs for the given type. func (g *Generator) addType(t reflect.Type) { if g.typesSeen[t] { diff --git a/jwriter/writer.go b/jwriter/writer.go index 2c5b2010..2bc59cdf 100644 --- a/jwriter/writer.go +++ b/jwriter/writer.go @@ -25,6 +25,7 @@ type Writer struct { Error error Buffer buffer.Buffer NoEscapeHTML bool + FloatFmt string } // Size returns the size of the data that was written out. @@ -237,28 +238,36 @@ func (w *Writer) Int64Str(n int64) { func (w *Writer) Float32(n float32) { w.Buffer.EnsureSpace(20) - w.Buffer.Buf = strconv.AppendFloat(w.Buffer.Buf, float64(n), 'g', -1, 32) + w.Buffer.Buf = strconv.AppendFloat(w.Buffer.Buf, float64(n), w.floatFmt(), -1, 32) } func (w *Writer) Float32Str(n float32) { w.Buffer.EnsureSpace(20) w.Buffer.Buf = append(w.Buffer.Buf, '"') - w.Buffer.Buf = strconv.AppendFloat(w.Buffer.Buf, float64(n), 'g', -1, 32) + w.Buffer.Buf = strconv.AppendFloat(w.Buffer.Buf, float64(n), w.floatFmt(), -1, 32) w.Buffer.Buf = append(w.Buffer.Buf, '"') } func (w *Writer) Float64(n float64) { w.Buffer.EnsureSpace(20) - w.Buffer.Buf = strconv.AppendFloat(w.Buffer.Buf, n, 'g', -1, 64) + w.Buffer.Buf = strconv.AppendFloat(w.Buffer.Buf, n, w.floatFmt(), -1, 64) } func (w *Writer) Float64Str(n float64) { w.Buffer.EnsureSpace(20) w.Buffer.Buf = append(w.Buffer.Buf, '"') - w.Buffer.Buf = strconv.AppendFloat(w.Buffer.Buf, float64(n), 'g', -1, 64) + w.Buffer.Buf = strconv.AppendFloat(w.Buffer.Buf, float64(n), w.floatFmt(), -1, 64) w.Buffer.Buf = append(w.Buffer.Buf, '"') } +func (w *Writer) floatFmt() byte { + if len(w.FloatFmt) < 1 { + return 'g' + } + + return w.FloatFmt[0] +} + func (w *Writer) Bool(v bool) { w.Buffer.EnsureSpace(5) if v { diff --git a/tests/basic_test.go b/tests/basic_test.go index e18e515c..a37cadf2 100644 --- a/tests/basic_test.go +++ b/tests/basic_test.go @@ -25,6 +25,7 @@ var testCases = []struct { {&structsValue, structsString}, {&omitEmptyValue, omitEmptyString}, {&snakeStructValue, snakeStructString}, + {&floatFmtStruct, floatFmtString}, {&omitEmptyDefaultValue, omitEmptyDefaultString}, {&optsValue, optsString}, {&rawValue, rawString}, @@ -244,7 +245,7 @@ func TestNestedMarshaler(t *testing.T) { t.Errorf("Can't marshal NestedMarshaler: %s", err) } - s2 := NestedMarshaler { + s2 := NestedMarshaler{ Value: &StructWithMarshaler{}, } diff --git a/tests/float_format.go b/tests/float_format.go new file mode 100644 index 00000000..c47e0bb4 --- /dev/null +++ b/tests/float_format.go @@ -0,0 +1,13 @@ +package tests + +//easyjson:json +type FloatFmtStruct struct { + A float64 `json:"a"` + B float64 `json:"b"` +} + +var floatFmtStruct = FloatFmtStruct{ + A: 100000000, + B: 1000, +} +var floatFmtString = `{"a":100000000,"b":1000}`