gojay

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

commit 3ebfcfb6372e874ff4cd2d6b905793acbdfd02cd
parent 346ac0d28bbe5a714bc66569339aa483a3585631
Author: Francois Parquet <francois.parquet@gmail.com>
Date:   Mon, 29 Oct 2018 22:33:56 +0800

Merge pull request #89 from francoispqt/doc/clean-up

Clean doc and reorganise code
Diffstat:
MREADME.md | 37+++++++++++++++++++++++++++++++++++++
Mdecode.go | 724++-----------------------------------------------------------------------------
Mdecode_array.go | 55++++++++++++++++++++++++++++++++++++++++++++-----------
Mdecode_bool.go | 44+++++++++++++++++++++++++++++++++++++++++++-
Mdecode_embedded_json.go | 6++++++
Adecode_example_test.go | 150+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Mdecode_interface.go | 19++++++++++++++++++-
Mdecode_number_float.go | 101+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--
Mdecode_number_int.go | 187++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++---
Mdecode_number_uint.go | 150++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++---
Mdecode_object.go | 63++++++++++++++++++++++++++++++++++++++++++++++++++++++---------
Mdecode_pool.go | 3++-
Mdecode_sqlnull.go | 82+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Mdecode_stream.go | 2+-
Mdecode_string.go | 40+++++++++++++++++++++++++++++++++++++++-
Mdecode_time.go | 17+++++++++++++++++
Mencode.go | 98++++++++++++++++++++-----------------------------------------------------------
Aencode_example_test.go | 65+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Mencode_interface.go | 18+++++++-----------
Mencode_interface_test.go | 4++--
Merrors.go | 2+-
Mgojay.go | 7+++++--
Agojay_example_test.go | 73+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
23 files changed, 1109 insertions(+), 838 deletions(-)

