gojay

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

commit ff18262ef2f5be4acf13cd9c83e2b7117a057baf
parent 4fc4320ce1c21434fb19f506945973e9189a341b
Author: Francois Parquet <francois.parquet@gmail.com>
Date:   Wed, 30 May 2018 22:27:34 +0800

Merge pull request #31 from m1ome/marshal-any

Added MarshalAny() support
Diffstat:
Mencode.go | 155++++++++++++++++++++++++++++++++++++++++++++-----------------------------------
Mencode_object_test.go | 16++++++++++++++++
2 files changed, 102 insertions(+), 69 deletions(-)

diff --git a/encode.go b/encode.go @@ -1,9 +1,10 @@ package gojay import ( - "fmt" "io" + "fmt" "reflect" + "encoding/json" ) // MarshalJSONObject returns the JSON encoding of v. @@ -97,74 +98,90 @@ func MarshalJSONArray(v MarshalerJSONArray) ([]byte, error) { // fmt.Println(b) // {"id":123456} // } func Marshal(v interface{}) ([]byte, error) { - switch vt := v.(type) { - case MarshalerJSONObject: - enc := BorrowEncoder(nil) - defer enc.Release() - return enc.encodeObject(vt) - case MarshalerJSONArray: - enc := BorrowEncoder(nil) - defer enc.Release() - return enc.encodeArray(vt) - case string: - enc := BorrowEncoder(nil) - defer enc.Release() - return enc.encodeString(vt) - case bool: - enc := BorrowEncoder(nil) - defer enc.Release() - return enc.encodeBool(vt) - case int: - enc := BorrowEncoder(nil) - defer enc.Release() - return enc.encodeInt(vt) - case int64: - enc := BorrowEncoder(nil) - defer enc.Release() - return enc.encodeInt64(vt) - case int32: - enc := BorrowEncoder(nil) - defer enc.Release() - return enc.encodeInt(int(vt)) - case int16: - enc := BorrowEncoder(nil) - defer enc.Release() - return enc.encodeInt(int(vt)) - case int8: - enc := BorrowEncoder(nil) - defer enc.Release() - return enc.encodeInt(int(vt)) - case uint64: - enc := BorrowEncoder(nil) - defer enc.Release() - return enc.encodeInt(int(vt)) - case uint32: - enc := BorrowEncoder(nil) - defer enc.Release() - return enc.encodeInt(int(vt)) - case uint16: - enc := BorrowEncoder(nil) - defer enc.Release() - return enc.encodeInt(int(vt)) - case uint8: - enc := BorrowEncoder(nil) - defer enc.Release() - return enc.encodeInt(int(vt)) - case float64: - enc := BorrowEncoder(nil) - defer enc.Release() - return enc.encodeFloat(vt) - case float32: - enc := BorrowEncoder(nil) - defer enc.Release() - return enc.encodeFloat32(vt) - case *EmbeddedJSON: - enc := BorrowEncoder(nil) - defer enc.Release() - return enc.encodeEmbeddedJSON(vt) - default: - return nil, InvalidMarshalError(fmt.Sprintf(invalidMarshalErrorMsg, reflect.TypeOf(vt).String())) - } + return marshal(v, false) +} + +// MarshalAny returns the JSON encoding of v. +// +// MarshalAny takes interface v and encodes it according to its type. +// Basic example with a string: +// b, err := gojay.Marshal("test") +// fmt.Println(b) // "test" +// +// If v implements Marshaler or Marshaler interface +// it will call the corresponding methods. +// +// If it cannot find any supported type it will be marshalled though default Go "json" package. +// Warning, this function can be slower, than a default "Marshal" +// +// type TestStruct struct { +// id int +// } +// +// func main() { +// test := &TestStruct{ +// id: 123456, +// } +// b, _ := gojay.Marshal(test) +// fmt.Println(b) // {"id": 123456} +// } +func MarshalAny(v interface{}) ([]byte, error) { + return marshal(v, true) +} + +func marshal(v interface{}, any bool) ([]byte, error) { + var ( + enc = BorrowEncoder(nil) + + buf []byte + err error + ) + + buf, err = func() ([]byte, error) { + switch vt := v.(type) { + case MarshalerJSONObject: + return enc.encodeObject(vt) + case MarshalerJSONArray: + return enc.encodeArray(vt) + case string: + return enc.encodeString(vt) + case bool: + return enc.encodeBool(vt) + case int: + return enc.encodeInt(vt) + case int64: + return enc.encodeInt64(vt) + case int32: + return enc.encodeInt(int(vt)) + case int16: + return enc.encodeInt(int(vt)) + case int8: + return enc.encodeInt(int(vt)) + case uint64: + return enc.encodeInt(int(vt)) + case uint32: + return enc.encodeInt(int(vt)) + case uint16: + return enc.encodeInt(int(vt)) + case uint8: + return enc.encodeInt(int(vt)) + case float64: + return enc.encodeFloat(vt) + case float32: + return enc.encodeFloat32(vt) + case *EmbeddedJSON: + return enc.encodeEmbeddedJSON(vt) + default: + if any { + return json.Marshal(vt) + } + + return nil, InvalidMarshalError(fmt.Sprintf(invalidMarshalErrorMsg, reflect.TypeOf(vt).String())) + } + } () + + enc.Release() + return buf, err } // MarshalerJSONObject is the interface to implement for struct to be encoded diff --git a/encode_object_test.go b/encode_object_test.go @@ -274,6 +274,22 @@ func TestEncoderObjectMarshalAPI(t *testing.T) { string(r), "Result of marshalling is different as the one expected") }) + t.Run("marshal-any-object", func(t *testing.T) { + test := struct { + Foo string + Bar int + }{ + "test", + 100, + } + r, err := MarshalAny(test) + assert.Nil(t, err, "Error should be nil") + assert.Equal( + t, + `{"Foo":"test","Bar":100}`, + string(r), + "Result of marshalling is different as the one expected") + }) } type TestObectOmitEmpty struct {