Merge pull request #49 from Shmel1k/feature/slice_in_body

Added possibility to marshal slice into body without it's identifier
This commit is contained in:
Victor Starodub
2016-07-18 17:43:05 +04:00
committed by GitHub
5 changed files with 103 additions and 21 deletions
+41 -7
View File
@@ -13,7 +13,7 @@ import (
// Target this byte size for initial slice allocation to reduce garbage collection.
const minSliceBytes = 64
func (g *Generator) getStructDecoderName(t reflect.Type) string {
func (g *Generator) getDecoderName(t reflect.Type) string {
return g.functionName("decode_", t)
}
@@ -47,7 +47,7 @@ var primitiveStringDecoders = map[reflect.Kind]string{
reflect.Uint64: "in.Uint64Str()",
}
// genTypeDecoder generates decoding code for the type t.
// genTypeDecoder generates decoding code for the type t, but uses unmarshaler interface if implemented by t.
func (g *Generator) genTypeDecoder(t reflect.Type, out string, tags fieldTags, indent int) error {
ws := strings.Repeat(" ", indent)
@@ -65,6 +65,13 @@ func (g *Generator) genTypeDecoder(t reflect.Type, out string, tags fieldTags, i
return nil
}
err := g.genTypeDecoderNoCheck(t, out, tags, indent)
return err
}
// genTypeDecoderNoCheck generates decoding code for the type t.
func (g *Generator) genTypeDecoderNoCheck(t reflect.Type, out string, tags fieldTags, indent int) error {
ws := strings.Repeat(" ", indent)
// Check whether type is primitive, needs to be done after interface check.
if dec := primitiveStringDecoders[t.Kind()]; dec != "" && tags.asString {
fmt.Fprintln(g.out, ws+out+" = "+g.getType(t)+"("+dec+")")
@@ -101,7 +108,7 @@ func (g *Generator) genTypeDecoder(t reflect.Type, out string, tags fieldTags, i
fmt.Fprintln(g.out, ws+"in.Delim(']')")
case reflect.Struct:
dec := g.getStructDecoderName(t)
dec := g.getDecoderName(t)
g.addType(t)
fmt.Fprintln(g.out, ws+dec+"(in, &"+out+")")
@@ -260,12 +267,39 @@ func getStructFields(t reflect.Type) ([]reflect.StructField, error) {
return mergeStructFields(efields, fields), nil
}
func (g *Generator) genDecoder(t reflect.Type) error {
switch t.Kind() {
case reflect.Slice:
return g.genSliceDecoder(t)
default:
return g.genStructDecoder(t)
}
}
func (g *Generator) genSliceDecoder(t reflect.Type) error {
if t.Kind() != reflect.Slice {
return fmt.Errorf("cannot generate encoder/decoder for %v, not a slice type", t)
}
fname := g.getDecoderName(t)
typ := g.getType(t)
fmt.Fprintln(g.out, "func "+fname+"(in *jlexer.Lexer, out *"+typ+") {")
err := g.genTypeDecoderNoCheck(t, "*out", fieldTags{}, 1)
if err != nil {
return err
}
fmt.Fprintln(g.out, "}")
return nil
}
func (g *Generator) genStructDecoder(t reflect.Type) error {
if t.Kind() != reflect.Struct {
return fmt.Errorf("cannot generate encoder/decoder for %v, not a struct type", t)
}
fname := g.getStructDecoderName(t)
fname := g.getDecoderName(t)
typ := g.getType(t)
fmt.Fprintln(g.out, "func "+fname+"(in *jlexer.Lexer, out *"+typ+") {")
@@ -326,11 +360,11 @@ func (g *Generator) genStructDecoder(t reflect.Type) error {
}
func (g *Generator) genStructUnmarshaller(t reflect.Type) error {
if t.Kind() != reflect.Struct {
return fmt.Errorf("cannot generate encoder/decoder for %v, not a struct type", t)
if t.Kind() != reflect.Struct && t.Kind() != reflect.Slice {
return fmt.Errorf("cannot generate encoder/decoder for %v, not a struct/slice type", t)
}
fname := g.getStructDecoderName(t)
fname := g.getDecoderName(t)
typ := g.getType(t)
if !g.noStdMarshalers {
+44 -10
View File
@@ -10,7 +10,7 @@ import (
"github.com/mailru/easyjson"
)
func (g *Generator) getStructEncoderName(t reflect.Type) string {
func (g *Generator) getEncoderName(t reflect.Type) string {
return g.functionName("encode_", t)
}
@@ -79,7 +79,7 @@ func parseFieldTags(f reflect.StructField) fieldTags {
return ret
}
// genTypeEncoder generates code that encodes in of type t into the writer.
// genTypeEncoder generates code that encodes in of type t into the writer, but uses marshaler interface if implemented by t.
func (g *Generator) genTypeEncoder(t reflect.Type, in string, tags fieldTags, indent int) error {
ws := strings.Repeat(" ", indent)
@@ -95,6 +95,14 @@ func (g *Generator) genTypeEncoder(t reflect.Type, in string, tags fieldTags, in
return nil
}
err := g.genTypeEncoderNoCheck(t, in, tags, indent)
return err
}
// genTypeEncoderNoCheck generates code that encodes in of type t into the writer.
func (g *Generator) genTypeEncoderNoCheck(t reflect.Type, in string, tags fieldTags, indent int) error {
ws := strings.Repeat(" ", indent)
// Check whether type is primitive, needs to be done after interface check.
if enc := primitiveStringEncoders[t.Kind()]; enc != "" && tags.asString {
fmt.Fprintf(g.out, ws+enc+"\n", in)
@@ -122,7 +130,7 @@ func (g *Generator) genTypeEncoder(t reflect.Type, in string, tags fieldTags, in
fmt.Fprintln(g.out, ws+"out.RawByte(']')")
case reflect.Struct:
enc := g.getStructEncoderName(t)
enc := g.getEncoderName(t)
g.addType(t)
fmt.Fprintln(g.out, ws+enc+"(out, "+in+")")
@@ -224,12 +232,38 @@ func (g *Generator) genStructFieldEncoder(t reflect.Type, f reflect.StructField)
return nil
}
func (g *Generator) genStructEncoder(t reflect.Type) error {
if t.Kind() != reflect.Struct {
return fmt.Errorf("cannot generate encoder/decoder for %v, not a struct type", t)
func (g *Generator) genEncoder(t reflect.Type) error {
switch t.Kind() {
case reflect.Slice:
return g.genSliceEncoder(t)
default:
return g.genStructEncoder(t)
}
}
func (g *Generator) genSliceEncoder(t reflect.Type) error {
if t.Kind() != reflect.Slice {
return fmt.Errorf("cannot generate encoder/decoder for %v, not a slice type", t)
}
fname := g.getStructEncoderName(t)
fname := g.getEncoderName(t)
typ := g.getType(t)
fmt.Fprintln(g.out, "func "+fname+"(out *jwriter.Writer, in "+typ+") {")
err := g.genTypeEncoderNoCheck(t, "in", fieldTags{}, 1)
if err != nil {
return err
}
fmt.Fprintln(g.out, "}")
return nil
}
func (g *Generator) genStructEncoder(t reflect.Type) error {
if t.Kind() != reflect.Struct {
return fmt.Errorf("cannot generate encoder/decoder for %v, not a struct type")
}
fname := g.getEncoderName(t)
typ := g.getType(t)
fmt.Fprintln(g.out, "func "+fname+"(out *jwriter.Writer, in "+typ+") {")
@@ -254,11 +288,11 @@ func (g *Generator) genStructEncoder(t reflect.Type) error {
}
func (g *Generator) genStructMarshaller(t reflect.Type) error {
if t.Kind() != reflect.Struct {
return fmt.Errorf("cannot generate encoder/decoder for %v, not a struct type", t)
if t.Kind() != reflect.Struct && t.Kind() != reflect.Slice {
return fmt.Errorf("cannot generate encoder/decoder for %v, not a struct/slice type", t)
}
fname := g.getStructEncoderName(t)
fname := g.getEncoderName(t)
typ := g.getType(t)
if !g.noStdMarshalers {
+2 -2
View File
@@ -175,10 +175,10 @@ func (g *Generator) Run(out io.Writer) error {
g.typesUnseen = g.typesUnseen[:len(g.typesUnseen)-1]
g.typesSeen[t] = true
if err := g.genStructDecoder(t); err != nil {
if err := g.genDecoder(t); err != nil {
return err
}
if err := g.genStructEncoder(t); err != nil {
if err := g.genEncoder(t); err != nil {
return err
}
+3 -2
View File
@@ -32,6 +32,7 @@ var testCases = []struct {
{&excludedFieldValue, excludedFieldString},
{&mapsValue, mapsString},
{&deepNestValue, deepNestString},
{&IntsValue, IntsString},
}
func TestMarshal(t *testing.T) {
@@ -107,7 +108,7 @@ func TestParseNull(t *testing.T) {
var testSpecialCases = []struct {
EncodedString string
Value string
Value string
}{
{`"Username \u003cuser@example.com\u003e"`, `Username <user@example.com>`},
{`"Username\ufffd"`, "Username\xc5"},
@@ -129,4 +130,4 @@ func TestSpecialCases(t *testing.T) {
t.Errorf("[%d] Encoded() = %+v; want %+v", i, got, test.EncodedString)
}
}
}
}
+13
View File
@@ -246,6 +246,8 @@ type Structs struct {
AnonymousSlice []struct{ V int }
AnonymousPtrSlice []*struct{ V int }
Slice []string
unexported bool
}
@@ -282,6 +284,8 @@ var structsValue = Structs{
AnonymousSlice: []struct{ V int }{{1}, {2}},
AnonymousPtrSlice: []*struct{ V int }{{3}, {4}},
Slice: []string{"test5", "test6"},
}
var structsString = "{" +
@@ -306,6 +310,8 @@ var structsString = "{" +
`"AnonymousSlice":[{"V":1},{"V":2}],` +
`"AnonymousPtrSlice":[{"V":3},{"V":4}],` +
`"Slice":["test5","test6"],` +
// Embedded fields go last.
`"V":"subp",` +
`"Value":"test"` +
@@ -526,6 +532,13 @@ var deepNestString = `{` +
`"NamedStringSlice":["value4","value5"]` +
`}`
//easyjson:json
type Ints []int
var IntsValue = Ints{1, 2, 3, 4, 5}
var IntsString = `[1,2,3,4,5]`
type RequiredOptionalStruct struct {
FirstName string `json:"first_name,required"`
Lastname string `json:"last_name"`