diff --git a/README.md b/README.md @@ -172,6 +172,21 @@ func (dec *gojay.Decoder) DecodeBool(v *bool) error func (dec *gojay.Decoder) DecodeString(v *string) error ``` +All DecodeXxx methods are used to decode top level JSON values. If you are decoding keys or items of a JSON object or array, don't use the Decode methods. + +Example: +```go +reader := strings.NewReader(`"John Doe"`) +dec := NewDecoder(reader) + +var str string +err := dec.DecodeString(&str) +if err != nil { + log.Fatal(err) +} + +fmt.Println(str) // gojay +``` ### Structs and Maps #### UnmarshalerJSONObject Interface @@ -287,6 +302,28 @@ func main() { } ``` +### Decode values methods +When decoding a JSON object of a JSON array using `UnmarshalerJSONObject` or `UnmarshalerJSONArray` interface, the `gojay.Decoder` provides dozens of methods to Decode multiple types. + +Non exhaustive list of methods available (to see all methods, check the godoc): +```go +dec.Int +dec.Int8 +dec.Int16 +dec.Int32 +dec.Int64 +dec.Uint8 +dec.Uint16 +dec.Uint32 +dec.Uint64 +dec.String +dec.Time +dec.Bool +dec.SQLNullString +dec.SQLNullInt64 +``` + + ## Encoding Encoding is done through two different API similar to standard `encoding/json`: diff --git a/decode.go b/decode.go @@ -1,10 +1,8 @@ package gojay import ( - "database/sql" "fmt" "io" - "time" ) // UnmarshalJSONArray parses the JSON-encoded data and stores the result in the value pointed to by v. @@ -52,23 +50,16 @@ func UnmarshalJSONObject(data []byte, v UnmarshalerJSONObject) error { } // Unmarshal parses the JSON-encoded data and stores the result in the value pointed to by v. -// If v is nil, not a pointer, or not an implementation of UnmarshalerJSONObject or UnmarshalerJSONArray +// If v is nil, not an implementation of UnmarshalerJSONObject or UnmarshalerJSONArray or not one of the following types: +// *string, **string, *int, **int, *int8, **int8, *int16, **int16, *int32, **int32, *int64, **int64, *uint8, **uint8, *uint16, **uint16, +// *uint32, **uint32, *uint64, **uint64, *float64, **float64, *float32, **float32, *bool, **bool // Unmarshal returns an InvalidUnmarshalError. // -// Unmarshal uses the inverse of the encodings that Marshal uses, allocating maps, slices, and pointers as necessary, with the following additional rules: -// To unmarshal JSON into a pointer, Unmarshal first handles the case of the JSON being the JSON literal null. -// In that case, Unmarshal sets the pointer to nil. -// Otherwise, Unmarshal unmarshals the JSON into the value pointed at by the pointer. -// If the pointer is nil, Unmarshal allocates a new value for it to point to. // -// To Unmarshal JSON into a struct, Unmarshal requires the struct to implement UnmarshalerJSONObject. -// -// To unmarshal a JSON array into a slice, Unmarshal requires the slice to implement UnmarshalerJSONArray. -// -// Unmarshal JSON does not allow yet to unmarshall an interface value // If a JSON value is not appropriate for a given target type, or if a JSON number // overflows the target type, Unmarshal skips that field and completes the unmarshaling as best it can. -// If no more serious errors are encountered, Unmarshal returns an UnmarshalTypeError describing the earliest such error. In any case, it's not guaranteed that all the remaining fields following the problematic one will be unmarshaled into the target object. +// If no more serious errors are encountered, Unmarshal returns an UnmarshalTypeError describing the earliest such error. +// In any case, it's not guaranteed that all the remaining fields following the problematic one will be unmarshaled into the target object. func Unmarshal(data []byte, v interface{}) error { var err error var dec *Decoder @@ -231,15 +222,13 @@ func Unmarshal(data []byte, v interface{}) error { return dec.err } -// UnmarshalerJSONObject is the interface to implement for a struct to be -// decoded +// UnmarshalerJSONObject is the interface to implement to decode a JSON Object. type UnmarshalerJSONObject interface { UnmarshalJSONObject(*Decoder, string) error NKeys() int } -// UnmarshalerJSONArray is the interface to implement for a slice or an array to be -// decoded +// UnmarshalerJSONArray is the interface to implement to decode a JSON Array. type UnmarshalerJSONArray interface { UnmarshalJSONArray(*Decoder) error } @@ -257,9 +246,12 @@ type Decoder struct { keysDone int } -// Decode reads the next JSON-encoded value from its input and stores it in the value pointed to by v. +// Decode reads the next JSON-encoded value from the decoder's input (io.Reader) and stores it in the value pointed to by v. // // See the documentation for Unmarshal for details about the conversion of JSON into a Go value. +// The differences between Decode and Unmarshal are: +// - Decode reads from an io.Reader in the Decoder, whereas Unmarshal reads from a []byte +// - Decode leaves to the user the option of borrowing and releasing a Decoder, whereas Unmarshal internally always borrows a Decoder and releases it when the unmarshaling is completed func (dec *Decoder) Decode(v interface{}) error { if dec.isPooled == 1 { panic(InvalidUsagePooledDecoderError("Invalid usage of pooled decoder")) @@ -335,700 +327,6 @@ func (dec *Decoder) Decode(v interface{}) error { return dec.err } -// ADD VALUES FUNCTIONS - -// AddInt decodes the next key to an *int. -// If next key value overflows int, an InvalidUnmarshalError error will be returned. -func (dec *Decoder) AddInt(v *int) error { - return dec.Int(v) -} - -// AddIntNull decodes the next key to an *int. -// If next key value overflows int, an InvalidUnmarshalError error will be returned. -// If a `null` is encountered, gojay does not change the value of the pointer. -func (dec *Decoder) AddIntNull(v **int) error { - return dec.IntNull(v) -} - -// AddInt8 decodes the next key to an *int. -// If next key value overflows int8, an InvalidUnmarshalError error will be returned. -func (dec *Decoder) AddInt8(v *int8) error { - return dec.Int8(v) -} - -// AddInt8Null decodes the next key to an *int. -// If next key value overflows int8, an InvalidUnmarshalError error will be returned. -// If a `null` is encountered, gojay does not change the value of the pointer. -func (dec *Decoder) AddInt8Null(v **int8) error { - return dec.Int8Null(v) -} - -// AddInt16 decodes the next key to an *int. -// If next key value overflows int16, an InvalidUnmarshalError error will be returned. -func (dec *Decoder) AddInt16(v *int16) error { - return dec.Int16(v) -} - -// AddInt16Null decodes the next key to an *int. -// If next key value overflows int16, an InvalidUnmarshalError error will be returned. -// If a `null` is encountered, gojay does not change the value of the pointer. -func (dec *Decoder) AddInt16Null(v **int16) error { - return dec.Int16Null(v) -} - -// AddInt32 decodes the next key to an *int. -// If next key value overflows int32, an InvalidUnmarshalError error will be returned. -func (dec *Decoder) AddInt32(v *int32) error { - return dec.Int32(v) -} - -// AddInt32Null decodes the next key to an *int. -// If next key value overflows int32, an InvalidUnmarshalError error will be returned. -// If a `null` is encountered, gojay does not change the value of the pointer. -func (dec *Decoder) AddInt32Null(v **int32) error { - return dec.Int32Null(v) -} - -// AddInt64 decodes the next key to an *int. -// If next key value overflows int64, an InvalidUnmarshalError error will be returned. -func (dec *Decoder) AddInt64(v *int64) error { - return dec.Int64(v) -} - -// AddInt64Null decodes the next key to an *int. -// If next key value overflows int64, an InvalidUnmarshalError error will be returned. -// If a `null` is encountered, gojay does not change the value of the pointer. -func (dec *Decoder) AddInt64Null(v **int64) error { - return dec.Int64Null(v) -} - -// AddUint8 decodes the next key to an *int. -// If next key value overflows uint8, an InvalidUnmarshalError error will be returned. -func (dec *Decoder) AddUint8(v *uint8) error { - return dec.Uint8(v) -} - -// AddUint8Null decodes the next key to an *int. -// If next key value overflows uint8, an InvalidUnmarshalError error will be returned. -// If a `null` is encountered, gojay does not change the value of the pointer. -func (dec *Decoder) AddUint8Null(v **uint8) error { - return dec.Uint8Null(v) -} - -// AddUint16 decodes the next key to an *int. -// If next key value overflows uint16, an InvalidUnmarshalError error will be returned. -func (dec *Decoder) AddUint16(v *uint16) error { - return dec.Uint16(v) -} - -// AddUint16Null decodes the next key to an *int. -// If next key value overflows uint16, an InvalidUnmarshalError error will be returned. -// If a `null` is encountered, gojay does not change the value of the pointer. -func (dec *Decoder) AddUint16Null(v **uint16) error { - return dec.Uint16Null(v) -} - -// AddUint32 decodes the next key to an *int. -// If next key value overflows uint32, an InvalidUnmarshalError error will be returned. -func (dec *Decoder) AddUint32(v *uint32) error { - return dec.Uint32(v) -} - -// AddUint32Null decodes the next key to an *int. -// If next key value overflows uint32, an InvalidUnmarshalError error will be returned. -// If a `null` is encountered, gojay does not change the value of the pointer. -func (dec *Decoder) AddUint32Null(v **uint32) error { - return dec.Uint32Null(v) -} - -// AddUint64 decodes the next key to an *int. -// If next key value overflows uint64, an InvalidUnmarshalError error will be returned. -func (dec *Decoder) AddUint64(v *uint64) error { - return dec.Uint64(v) -} - -// AddUint64Null decodes the next key to an *int. -// If next key value overflows uint64, an InvalidUnmarshalError error will be returned. -// If a `null` is encountered, gojay does not change the value of the pointer. -func (dec *Decoder) AddUint64Null(v **uint64) error { - return dec.Uint64Null(v) -} - -// AddFloat decodes the next key to a *float64. -// If next key value overflows float64, an InvalidUnmarshalError error will be returned. -func (dec *Decoder) AddFloat(v *float64) error { - return dec.Float64(v) -} - -// AddFloatNull decodes the next key to a *float64. -// If next key value overflows float64, an InvalidUnmarshalError error will be returned. -// If a `null` is encountered, gojay does not change the value of the pointer. -func (dec *Decoder) AddFloatNull(v **float64) error { - return dec.Float64Null(v) -} - -// AddFloat64 decodes the next key to a *float64. -// If next key value overflows float64, an InvalidUnmarshalError error will be returned. -func (dec *Decoder) AddFloat64(v *float64) error { - return dec.Float64(v) -} - -// AddFloat64Null decodes the next key to a *float64. -// If next key value overflows float64, an InvalidUnmarshalError error will be returned. -// If a `null` is encountered, gojay does not change the value of the pointer. -func (dec *Decoder) AddFloat64Null(v **float64) error { - return dec.Float64Null(v) -} - -// AddFloat32 decodes the next key to a *float64. -// If next key value overflows float64, an InvalidUnmarshalError error will be returned. -func (dec *Decoder) AddFloat32(v *float32) error { - return dec.Float32(v) -} - -// AddFloat32Null decodes the next key to a *float64. -// If next key value overflows float64, an InvalidUnmarshalError error will be returned. -// If a `null` is encountered, gojay does not change the value of the pointer. -func (dec *Decoder) AddFloat32Null(v **float32) error { - return dec.Float32Null(v) -} - -// AddBool decodes the next key to a *bool. -// If next key is neither null nor a JSON boolean, an InvalidUnmarshalError will be returned. -// If next key is null, bool will be false. -func (dec *Decoder) AddBool(v *bool) error { - return dec.Bool(v) -} - -// AddBoolNull decodes the next key to a *bool. -// If next key is neither null nor a JSON boolean, an InvalidUnmarshalError will be returned. -// If next key is null, bool will be false. -// If a `null` is encountered, gojay does not change the value of the pointer. -func (dec *Decoder) AddBoolNull(v **bool) error { - return dec.BoolNull(v) -} - -// AddString decodes the next key to a *string. -// If next key is not a JSON string nor null, InvalidUnmarshalError will be returned. -func (dec *Decoder) AddString(v *string) error { - return dec.String(v) -} - -// AddStringNull decodes the next key to a *string. -// If next key is not a JSON string nor null, InvalidUnmarshalError will be returned. -// If a `null` is encountered, gojay does not change the value of the pointer. -func (dec *Decoder) AddStringNull(v **string) error { - return dec.StringNull(v) -} - -// AddObject decodes the next key to a UnmarshalerJSONObject. -func (dec *Decoder) AddObject(v UnmarshalerJSONObject) error { - return dec.Object(v) -} - -// AddObjectNull decodes the next key to a UnmarshalerJSONObject. -func (dec *Decoder) AddObjectNull(v interface{}) error { - return dec.ObjectNull(v) -} - -// AddArray decodes the next key to a UnmarshalerJSONArray. -func (dec *Decoder) AddArray(v UnmarshalerJSONArray) error { - return dec.Array(v) -} - -// AddArrayNull decodes the next key to a UnmarshalerJSONArray. -func (dec *Decoder) AddArrayNull(v UnmarshalerJSONArray) error { - return dec.ArrayNull(v) -} - -// AddInterface decodes the next key to a interface{}. -func (dec *Decoder) AddInterface(v *interface{}) error { - return dec.Interface(v) -} - -// --- SQL types - -// AddSQLNullString decodes the next key to qn *sql.NullString -func (dec *Decoder) AddSQLNullString(v *sql.NullString) error { - return dec.SQLNullString(v) -} - -// SQLNullString decodes the next key to an *sql.NullString -func (dec *Decoder) SQLNullString(v *sql.NullString) error { - var b *string - if err := dec.StringNull(&b); err != nil { - return err - } - if b == nil { - v.Valid = false - } else { - v.String = *b - v.Valid = true - } - return nil -} - -// AddSQLNullInt64 decodes the next key to qn *sql.NullInt64 -func (dec *Decoder) AddSQLNullInt64(v *sql.NullInt64) error { - return dec.SQLNullInt64(v) -} - -// SQLNullInt64 decodes the next key to an *sql.NullInt64 -func (dec *Decoder) SQLNullInt64(v *sql.NullInt64) error { - var b *int64 - if err := dec.Int64Null(&b); err != nil { - return err - } - if b == nil { - v.Valid = false - } else { - v.Int64 = *b - v.Valid = true - } - return nil -} - -// AddSQLNullFloat64 decodes the next key to qn *sql.NullFloat64 -func (dec *Decoder) AddSQLNullFloat64(v *sql.NullFloat64) error { - return dec.SQLNullFloat64(v) -} - -// SQLNullFloat64 decodes the next key to an *sql.NullFloat64 -func (dec *Decoder) SQLNullFloat64(v *sql.NullFloat64) error { - var b *float64 - if err := dec.Float64Null(&b); err != nil { - return err - } - if b == nil { - v.Valid = false - } else { - v.Float64 = *b - v.Valid = true - } - return nil -} - -// AddSQLNullBool decodes the next key to an *sql.NullBool -func (dec *Decoder) AddSQLNullBool(v *sql.NullBool) error { - return dec.SQLNullBool(v) -} - -// SQLNullBool decodes the next key to an *sql.NullBool -func (dec *Decoder) SQLNullBool(v *sql.NullBool) error { - var b *bool - if err := dec.BoolNull(&b); err != nil { - return err - } - if b == nil { - v.Valid = false - } else { - v.Bool = *b - v.Valid = true - } - return nil -} - -// Int decodes the next key to an *int. -// If next key value overflows int, an InvalidUnmarshalError error will be returned. -func (dec *Decoder) Int(v *int) error { - err := dec.decodeInt(v) - if err != nil { - return err - } - dec.called |= 1 - return nil -} - -// IntNull decodes the next key to an *int. -// If next key value overflows int, an InvalidUnmarshalError error will be returned. -func (dec *Decoder) IntNull(v **int) error { - err := dec.decodeIntNull(v) - if err != nil { - return err - } - dec.called |= 1 - return nil -} - -// Int8 decodes the next key to an *int. -// If next key value overflows int8, an InvalidUnmarshalError error will be returned. -func (dec *Decoder) Int8(v *int8) error { - err := dec.decodeInt8(v) - if err != nil { - return err - } - dec.called |= 1 - return nil -} - -// Int8Null decodes the next key to an *int. -// If next key value overflows int8, an InvalidUnmarshalError error will be returned. -func (dec *Decoder) Int8Null(v **int8) error { - err := dec.decodeInt8Null(v) - if err != nil { - return err - } - dec.called |= 1 - return nil -} - -// Int16 decodes the next key to an *int. -// If next key value overflows int16, an InvalidUnmarshalError error will be returned. -func (dec *Decoder) Int16(v *int16) error { - err := dec.decodeInt16(v) - if err != nil { - return err - } - dec.called |= 1 - return nil -} - -// Int16Null decodes the next key to an *int. -// If next key value overflows int16, an InvalidUnmarshalError error will be returned. -func (dec *Decoder) Int16Null(v **int16) error { - err := dec.decodeInt16Null(v) - if err != nil { - return err - } - dec.called |= 1 - return nil -} - -// Int32 decodes the next key to an *int. -// If next key value overflows int32, an InvalidUnmarshalError error will be returned. -func (dec *Decoder) Int32(v *int32) error { - err := dec.decodeInt32(v) - if err != nil { - return err - } - dec.called |= 1 - return nil -} - -// Int32Null decodes the next key to an *int. -// If next key value overflows int32, an InvalidUnmarshalError error will be returned. -func (dec *Decoder) Int32Null(v **int32) error { - err := dec.decodeInt32Null(v) - if err != nil { - return err - } - dec.called |= 1 - return nil -} - -// Int64 decodes the next key to an *int. -// If next key value overflows int64, an InvalidUnmarshalError error will be returned. -func (dec *Decoder) Int64(v *int64) error { - err := dec.decodeInt64(v) - if err != nil { - return err - } - dec.called |= 1 - return nil -} - -// Int64Null decodes the next key to an *int. -// If next key value overflows int64, an InvalidUnmarshalError error will be returned. -func (dec *Decoder) Int64Null(v **int64) error { - err := dec.decodeInt64Null(v) - if err != nil { - return err - } - dec.called |= 1 - return nil -} - -// Uint8 decodes the next key to an *int. -// If next key value overflows uint8, an InvalidUnmarshalError error will be returned. -func (dec *Decoder) Uint8(v *uint8) error { - err := dec.decodeUint8(v) - if err != nil { - return err - } - dec.called |= 1 - return nil -} - -// Uint8Null decodes the next key to an *int. -// If next key value overflows uint8, an InvalidUnmarshalError error will be returned. -func (dec *Decoder) Uint8Null(v **uint8) error { - err := dec.decodeUint8Null(v) - if err != nil { - return err - } - dec.called |= 1 - return nil -} - -// Uint16 decodes the next key to an *int. -// If next key value overflows uint16, an InvalidUnmarshalError error will be returned. -func (dec *Decoder) Uint16(v *uint16) error { - err := dec.decodeUint16(v) - if err != nil { - return err - } - dec.called |= 1 - return nil -} - -// Uint16Null decodes the next key to an *int. -// If next key value overflows uint16, an InvalidUnmarshalError error will be returned. -func (dec *Decoder) Uint16Null(v **uint16) error { - err := dec.decodeUint16Null(v) - if err != nil { - return err - } - dec.called |= 1 - return nil -} - -// Uint32 decodes the next key to an *int. -// If next key value overflows uint32, an InvalidUnmarshalError error will be returned. -func (dec *Decoder) Uint32(v *uint32) error { - err := dec.decodeUint32(v) - if err != nil { - return err - } - dec.called |= 1 - return nil -} - -// Uint32Null decodes the next key to an *int. -// If next key value overflows uint32, an InvalidUnmarshalError error will be returned. -func (dec *Decoder) Uint32Null(v **uint32) error { - err := dec.decodeUint32Null(v) - if err != nil { - return err - } - dec.called |= 1 - return nil -} - -// Uint64 decodes the next key to an *int. -// If next key value overflows uint64, an InvalidUnmarshalError error will be returned. -func (dec *Decoder) Uint64(v *uint64) error { - err := dec.decodeUint64(v) - if err != nil { - return err - } - dec.called |= 1 - return nil -} - -// Uint64Null decodes the next key to an *int. -// If next key value overflows uint64, an InvalidUnmarshalError error will be returned. -func (dec *Decoder) Uint64Null(v **uint64) error { - err := dec.decodeUint64Null(v) - if err != nil { - return err - } - dec.called |= 1 - return nil -} - -// Float decodes the next key to a *float64. -// If next key value overflows float64, an InvalidUnmarshalError error will be returned. -func (dec *Decoder) Float(v *float64) error { - return dec.Float64(v) -} - -// FloatNull decodes the next key to a *float64. -// If next key value overflows float64, an InvalidUnmarshalError error will be returned. -func (dec *Decoder) FloatNull(v **float64) error { - return dec.Float64Null(v) -} - -// Float64 decodes the next key to a *float64. -// If next key value overflows float64, an InvalidUnmarshalError error will be returned. -func (dec *Decoder) Float64(v *float64) error { - err := dec.decodeFloat64(v) - if err != nil { - return err - } - dec.called |= 1 - return nil -} - -// Float64Null decodes the next key to a *float64. -// If next key value overflows float64, an InvalidUnmarshalError error will be returned. -func (dec *Decoder) Float64Null(v **float64) error { - err := dec.decodeFloat64Null(v) - if err != nil { - return err - } - dec.called |= 1 - return nil -} - -// Float32 decodes the next key to a *float64. -// If next key value overflows float64, an InvalidUnmarshalError error will be returned. -func (dec *Decoder) Float32(v *float32) error { - err := dec.decodeFloat32(v) - if err != nil { - return err - } - dec.called |= 1 - return nil -} - -// Float32Null decodes the next key to a *float64. -// If next key value overflows float64, an InvalidUnmarshalError error will be returned. -func (dec *Decoder) Float32Null(v **float32) error { - err := dec.decodeFloat32Null(v) - if err != nil { - return err - } - dec.called |= 1 - return nil -} - -// Bool decodes the next key to a *bool. -// If next key is neither null nor a JSON boolean, an InvalidUnmarshalError will be returned. -// If next key is null, bool will be false. -func (dec *Decoder) Bool(v *bool) error { - err := dec.decodeBool(v) - if err != nil { - return err - } - dec.called |= 1 - return nil -} - -// BoolNull decodes the next key to a *bool. -// If next key is neither null nor a JSON boolean, an InvalidUnmarshalError will be returned. -// If next key is null, bool will be false. -func (dec *Decoder) BoolNull(v **bool) error { - err := dec.decodeBoolNull(v) - if err != nil { - return err - } - dec.called |= 1 - return nil -} - -// String decodes the next key to a *string. -// If next key is not a JSON string nor null, InvalidUnmarshalError will be returned. -func (dec *Decoder) String(v *string) error { - err := dec.decodeString(v) - if err != nil { - return err - } - dec.called |= 1 - return nil -} - -// StringNull decodes the next key to a **string. -// If next key is not a JSON string nor null, InvalidUnmarshalError will be returned. -// If a `null` is encountered, gojay does not change the value of the pointer. -func (dec *Decoder) StringNull(v **string) error { - err := dec.decodeStringNull(v) - if err != nil { - return err - } - dec.called |= 1 - return nil -} - -// AddTime decodes the next key to a *time.Time with the given format -func (dec *Decoder) AddTime(v *time.Time, format string) error { - return dec.Time(v, format) -} - -// Time decodes the next key to a *time.Time with the given format -func (dec *Decoder) Time(v *time.Time, format string) error { - err := dec.decodeTime(v, format) - if err != nil { - return err - } - dec.called |= 1 - return nil -} - -// Object decodes the next key to a UnmarshalerJSONObject. -func (dec *Decoder) Object(value UnmarshalerJSONObject) error { - initialKeysDone := dec.keysDone - initialChild := dec.child - dec.keysDone = 0 - dec.called = 0 - dec.child |= 1 - newCursor, err := dec.decodeObject(value) - if err != nil { - return err - } - dec.cursor = newCursor - dec.keysDone = initialKeysDone - dec.child = initialChild - dec.called |= 1 - return nil -} - -// ObjectNull decodes the next key to a UnmarshalerJSONObject. -// v should be a pointer to an UnmarshalerJSONObject, -// if `null` value is encountered in JSON, it will leave the value v untouched, -// else it will create a new instance of the UnmarshalerJSONObject behind v. -func (dec *Decoder) ObjectNull(v interface{}) error { - initialKeysDone := dec.keysDone - initialChild := dec.child - dec.keysDone = 0 - dec.called = 0 - dec.child |= 1 - newCursor, err := dec.decodeObjectNull(v) - if err != nil { - return err - } - dec.cursor = newCursor - dec.keysDone = initialKeysDone - dec.child = initialChild - dec.called |= 1 - return nil -} - -// Array decodes the next key to a UnmarshalerJSONArray. -func (dec *Decoder) Array(v UnmarshalerJSONArray) error { - newCursor, err := dec.decodeArray(v) - if err != nil { - return err - } - dec.cursor = newCursor - dec.called |= 1 - return nil -} - -// ArrayNull decodes the next key to a UnmarshalerJSONArray. -// v should be a pointer to an UnmarshalerJSONArray, -// if `null` value is encountered in JSON, it will leave the value v untouched, -// else it will create a new instance of the UnmarshalerJSONArray behind v. -func (dec *Decoder) ArrayNull(v interface{}) error { - newCursor, err := dec.decodeArrayNull(v) - if err != nil { - return err - } - dec.cursor = newCursor - dec.called |= 1 - return nil -} - -// Interface decodes the next key to an interface{}. -func (dec *Decoder) Interface(value *interface{}) error { - err := dec.decodeInterface(value) - if err != nil { - return err - } - dec.called |= 1 - return nil -} - -// Array decodes the next key to a UnmarshalerJSONArray. -// func (dec *Decoder) ArrayNull(factory func() UnmarshalerJSONArray) error { -// newCursor, err := dec.decodeArrayNull(factory) -// if err != nil { -// return err -// } -// dec.cursor = newCursor -// dec.called |= 1 -// return nil -// } - // Non exported func isDigit(b byte) bool { diff --git a/decode_array.go b/decode_array.go @@ -2,16 +2,17 @@ package gojay import "reflect" -// DecodeArray reads the next JSON-encoded value from its input and stores it in the value pointed to by v. +// DecodeArray reads the next JSON-encoded value from the decoder's input (io.Reader) +// and stores it in the value pointed to by v. // // v must implement UnmarshalerJSONArray. // // See the documentation for Unmarshal for details about the conversion of JSON into a Go value. -func (dec *Decoder) DecodeArray(arr UnmarshalerJSONArray) error { +func (dec *Decoder) DecodeArray(v UnmarshalerJSONArray) error { if dec.isPooled == 1 { panic(InvalidUsagePooledDecoderError("Invalid usage of pooled decoder")) } - _, err := dec.decodeArray(arr) + _, err := dec.decodeArray(v) return err } func (dec *Decoder) decodeArray(arr UnmarshalerJSONArray) (int, error) { @@ -174,14 +175,9 @@ func (dec *Decoder) skipArray() (int, error) { return 0, dec.raiseInvalidJSONErr(dec.cursor) } -// DecodeArrayFunc is a custom func type implementing UnmarshalerJSONArray. -// Use it to cast a func(*Decoder) to Unmarshal an object. -// -// str := "" -// dec := gojay.NewDecoder(io.Reader) -// dec.DecodeArray(gojay.DecodeArrayFunc(func(dec *gojay.Decoder, k string) error { -// return dec.AddString(&str) -// })) +// DecodeArrayFunc is a func type implementing UnmarshalerJSONArray. +// Use it to cast a `func(*Decoder) error` to Unmarshal an array on the fly. + type DecodeArrayFunc func(*Decoder) error // UnmarshalJSONArray implements UnmarshalerJSONArray. @@ -193,3 +189,40 @@ func (f DecodeArrayFunc) UnmarshalJSONArray(dec *Decoder) error { func (f DecodeArrayFunc) IsNil() bool { return f == nil } + +// Add Values functions + +// AddArray decodes the JSON value within an object or an array to a UnmarshalerJSONArray. +func (dec *Decoder) AddArray(v UnmarshalerJSONArray) error { + return dec.Array(v) +} + +// AddArrayNull decodes the JSON value within an object or an array to a UnmarshalerJSONArray. +func (dec *Decoder) AddArrayNull(v UnmarshalerJSONArray) error { + return dec.ArrayNull(v) +} + +// Array decodes the JSON value within an object or an array to a UnmarshalerJSONArray. +func (dec *Decoder) Array(v UnmarshalerJSONArray) error { + newCursor, err := dec.decodeArray(v) + if err != nil { + return err + } + dec.cursor = newCursor + dec.called |= 1 + return nil +} + +// ArrayNull decodes the JSON value within an object or an array to a UnmarshalerJSONArray. +// v should be a pointer to an UnmarshalerJSONArray, +// if `null` value is encountered in JSON, it will leave the value v untouched, +// else it will create a new instance of the UnmarshalerJSONArray behind v. +func (dec *Decoder) ArrayNull(v interface{}) error { + newCursor, err := dec.decodeArrayNull(v) + if err != nil { + return err + } + dec.cursor = newCursor + dec.called |= 1 + return nil +} diff --git a/decode_bool.go b/decode_bool.go @@ -1,6 +1,7 @@ package gojay -// DecodeBool reads the next JSON-encoded value from its input and stores it in the boolean pointed to by v. +// DecodeBool reads the next JSON-encoded value from the decoder's input (io.Reader) +// and stores it in the boolean pointed to by v. // // See the documentation for Unmarshal for details about the conversion of JSON into a Go value. func (dec *Decoder) DecodeBool(v *bool) error { @@ -197,3 +198,44 @@ func (dec *Decoder) assertFalse() error { } return dec.raiseInvalidJSONErr(dec.cursor) } + +// Add Values functions + +// AddBool decodes the JSON value within an object or an array to a *bool. +// If next key is neither null nor a JSON boolean, an InvalidUnmarshalError will be returned. +// If next key is null, bool will be false. +func (dec *Decoder) AddBool(v *bool) error { + return dec.Bool(v) +} + +// AddBoolNull decodes the JSON value within an object or an array to a *bool. +// If next key is neither null nor a JSON boolean, an InvalidUnmarshalError will be returned. +// If next key is null, bool will be false. +// If a `null` is encountered, gojay does not change the value of the pointer. +func (dec *Decoder) AddBoolNull(v **bool) error { + return dec.BoolNull(v) +} + +// Bool decodes the JSON value within an object or an array to a *bool. +// If next key is neither null nor a JSON boolean, an InvalidUnmarshalError will be returned. +// If next key is null, bool will be false. +func (dec *Decoder) Bool(v *bool) error { + err := dec.decodeBool(v) + if err != nil { + return err + } + dec.called |= 1 + return nil +} + +// BoolNull decodes the JSON value within an object or an array to a *bool. +// If next key is neither null nor a JSON boolean, an InvalidUnmarshalError will be returned. +// If next key is null, bool will be false. +func (dec *Decoder) BoolNull(v **bool) error { + err := dec.decodeBoolNull(v) + if err != nil { + return err + } + dec.called |= 1 + return nil +} diff --git a/decode_embedded_json.go b/decode_embedded_json.go @@ -70,6 +70,12 @@ func (dec *Decoder) decodeEmbeddedJSON(ej *EmbeddedJSON) error { // AddEmbeddedJSON adds an EmbeddedsJSON to the value pointed by v. // It can be used to delay JSON decoding or precompute a JSON encoding. func (dec *Decoder) AddEmbeddedJSON(v *EmbeddedJSON) error { + return dec.EmbeddedJSON(v) +} + +// EmbeddedJSON adds an EmbeddedsJSON to the value pointed by v. +// It can be used to delay JSON decoding or precompute a JSON encoding. +func (dec *Decoder) EmbeddedJSON(v *EmbeddedJSON) error { err := dec.decodeEmbeddedJSON(v) if err != nil { return err diff --git a/decode_example_test.go b/decode_example_test.go @@ -0,0 +1,150 @@ +package gojay_test + +import ( + "fmt" + "log" + "strings" + + "github.com/francoispqt/gojay" +) + +func ExampleUnmarshal_string() { + data := []byte(`"gojay"`) + var str string + err := gojay.Unmarshal(data, &str) + if err != nil { + log.Fatal(err) + } + fmt.Println(str) // true +} + +func ExampleUnmarshal_bool() { + data := []byte(`true`) + var b bool + err := gojay.Unmarshal(data, &b) + if err != nil { + log.Fatal(err) + } + fmt.Println(b) // true +} + +func ExampleUnmarshal_invalidType() { + data := []byte(`"gojay"`) + someStruct := struct{}{} + err := gojay.Unmarshal(data, &someStruct) + + fmt.Println(err) // "Cannot unmarshal JSON to type '*struct{}'" +} + +func ExampleDecoder_Decode_string() { + var str string + dec := gojay.BorrowDecoder(strings.NewReader(`"gojay"`)) + err := dec.Decode(&str) + dec.Release() + + if err != nil { + log.Fatal(err) + } + fmt.Println(str) // "gojay" +} + +func ExampleDecodeObjectFunc() { + reader := strings.NewReader(`{ + "name": "John Doe", + "email": "john.doe@email.com" + }`) + dec := gojay.NewDecoder(reader) + + user := struct { + name string + email string + }{} + dec.DecodeObject(gojay.DecodeObjectFunc(func(dec *gojay.Decoder, k string) error { + switch k { + case "name": + return dec.String(&user.name) + case "email": + return dec.String(&user.email) + } + return nil + })) + + fmt.Printf("User\nname: %s\nemail: %s", user.name, user.email) + + // Output: + // User + // name: John Doe + // email: john.doe@email.com +} + +func ExampleDecodeArrayFunc() { + reader := strings.NewReader(`[ + "foo", + "bar" + ]`) + dec := gojay.NewDecoder(reader) + + strSlice := make([]string, 0) + err := dec.DecodeArray(gojay.DecodeArrayFunc(func(dec *gojay.Decoder) error { + var str string + if err := dec.AddString(&str); err != nil { + return err + } + strSlice = append(strSlice, str) + return nil + })) + + if err != nil { + log.Fatal(err) + } + + fmt.Print(strSlice) + // Output: + // [foo bar] +} + +func ExampleNewDecoder() { + reader := strings.NewReader(`"gojay"`) + dec := gojay.NewDecoder(reader) + + var str string + err := dec.DecodeString(&str) + if err != nil { + log.Fatal(err) + } + + fmt.Println(str) + // Output: + // gojay +} + +func ExampleBorrowDecoder() { + reader := strings.NewReader(`"gojay"`) + dec := gojay.BorrowDecoder(reader) + defer dec.Release() + + var str string + err := dec.DecodeString(&str) + if err != nil { + log.Fatal(err) + } + + fmt.Println(str) + // Output: + // gojay +} + +func ExampleDecoder_DecodeBool() { + reader := strings.NewReader(`true`) + dec := gojay.NewDecoder(reader) + + var b bool + err := dec.DecodeBool(&b) + if err != nil { + log.Fatal(err) + } + + fmt.Println(b) + // Output: + // true +} diff --git a/decode_interface.go b/decode_interface.go @@ -4,7 +4,7 @@ package gojay // the future it would be great to implement one here inside this repo import "encoding/json" -// DecodeInterface reads the next JSON-encoded value from its input and stores it in the value pointed to by i. +// DecodeInterface reads the next JSON-encoded value from the decoder's input (io.Reader) and stores it in the value pointed to by i. // // i must be an interface poiter func (dec *Decoder) DecodeInterface(i *interface{}) error { @@ -111,3 +111,20 @@ func (dec *Decoder) getObject() (start int, end int, err error) { err = dec.raiseInvalidJSONErr(dec.cursor) return } + +// Add Values functions + +// AddInterface decodes the JSON value within an object or an array to a interface{}. +func (dec *Decoder) AddInterface(v *interface{}) error { + return dec.Interface(v) +} + +// Interface decodes the JSON value within an object or an array to an interface{}. +func (dec *Decoder) Interface(value *interface{}) error { + err := dec.decodeInterface(value) + if err != nil { + return err + } + dec.called |= 1 + return nil +} diff --git a/decode_number_float.go b/decode_number_float.go @@ -1,6 +1,6 @@ package gojay -// DecodeFloat64 reads the next JSON-encoded value from its input and stores it in the float64 pointed to by v. +// DecodeFloat64 reads the next JSON-encoded value from the decoder's input (io.Reader) and stores it in the float64 pointed to by v. // // See the documentation for Unmarshal for details about the conversion of JSON into a Go value. func (dec *Decoder) DecodeFloat64(v *float64) error { @@ -208,7 +208,7 @@ func (dec *Decoder) getFloat() (float64, error) { return float64(dec.atoi64(start, end)), nil } -// DecodeFloat32 reads the next JSON-encoded value from its input and stores it in the float32 pointed to by v. +// DecodeFloat32 reads the next JSON-encoded value from the decoder's input (io.Reader) and stores it in the float32 pointed to by v. // // See the documentation for Unmarshal for details about the conversion of JSON into a Go value. func (dec *Decoder) DecodeFloat32(v *float32) error { @@ -417,3 +417,100 @@ func (dec *Decoder) getFloat32() (float32, error) { } return float32(dec.atoi32(start, end)), nil } + +// Add Values functions + +// AddFloat decodes the JSON value within an object or an array to a *float64. +// If next key value overflows float64, an InvalidUnmarshalError error will be returned. +func (dec *Decoder) AddFloat(v *float64) error { + return dec.Float64(v) +} + +// AddFloatNull decodes the JSON value within an object or an array to a *float64. +// If next key value overflows float64, an InvalidUnmarshalError error will be returned. +// If a `null` is encountered, gojay does not change the value of the pointer. +func (dec *Decoder) AddFloatNull(v **float64) error { + return dec.Float64Null(v) +} + +// AddFloat64 decodes the JSON value within an object or an array to a *float64. +// If next key value overflows float64, an InvalidUnmarshalError error will be returned. +func (dec *Decoder) AddFloat64(v *float64) error { + return dec.Float64(v) +} + +// AddFloat64Null decodes the JSON value within an object or an array to a *float64. +// If next key value overflows float64, an InvalidUnmarshalError error will be returned. +// If a `null` is encountered, gojay does not change the value of the pointer. +func (dec *Decoder) AddFloat64Null(v **float64) error { + return dec.Float64Null(v) +} + +// AddFloat32 decodes the JSON value within an object or an array to a *float64. +// If next key value overflows float64, an InvalidUnmarshalError error will be returned. +func (dec *Decoder) AddFloat32(v *float32) error { + return dec.Float32(v) +} + +// AddFloat32Null decodes the JSON value within an object or an array to a *float64. +// If next key value overflows float64, an InvalidUnmarshalError error will be returned. +// If a `null` is encountered, gojay does not change the value of the pointer. +func (dec *Decoder) AddFloat32Null(v **float32) error { + return dec.Float32Null(v) +} + +// Float decodes the JSON value within an object or an array to a *float64. +// If next key value overflows float64, an InvalidUnmarshalError error will be returned. +func (dec *Decoder) Float(v *float64) error { + return dec.Float64(v) +} + +// FloatNull decodes the JSON value within an object or an array to a *float64. +// If next key value overflows float64, an InvalidUnmarshalError error will be returned. +func (dec *Decoder) FloatNull(v **float64) error { + return dec.Float64Null(v) +} + +// Float64 decodes the JSON value within an object or an array to a *float64. +// If next key value overflows float64, an InvalidUnmarshalError error will be returned. +func (dec *Decoder) Float64(v *float64) error { + err := dec.decodeFloat64(v) + if err != nil { + return err + } + dec.called |= 1 + return nil +} + +// Float64Null decodes the JSON value within an object or an array to a *float64. +// If next key value overflows float64, an InvalidUnmarshalError error will be returned. +func (dec *Decoder) Float64Null(v **float64) error { + err := dec.decodeFloat64Null(v) + if err != nil { + return err + } + dec.called |= 1 + return nil +} + +// Float32 decodes the JSON value within an object or an array to a *float64. +// If next key value overflows float64, an InvalidUnmarshalError error will be returned. +func (dec *Decoder) Float32(v *float32) error { + err := dec.decodeFloat32(v) + if err != nil { + return err + } + dec.called |= 1 + return nil +} + +// Float32Null decodes the JSON value within an object or an array to a *float64. +// If next key value overflows float64, an InvalidUnmarshalError error will be returned. +func (dec *Decoder) Float32Null(v **float32) error { + err := dec.decodeFloat32Null(v) + if err != nil { + return err + } + dec.called |= 1 + return nil +} diff --git a/decode_number_int.go b/decode_number_int.go @@ -5,7 +5,7 @@ import ( "math" ) -// DecodeInt reads the next JSON-encoded value from its input and stores it in the int pointed to by v. +// DecodeInt reads the next JSON-encoded value from the decoder's input (io.Reader) and stores it in the int pointed to by v. // // See the documentation for Unmarshal for details about the conversion of JSON into a Go value. func (dec *Decoder) DecodeInt(v *int) error { @@ -112,7 +112,7 @@ func (dec *Decoder) decodeIntNull(v **int) error { return dec.raiseInvalidJSONErr(dec.cursor) } -// DecodeInt16 reads the next JSON-encoded value from its input and stores it in the int16 pointed to by v. +// DecodeInt16 reads the next JSON-encoded value from the decoder's input (io.Reader) and stores it in the int16 pointed to by v. // // See the documentation for Unmarshal for details about the conversion of JSON into a Go value. func (dec *Decoder) DecodeInt16(v *int16) error { @@ -344,7 +344,7 @@ func (dec *Decoder) getInt16WithExp(init int16) (int16, error) { return 0, dec.raiseInvalidJSONErr(dec.cursor) } -// DecodeInt8 reads the next JSON-encoded value from its input and stores it in the int8 pointed to by v. +// DecodeInt8 reads the next JSON-encoded value from the decoder's input (io.Reader) and stores it in the int8 pointed to by v. // // See the documentation for Unmarshal for details about the conversion of JSON into a Go value. func (dec *Decoder) DecodeInt8(v *int8) error { @@ -575,7 +575,7 @@ func (dec *Decoder) getInt8WithExp(init int8) (int8, error) { return 0, dec.raiseInvalidJSONErr(dec.cursor) } -// DecodeInt32 reads the next JSON-encoded value from its input and stores it in the int32 pointed to by v. +// DecodeInt32 reads the next JSON-encoded value from the decoder's input (io.Reader) and stores it in the int32 pointed to by v. // // See the documentation for Unmarshal for details about the conversion of JSON into a Go value. func (dec *Decoder) DecodeInt32(v *int32) error { @@ -805,7 +805,7 @@ func (dec *Decoder) getInt32WithExp(init int32) (int32, error) { return 0, dec.raiseInvalidJSONErr(dec.cursor) } -// DecodeInt64 reads the next JSON-encoded value from its input and stores it in the int64 pointed to by v. +// DecodeInt64 reads the next JSON-encoded value from the decoder's input (io.Reader) and stores it in the int64 pointed to by v. // // See the documentation for Unmarshal for details about the conversion of JSON into a Go value. func (dec *Decoder) DecodeInt64(v *int64) error { @@ -1158,3 +1158,180 @@ func (dec *Decoder) atoi8(start, end int) int8 { } return val } + +// Add Values functions + +// AddInt decodes the JSON value within an object or an array to an *int. +// If next key value overflows int, an InvalidUnmarshalError error will be returned. +func (dec *Decoder) AddInt(v *int) error { + return dec.Int(v) +} + +// AddIntNull decodes the JSON value within an object or an array to an *int. +// If next key value overflows int, an InvalidUnmarshalError error will be returned. +// If a `null` is encountered, gojay does not change the value of the pointer. +func (dec *Decoder) AddIntNull(v **int) error { + return dec.IntNull(v) +} + +// AddInt8 decodes the JSON value within an object or an array to an *int. +// If next key value overflows int8, an InvalidUnmarshalError error will be returned. +func (dec *Decoder) AddInt8(v *int8) error { + return dec.Int8(v) +} + +// AddInt8Null decodes the JSON value within an object or an array to an *int. +// If next key value overflows int8, an InvalidUnmarshalError error will be returned. +// If a `null` is encountered, gojay does not change the value of the pointer. +func (dec *Decoder) AddInt8Null(v **int8) error { + return dec.Int8Null(v) +} + +// AddInt16 decodes the JSON value within an object or an array to an *int. +// If next key value overflows int16, an InvalidUnmarshalError error will be returned. +func (dec *Decoder) AddInt16(v *int16) error { + return dec.Int16(v) +} + +// AddInt16Null decodes the JSON value within an object or an array to an *int. +// If next key value overflows int16, an InvalidUnmarshalError error will be returned. +// If a `null` is encountered, gojay does not change the value of the pointer. +func (dec *Decoder) AddInt16Null(v **int16) error { + return dec.Int16Null(v) +} + +// AddInt32 decodes the JSON value within an object or an array to an *int. +// If next key value overflows int32, an InvalidUnmarshalError error will be returned. +func (dec *Decoder) AddInt32(v *int32) error { + return dec.Int32(v) +} + +// AddInt32Null decodes the JSON value within an object or an array to an *int. +// If next key value overflows int32, an InvalidUnmarshalError error will be returned. +// If a `null` is encountered, gojay does not change the value of the pointer. +func (dec *Decoder) AddInt32Null(v **int32) error { + return dec.Int32Null(v) +} + +// AddInt64 decodes the JSON value within an object or an array to an *int. +// If next key value overflows int64, an InvalidUnmarshalError error will be returned. +func (dec *Decoder) AddInt64(v *int64) error { + return dec.Int64(v) +} + +// AddInt64Null decodes the JSON value within an object or an array to an *int. +// If next key value overflows int64, an InvalidUnmarshalError error will be returned. +// If a `null` is encountered, gojay does not change the value of the pointer. +func (dec *Decoder) AddInt64Null(v **int64) error { + return dec.Int64Null(v) +} + +// Int decodes the JSON value within an object or an array to an *int. +// If next key value overflows int, an InvalidUnmarshalError error will be returned. +func (dec *Decoder) Int(v *int) error { + err := dec.decodeInt(v) + if err != nil { + return err + } + dec.called |= 1 + return nil +} + +// IntNull decodes the JSON value within an object or an array to an *int. +// If next key value overflows int, an InvalidUnmarshalError error will be returned. +func (dec *Decoder) IntNull(v **int) error { + err := dec.decodeIntNull(v) + if err != nil { + return err + } + dec.called |= 1 + return nil +} + +// Int8 decodes the JSON value within an object or an array to an *int. +// If next key value overflows int8, an InvalidUnmarshalError error will be returned. +func (dec *Decoder) Int8(v *int8) error { + err := dec.decodeInt8(v) + if err != nil { + return err + } + dec.called |= 1 + return nil +} + +// Int8Null decodes the JSON value within an object or an array to an *int. +// If next key value overflows int8, an InvalidUnmarshalError error will be returned. +func (dec *Decoder) Int8Null(v **int8) error { + err := dec.decodeInt8Null(v) + if err != nil { + return err + } + dec.called |= 1 + return nil +} + +// Int16 decodes the JSON value within an object or an array to an *int. +// If next key value overflows int16, an InvalidUnmarshalError error will be returned. +func (dec *Decoder) Int16(v *int16) error { + err := dec.decodeInt16(v) + if err != nil { + return err + } + dec.called |= 1 + return nil +} + +// Int16Null decodes the JSON value within an object or an array to an *int. +// If next key value overflows int16, an InvalidUnmarshalError error will be returned. +func (dec *Decoder) Int16Null(v **int16) error { + err := dec.decodeInt16Null(v) + if err != nil { + return err + } + dec.called |= 1 + return nil +} + +// Int32 decodes the JSON value within an object or an array to an *int. +// If next key value overflows int32, an InvalidUnmarshalError error will be returned. +func (dec *Decoder) Int32(v *int32) error { + err := dec.decodeInt32(v) + if err != nil { + return err + } + dec.called |= 1 + return nil +} + +// Int32Null decodes the JSON value within an object or an array to an *int. +// If next key value overflows int32, an InvalidUnmarshalError error will be returned. +func (dec *Decoder) Int32Null(v **int32) error { + err := dec.decodeInt32Null(v) + if err != nil { + return err + } + dec.called |= 1 + return nil +} + +// Int64 decodes the JSON value within an object or an array to an *int. +// If next key value overflows int64, an InvalidUnmarshalError error will be returned. +func (dec *Decoder) Int64(v *int64) error { + err := dec.decodeInt64(v) + if err != nil { + return err + } + dec.called |= 1 + return nil +} + +// Int64Null decodes the JSON value within an object or an array to an *int. +// If next key value overflows int64, an InvalidUnmarshalError error will be returned. +func (dec *Decoder) Int64Null(v **int64) error { + err := dec.decodeInt64Null(v) + if err != nil { + return err + } + dec.called |= 1 + return nil +} diff --git a/decode_number_uint.go b/decode_number_uint.go @@ -4,7 +4,7 @@ import ( "math" ) -// DecodeUint8 reads the next JSON-encoded value from its input and stores it in the uint8 pointed to by v. +// DecodeUint8 reads the next JSON-encoded value from the decoder's input (io.Reader) and stores it in the uint8 pointed to by v. // // See the documentation for Unmarshal for details about the conversion of JSON into a Go value. func (dec *Decoder) DecodeUint8(v *uint8) error { @@ -116,7 +116,7 @@ func (dec *Decoder) getUint8() (uint8, error) { return dec.atoui8(start, end), nil } -// DecodeUint16 reads the next JSON-encoded value from its input and stores it in the uint16 pointed to by v. +// DecodeUint16 reads the next JSON-encoded value from the decoder's input (io.Reader) and stores it in the uint16 pointed to by v. // // See the documentation for Unmarshal for details about the conversion of JSON into a Go value. func (dec *Decoder) DecodeUint16(v *uint16) error { @@ -228,7 +228,7 @@ func (dec *Decoder) getUint16() (uint16, error) { return dec.atoui16(start, end), nil } -// DecodeUint32 reads the next JSON-encoded value from its input and stores it in the uint32 pointed to by v. +// DecodeUint32 reads the next JSON-encoded value from the decoder's input (io.Reader) and stores it in the uint32 pointed to by v. // // See the documentation for Unmarshal for details about the conversion of JSON into a Go value. func (dec *Decoder) DecodeUint32(v *uint32) error { @@ -340,7 +340,7 @@ func (dec *Decoder) getUint32() (uint32, error) { return dec.atoui32(start, end), nil } -// DecodeUint64 reads the next JSON-encoded value from its input and stores it in the uint64 pointed to by v. +// DecodeUint64 reads the next JSON-encoded value from the decoder's input (io.Reader) and stores it in the uint64 pointed to by v. // // See the documentation for Unmarshal for details about the conversion of JSON into a Go value. func (dec *Decoder) DecodeUint64(v *uint64) error { @@ -571,3 +571,145 @@ func (dec *Decoder) atoui8(start, end int) uint8 { } return val } + +// Add Values functions + +// AddUint8 decodes the JSON value within an object or an array to an *int. +// If next key value overflows uint8, an InvalidUnmarshalError error will be returned. +func (dec *Decoder) AddUint8(v *uint8) error { + return dec.Uint8(v) +} + +// AddUint8Null decodes the JSON value within an object or an array to an *int. +// If next key value overflows uint8, an InvalidUnmarshalError error will be returned. +// If a `null` is encountered, gojay does not change the value of the pointer. +func (dec *Decoder) AddUint8Null(v **uint8) error { + return dec.Uint8Null(v) +} + +// AddUint16 decodes the JSON value within an object or an array to an *int. +// If next key value overflows uint16, an InvalidUnmarshalError error will be returned. +func (dec *Decoder) AddUint16(v *uint16) error { + return dec.Uint16(v) +} + +// AddUint16Null decodes the JSON value within an object or an array to an *int. +// If next key value overflows uint16, an InvalidUnmarshalError error will be returned. +// If a `null` is encountered, gojay does not change the value of the pointer. +func (dec *Decoder) AddUint16Null(v **uint16) error { + return dec.Uint16Null(v) +} + +// AddUint32 decodes the JSON value within an object or an array to an *int. +// If next key value overflows uint32, an InvalidUnmarshalError error will be returned. +func (dec *Decoder) AddUint32(v *uint32) error { + return dec.Uint32(v) +} + +// AddUint32Null decodes the JSON value within an object or an array to an *int. +// If next key value overflows uint32, an InvalidUnmarshalError error will be returned. +// If a `null` is encountered, gojay does not change the value of the pointer. +func (dec *Decoder) AddUint32Null(v **uint32) error { + return dec.Uint32Null(v) +} + +// AddUint64 decodes the JSON value within an object or an array to an *int. +// If next key value overflows uint64, an InvalidUnmarshalError error will be returned. +func (dec *Decoder) AddUint64(v *uint64) error { + return dec.Uint64(v) +} + +// AddUint64Null decodes the JSON value within an object or an array to an *int. +// If next key value overflows uint64, an InvalidUnmarshalError error will be returned. +// If a `null` is encountered, gojay does not change the value of the pointer. +func (dec *Decoder) AddUint64Null(v **uint64) error { + return dec.Uint64Null(v) +} + +// Uint8 decodes the JSON value within an object or an array to an *int. +// If next key value overflows uint8, an InvalidUnmarshalError error will be returned. +func (dec *Decoder) Uint8(v *uint8) error { + err := dec.decodeUint8(v) + if err != nil { + return err + } + dec.called |= 1 + return nil +} + +// Uint8Null decodes the JSON value within an object or an array to an *int. +// If next key value overflows uint8, an InvalidUnmarshalError error will be returned. +func (dec *Decoder) Uint8Null(v **uint8) error { + err := dec.decodeUint8Null(v) + if err != nil { + return err + } + dec.called |= 1 + return nil +} + +// Uint16 decodes the JSON value within an object or an array to an *int. +// If next key value overflows uint16, an InvalidUnmarshalError error will be returned. +func (dec *Decoder) Uint16(v *uint16) error { + err := dec.decodeUint16(v) + if err != nil { + return err + } + dec.called |= 1 + return nil +} + +// Uint16Null decodes the JSON value within an object or an array to an *int. +// If next key value overflows uint16, an InvalidUnmarshalError error will be returned. +func (dec *Decoder) Uint16Null(v **uint16) error { + err := dec.decodeUint16Null(v) + if err != nil { + return err + } + dec.called |= 1 + return nil +} + +// Uint32 decodes the JSON value within an object or an array to an *int. +// If next key value overflows uint32, an InvalidUnmarshalError error will be returned. +func (dec *Decoder) Uint32(v *uint32) error { + err := dec.decodeUint32(v) + if err != nil { + return err + } + dec.called |= 1 + return nil +} + +// Uint32Null decodes the JSON value within an object or an array to an *int. +// If next key value overflows uint32, an InvalidUnmarshalError error will be returned. +func (dec *Decoder) Uint32Null(v **uint32) error { + err := dec.decodeUint32Null(v) + if err != nil { + return err + } + dec.called |= 1 + return nil +} + +// Uint64 decodes the JSON value within an object or an array to an *int. +// If next key value overflows uint64, an InvalidUnmarshalError error will be returned. +func (dec *Decoder) Uint64(v *uint64) error { + err := dec.decodeUint64(v) + if err != nil { + return err + } + dec.called |= 1 + return nil +} + +// Uint64Null decodes the JSON value within an object or an array to an *int. +// If next key value overflows uint64, an InvalidUnmarshalError error will be returned. +func (dec *Decoder) Uint64Null(v **uint64) error { + err := dec.decodeUint64Null(v) + if err != nil { + return err + } + dec.called |= 1 + return nil +} diff --git a/decode_object.go b/decode_object.go @@ -5,7 +5,7 @@ import ( "unsafe" ) -// DecodeObject reads the next JSON-encoded value from its input and stores it in the value pointed to by v. +// DecodeObject reads the next JSON-encoded value from the decoder's input (io.Reader) and stores it in the value pointed to by v. // // v must implement UnmarshalerJSONObject. // @@ -341,14 +341,8 @@ func (dec *Decoder) skipData() error { return dec.raiseInvalidJSONErr(dec.cursor) } -// DecodeObjectFunc is a custom func type implementing UnmarshalerJSONObject. -// Use it to cast a func(*Decoder) to Unmarshal an object. -// -// str := "" -// dec := gojay.NewDecoder(io.Reader) -// dec.DecodeObject(gojay.DecodeObjectFunc(func(dec *gojay.Decoder, k string) error { -// return dec.AddString(&str) -// })) +// DecodeObjectFunc is a func type implementing UnmarshalerJSONObject. +// Use it to cast a `func(*Decoder, k string) error` to Unmarshal an object on the fly. type DecodeObjectFunc func(*Decoder, string) error // UnmarshalJSONObject implements UnmarshalerJSONObject. @@ -360,3 +354,54 @@ func (f DecodeObjectFunc) UnmarshalJSONObject(dec *Decoder, k string) error { func (f DecodeObjectFunc) NKeys() int { return 0 } + +// Add Values functions + +// AddObject decodes the JSON value within an object or an array to a UnmarshalerJSONObject. +func (dec *Decoder) AddObject(v UnmarshalerJSONObject) error { + return dec.Object(v) +} + +// AddObjectNull decodes the JSON value within an object or an array to a UnmarshalerJSONObject. +func (dec *Decoder) AddObjectNull(v interface{}) error { + return dec.ObjectNull(v) +} + +// Object decodes the JSON value within an object or an array to a UnmarshalerJSONObject. +func (dec *Decoder) Object(value UnmarshalerJSONObject) error { + initialKeysDone := dec.keysDone + initialChild := dec.child + dec.keysDone = 0 + dec.called = 0 + dec.child |= 1 + newCursor, err := dec.decodeObject(value) + if err != nil { + return err + } + dec.cursor = newCursor + dec.keysDone = initialKeysDone + dec.child = initialChild + dec.called |= 1 + return nil +} + +// ObjectNull decodes the JSON value within an object or an array to a UnmarshalerJSONObject. +// v should be a pointer to an UnmarshalerJSONObject, +// if `null` value is encountered in JSON, it will leave the value v untouched, +// else it will create a new instance of the UnmarshalerJSONObject behind v. +func (dec *Decoder) ObjectNull(v interface{}) error { + initialKeysDone := dec.keysDone + initialChild := dec.child + dec.keysDone = 0 + dec.called = 0 + dec.child |= 1 + newCursor, err := dec.decodeObjectNull(v) + if err != nil { + return err + } + dec.cursor = newCursor + dec.keysDone = initialKeysDone + dec.child = initialChild + dec.called |= 1 + return nil +} diff --git a/decode_pool.go b/decode_pool.go @@ -35,7 +35,8 @@ func newDecoderPool() interface{} { // BorrowDecoder borrows a Decoder from the pool. // It takes an io.Reader implementation as data input. -// It initiates the done channel returned by Done(). +// +// In order to benefit from the pool, a borrowed decoder must be released after usage. func BorrowDecoder(r io.Reader) *Decoder { return borrowDecoder(r, 512) } diff --git a/decode_sqlnull.go b/decode_sqlnull.go @@ -73,3 +73,85 @@ func (dec *Decoder) decodeSQLNullBool(v *sql.NullBool) error { v.Valid = true return nil } + +// Add Values functions + +// AddSQLNullString decodes the JSON value within an object or an array to qn *sql.NullString +func (dec *Decoder) AddSQLNullString(v *sql.NullString) error { + return dec.SQLNullString(v) +} + +// SQLNullString decodes the JSON value within an object or an array to an *sql.NullString +func (dec *Decoder) SQLNullString(v *sql.NullString) error { + var b *string + if err := dec.StringNull(&b); err != nil { + return err + } + if b == nil { + v.Valid = false + } else { + v.String = *b + v.Valid = true + } + return nil +} + +// AddSQLNullInt64 decodes the JSON value within an object or an array to qn *sql.NullInt64 +func (dec *Decoder) AddSQLNullInt64(v *sql.NullInt64) error { + return dec.SQLNullInt64(v) +} + +// SQLNullInt64 decodes the JSON value within an object or an array to an *sql.NullInt64 +func (dec *Decoder) SQLNullInt64(v *sql.NullInt64) error { + var b *int64 + if err := dec.Int64Null(&b); err != nil { + return err + } + if b == nil { + v.Valid = false + } else { + v.Int64 = *b + v.Valid = true + } + return nil +} + +// AddSQLNullFloat64 decodes the JSON value within an object or an array to qn *sql.NullFloat64 +func (dec *Decoder) AddSQLNullFloat64(v *sql.NullFloat64) error { + return dec.SQLNullFloat64(v) +} + +// SQLNullFloat64 decodes the JSON value within an object or an array to an *sql.NullFloat64 +func (dec *Decoder) SQLNullFloat64(v *sql.NullFloat64) error { + var b *float64 + if err := dec.Float64Null(&b); err != nil { + return err + } + if b == nil { + v.Valid = false + } else { + v.Float64 = *b + v.Valid = true + } + return nil +} + +// AddSQLNullBool decodes the JSON value within an object or an array to an *sql.NullBool +func (dec *Decoder) AddSQLNullBool(v *sql.NullBool) error { + return dec.SQLNullBool(v) +} + +// SQLNullBool decodes the JSON value within an object or an array to an *sql.NullBool +func (dec *Decoder) SQLNullBool(v *sql.NullBool) error { + var b *bool + if err := dec.BoolNull(&b); err != nil { + return err + } + if b == nil { + v.Valid = false + } else { + v.Bool = *b + v.Valid = true + } + return nil +} diff --git a/decode_stream.go b/decode_stream.go @@ -26,7 +26,7 @@ type StreamDecoder struct { deadline *time.Time } -// DecodeStream reads the next line delimited JSON-encoded value from its input and stores it in the value pointed to by c. +// DecodeStream reads the next line delimited JSON-encoded value from the decoder's input (io.Reader) and stores it in the value pointed to by c. // // c must implement UnmarshalerStream. Ideally c is a channel. See example for implementation. // diff --git a/decode_string.go b/decode_string.go @@ -4,7 +4,7 @@ import ( "unsafe" ) -// DecodeString reads the next JSON-encoded value from its input and stores it in the string pointed to by v. +// DecodeString reads the next JSON-encoded value from the decoder's input (io.Reader) and stores it in the string pointed to by v. // // See the documentation for Unmarshal for details about the conversion of JSON into a Go value. func (dec *Decoder) DecodeString(v *string) error { @@ -213,3 +213,41 @@ func (dec *Decoder) skipString() error { } return dec.raiseInvalidJSONErr(len(dec.data) - 1) } + +// Add Values functions + +// AddString decodes the JSON value within an object or an array to a *string. +// If next key is not a JSON string nor null, InvalidUnmarshalError will be returned. +func (dec *Decoder) AddString(v *string) error { + return dec.String(v) +} + +// AddStringNull decodes the JSON value within an object or an array to a *string. +// If next key is not a JSON string nor null, InvalidUnmarshalError will be returned. +// If a `null` is encountered, gojay does not change the value of the pointer. +func (dec *Decoder) AddStringNull(v **string) error { + return dec.StringNull(v) +} + +// String decodes the JSON value within an object or an array to a *string. +// If next key is not a JSON string nor null, InvalidUnmarshalError will be returned. +func (dec *Decoder) String(v *string) error { + err := dec.decodeString(v) + if err != nil { + return err + } + dec.called |= 1 + return nil +} + +// StringNull decodes the JSON value within an object or an array to a **string. +// If next key is not a JSON string nor null, InvalidUnmarshalError will be returned. +// If a `null` is encountered, gojay does not change the value of the pointer. +func (dec *Decoder) StringNull(v **string) error { + err := dec.decodeStringNull(v) + if err != nil { + return err + } + dec.called |= 1 + return nil +} diff --git a/decode_time.go b/decode_time.go @@ -34,3 +34,20 @@ func (dec *Decoder) decodeTime(v *time.Time, format string) error { *v = tt return nil } + +// Add Values functions + +// AddTime decodes the JSON value within an object or an array to a *time.Time with the given format +func (dec *Decoder) AddTime(v *time.Time, format string) error { + return dec.Time(v, format) +} + +// Time decodes the JSON value within an object or an array to a *time.Time with the given format +func (dec *Decoder) Time(v *time.Time, format string) error { + err := dec.decodeTime(v, format) + if err != nil { + return err + } + dec.called |= 1 + return nil +} diff --git a/encode.go b/encode.go @@ -4,45 +4,14 @@ import ( "encoding/json" "fmt" "io" - "reflect" ) var nullBytes = []byte("null") -// MarshalJSONObject returns the JSON encoding of v. +// MarshalJSONArray returns the JSON encoding of v, an implementation of MarshalerJSONArray. // -// It takes a struct implementing Marshaler to a JSON slice of byte -// it returns a slice of bytes and an error. -// Example with an Marshaler: -// type TestStruct struct { -// id int -// } -// func (s *TestStruct) MarshalJSONObject(enc *gojay.Encoder) { -// enc.AddIntKey("id", s.id) -// } -// func (s *TestStruct) IsNil() bool { -// return s == nil -// } // -// func main() { -// test := &TestStruct{ -// id: 123456, -// } -// b, _ := gojay.Marshal(test) -// fmt.Println(b) // {"id":123456} -// } -func MarshalJSONObject(v MarshalerJSONObject) ([]byte, error) { - enc := BorrowEncoder(nil) - enc.grow(512) - defer enc.Release() - return enc.encodeObject(v) -} - -// MarshalJSONArray returns the JSON encoding of v. -// -// It takes an array or a slice implementing Marshaler to a JSON slice of byte -// it returns a slice of bytes and an error. -// Example with an Marshaler: +// Example: // type TestSlice []*TestStruct // // func (t TestSlice) MarshalJSONArray(enc *Encoder) { @@ -69,64 +38,47 @@ func MarshalJSONArray(v MarshalerJSONArray) ([]byte, error) { return enc.buf, nil } -// Marshal returns the JSON encoding of v. -// -// Marshal takes interface v and encodes it according to its type. -// Basic example with a string: -// b, err := gojay.Marshal("test") -// fmt.Println(b) // "test" +// MarshalJSONObject returns the JSON encoding of v, an implementation of MarshalerJSONObject. // -// If v implements Marshaler or Marshaler interface -// it will call the corresponding methods. -// -// If a struct, slice, or array is passed and does not implement these interfaces -// it will return a a non nil InvalidUnmarshalError error. -// Example with an Marshaler: -// type TestStruct struct { +// Example: +// type Object struct { // id int // } -// func (s *TestStruct) MarshalJSONObject(enc *gojay.Encoder) { -// enc.AddIntKey("id", s.id) +// func (s *Object) MarshalJSONObject(enc *gojay.Encoder) { +// enc.IntKey("id", s.id) // } -// func (s *TestStruct) IsNil() bool { +// func (s *Object) IsNil() bool { // return s == nil // } // // func main() { -// test := &TestStruct{ +// test := &Object{ // id: 123456, // } // b, _ := gojay.Marshal(test) // fmt.Println(b) // {"id":123456} // } +func MarshalJSONObject(v MarshalerJSONObject) ([]byte, error) { + enc := BorrowEncoder(nil) + enc.grow(512) + defer enc.Release() + return enc.encodeObject(v) +} + +// Marshal returns the JSON encoding of v. +// +// If v is nil, not an implementation MarshalerJSONObject or MarshalerJSONArray or not one of the following types: +// string, int, int8, int16, int32, int64, uint8, uint16, uint32, uint64, float64, float32, bool +// Marshal returns an InvalidMarshalError. func Marshal(v interface{}) ([]byte, error) { 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} -// } +// If v is nil, not an implementation MarshalerJSONObject or MarshalerJSONArray or not one of the following types: +// string, int, int8, int16, int32, int64, uint8, uint16, uint32, uint64, float64, float32, bool +// MarshalAny falls back to "json/encoding" package to marshal the value. func MarshalAny(v interface{}) ([]byte, error) { return marshal(v, true) } @@ -178,7 +130,7 @@ func marshal(v interface{}, any bool) ([]byte, error) { return json.Marshal(vt) } - return nil, InvalidMarshalError(fmt.Sprintf(invalidMarshalErrorMsg, reflect.TypeOf(vt).String())) + return nil, InvalidMarshalError(fmt.Sprintf(invalidMarshalErrorMsg, vt)) } }() diff --git a/encode_example_test.go b/encode_example_test.go @@ -0,0 +1,65 @@ +package gojay_test + +import ( + "fmt" + "log" + "os" + + "github.com/francoispqt/gojay" +) + +func ExampleMarshal_string() { + str := "gojay" + d, err := gojay.Marshal(str) + if err != nil { + log.Fatal(err) + } + fmt.Println(string(d)) // "gojay" +} + +func ExampleMarshal_bool() { + b := true + d, err := gojay.Marshal(b) + if err != nil { + log.Fatal(err) + } + fmt.Println(string(d)) // true +} + +func ExampleNewEncoder() { + enc := gojay.BorrowEncoder(os.Stdout) + + var str = "gojay" + err := enc.EncodeString(str) + if err != nil { + log.Fatal(err) + } + // Output: + // "gojay" +} + +func ExampleBorrowEncoder() { + enc := gojay.BorrowEncoder(os.Stdout) + defer enc.Release() + + var str = "gojay" + err := enc.EncodeString(str) + if err != nil { + log.Fatal(err) + } + // Output: + // "gojay" +} + +func ExampleEncoder_EncodeString() { + enc := gojay.BorrowEncoder(os.Stdout) + defer enc.Release() + + var str = "gojay" + err := enc.EncodeString(str) + if err != nil { + log.Fatal(err) + } + // Output: + // "gojay" +} diff --git a/encode_interface.go b/encode_interface.go @@ -2,7 +2,6 @@ package gojay import ( "fmt" - "reflect" ) // Encode encodes a value to JSON. @@ -45,7 +44,7 @@ func (enc *Encoder) Encode(v interface{}) error { case *EmbeddedJSON: return enc.EncodeEmbeddedJSON(vt) default: - return InvalidMarshalError(fmt.Sprintf(invalidMarshalErrorMsg, reflect.TypeOf(vt).String())) + return InvalidMarshalError(fmt.Sprintf(invalidMarshalErrorMsg, vt)) } } @@ -81,9 +80,8 @@ func (enc *Encoder) AddInterface(value interface{}) { case float32: enc.AddFloat32(vt) default: - t := reflect.TypeOf(vt) - if t != nil { - enc.err = InvalidMarshalError(fmt.Sprintf(invalidMarshalErrorMsg, t.String())) + if vt != nil { + enc.err = InvalidMarshalError(fmt.Sprintf(invalidMarshalErrorMsg, vt)) return } return @@ -124,9 +122,8 @@ func (enc *Encoder) AddInterfaceKey(key string, value interface{}) { case float32: enc.AddFloat32Key(key, vt) default: - t := reflect.TypeOf(vt) - if t != nil { - enc.err = InvalidMarshalError(fmt.Sprintf(invalidMarshalErrorMsg, t.String())) + if vt != nil { + enc.err = InvalidMarshalError(fmt.Sprintf(invalidMarshalErrorMsg, vt)) return } return @@ -167,9 +164,8 @@ func (enc *Encoder) AddInterfaceKeyOmitEmpty(key string, v interface{}) { case float32: enc.AddFloat32KeyOmitEmpty(key, vt) default: - t := reflect.TypeOf(vt) - if t != nil { - enc.err = InvalidMarshalError(fmt.Sprintf(invalidMarshalErrorMsg, t.String())) + if vt != nil { + enc.err = InvalidMarshalError(fmt.Sprintf(invalidMarshalErrorMsg, vt)) return } return diff --git a/encode_interface_test.go b/encode_interface_test.go @@ -2,7 +2,6 @@ package gojay import ( "fmt" - "reflect" "strings" "testing" @@ -127,7 +126,8 @@ var encoderTestCases = []struct { expectations: func(t *testing.T, b string, err error) { assert.NotNil(t, err, "err should be nil") assert.IsType(t, InvalidMarshalError(""), err, "err should be of type InvalidMarshalError") - assert.Equal(t, fmt.Sprintf(invalidMarshalErrorMsg, reflect.TypeOf(&struct{}{}).String()), err.Error(), "err message should be equal to invalidMarshalErrorMsg") + var s = struct{}{} + assert.Equal(t, fmt.Sprintf(invalidMarshalErrorMsg, &s), err.Error(), "err message should be equal to invalidMarshalErrorMsg") }, }, } diff --git a/errors.go b/errors.go @@ -49,7 +49,7 @@ func (dec *Decoder) makeInvalidUnmarshalErr(v interface{}) error { ) } -const invalidMarshalErrorMsg = "Invalid type %s provided to Marshal" +const invalidMarshalErrorMsg = "Invalid type %T provided to Marshal" // InvalidMarshalError is a type representing an error returned when // Encoding did not find the proper way to encode diff --git a/gojay.go b/gojay.go @@ -1,7 +1,10 @@ -// Package gojay Package implements encoding and decoding of JSON as defined in RFC 7159. +// Package gojay implements encoding and decoding of JSON as defined in RFC 7159. // The mapping between JSON and Go values is described // in the documentation for the Marshal and Unmarshal functions. // // It aims at performance and usability by relying on simple interfaces -// to decode or encode structures, slices, arrays and even channels. +// to decode and encode structures, slices, arrays and even channels. +// +// On top of the simple interfaces to implement, gojay provides lots of helpers to decode and encode +// multiple of different types natively such as bit.Int, sql.NullString or time.Time package gojay diff --git a/gojay_example_test.go b/gojay_example_test.go @@ -0,0 +1,73 @@ +package gojay_test + +import ( + "fmt" + "log" + "os" + "strings" + + "github.com/francoispqt/gojay" +) + +type User struct { + ID int + Name string + Email string +} + +func (u *User) UnmarshalJSONObject(dec *gojay.Decoder, k string) error { + switch k { + case "id": + return dec.Int(&u.ID) + case "name": + return dec.String(&u.Name) + case "email": + return dec.String(&u.Email) + } + return nil +} + +func (u *User) NKeys() int { + return 3 +} + +func (u *User) MarshalJSONObject(enc *gojay.Encoder) { + enc.IntKey("id", u.ID) + enc.StringKey("name", u.Name) + enc.StringKey("email", u.Email) +} + +func (u *User) IsNil() bool { + return u == nil +} + +func Example_decodeEncode() { + reader := strings.NewReader(`{ + "id": 1, + "name": "John Doe", + "email": "john.doe@email.com" + }`) + dec := gojay.BorrowDecoder(reader) + defer dec.Release() + + u := &User{} + err := dec.Decode(u) + if err != nil { + log.Fatal(err) + } + + enc := gojay.BorrowEncoder(os.Stdout) + err = enc.Encode(u) + if err != nil { + log.Fatal(err) + } + + fmt.Printf("\nUser ID: %d\nName: %s\nEmail: %s\n", + u.ID, u.Name, u.Email) + + // Output: + // {"id":1,"name":"John Doe","email":"john.doe@email.com"} + // User ID: 1 + // Name: John Doe + // Email: john.doe@email.com +}