commit c4759855a621fbf631847cf81265b17c0e1e6990
parent 2f9e3aba9ce5220ddae44a60ef8760c1b4b25440
Author: francoispqt <francois@parquet.ninja>
Date: Tue, 1 May 2018 13:20:38 +0800
simplify encode API filling enc.err when error encountered
Diffstat:
14 files changed, 114 insertions(+), 111 deletions(-)
diff --git a/decode.go b/decode.go
@@ -149,15 +149,15 @@ type UnmarshalerArray interface {
// A Decoder reads and decodes JSON values from an input stream.
type Decoder struct {
+ r io.Reader
data []byte
+ err error
+ isPooled byte
+ called byte
+ child byte
cursor int
length int
keysDone int
- called byte
- child byte
- err error
- r io.Reader
- isPooled byte
}
// Decode reads the next JSON-encoded value from its input and stores it in the value pointed to by v.
diff --git a/decode_stream_test.go b/decode_stream_test.go
@@ -338,7 +338,7 @@ func (r *StreamReader) Write() {
for r.writeCounter < t {
time.Sleep(time.Duration(r.writeCounter*100) * time.Millisecond)
currentChunkStart := (chunkSize) * r.writeCounter
- lastWrite := currentChunkStart + chunkSize
+ lastWrite = currentChunkStart + chunkSize
r.readChan <- r.data[currentChunkStart:lastWrite]
carry = l - lastWrite
r.writeCounter++
diff --git a/encode.go b/encode.go
@@ -96,38 +96,27 @@ func MarshalArray(v MarshalerArray) ([]byte, error) {
// fmt.Println(b) // {"id":123456}
// }
func Marshal(v interface{}) ([]byte, error) {
- var b []byte
- var err error = InvalidTypeError("Unknown type to Marshal")
switch vt := v.(type) {
case MarshalerObject:
enc := BorrowEncoder(nil)
- enc.writeByte('{')
- vt.MarshalObject(enc)
- enc.writeByte('}')
- b = enc.buf
defer enc.Release()
- return b, nil
+ return enc.encodeObject(vt)
case MarshalerArray:
enc := BorrowEncoder(nil)
- enc.writeByte('[')
- vt.MarshalArray(enc)
- enc.writeByte(']')
- b = enc.buf
defer enc.Release()
- return b, nil
+ return enc.encodeArray(vt)
case string:
enc := BorrowEncoder(nil)
- b, err = enc.encodeString(vt)
defer enc.Release()
+ return enc.encodeString(vt)
case bool:
enc := BorrowEncoder(nil)
- err = enc.AddBool(vt)
- b = enc.buf
defer enc.Release()
+ return enc.encodeBool(vt)
case int:
enc := BorrowEncoder(nil)
- b, err = enc.encodeInt(vt)
defer enc.Release()
+ return enc.encodeInt(vt)
case int64:
enc := BorrowEncoder(nil)
defer enc.Release()
@@ -158,8 +147,8 @@ func Marshal(v interface{}) ([]byte, error) {
return enc.encodeInt(int(vt))
case uint8:
enc := BorrowEncoder(nil)
- b, err = enc.encodeInt(int(vt))
defer enc.Release()
+ return enc.encodeInt(int(vt))
case float64:
enc := BorrowEncoder(nil)
defer enc.Release()
@@ -169,9 +158,8 @@ func Marshal(v interface{}) ([]byte, error) {
defer enc.Release()
return enc.encodeFloat32(vt)
default:
- err = InvalidMarshalError(fmt.Sprintf(invalidMarshalErrorMsg, reflect.TypeOf(vt).String()))
+ return nil, InvalidMarshalError(fmt.Sprintf(invalidMarshalErrorMsg, reflect.TypeOf(vt).String()))
}
- return b, err
}
// MarshalerObject is the interface to implement for struct to be encoded
diff --git a/encode_array.go b/encode_array.go
@@ -18,12 +18,12 @@ func (enc *Encoder) encodeArray(v MarshalerArray) ([]byte, error) {
enc.writeByte('[')
v.MarshalArray(enc)
enc.writeByte(']')
- return enc.buf, nil
+ return enc.buf, enc.err
}
// AddArray adds an array or slice to be encoded, must be used inside a slice or array encoding (does not encode a key)
// value must implement Marshaler
-func (enc *Encoder) AddArray(value MarshalerArray) error {
+func (enc *Encoder) AddArray(value MarshalerArray) {
r, ok := enc.getPreviousRune()
if ok && r != '[' {
enc.writeByte(',')
@@ -31,12 +31,11 @@ func (enc *Encoder) AddArray(value MarshalerArray) error {
enc.writeByte('[')
value.MarshalArray(enc)
enc.writeByte(']')
- return nil
}
// AddArrayKey adds an array or slice to be encoded, must be used inside an object as it will encode a key
// value must implement Marshaler
-func (enc *Encoder) AddArrayKey(key string, value MarshalerArray) error {
+func (enc *Encoder) AddArrayKey(key string, value MarshalerArray) {
// grow to avoid allocs (length of key/value + quotes)
r, ok := enc.getPreviousRune()
if ok && r != '[' && r != '{' {
@@ -47,5 +46,4 @@ func (enc *Encoder) AddArrayKey(key string, value MarshalerArray) error {
enc.writeBytes(objKeyArr)
value.MarshalArray(enc)
enc.writeByte(']')
- return nil
}
diff --git a/encode_bool.go b/encode_bool.go
@@ -23,11 +23,11 @@ func (enc *Encoder) encodeBool(v bool) ([]byte, error) {
} else {
enc.writeString("false")
}
- return enc.buf, nil
+ return enc.buf, enc.err
}
// AddBool adds a bool to be encoded, must be used inside a slice or array encoding (does not encode a key)
-func (enc *Encoder) AddBool(value bool) error {
+func (enc *Encoder) AddBool(value bool) {
r, ok := enc.getPreviousRune()
if ok && r != '[' {
enc.writeByte(',')
@@ -37,11 +37,10 @@ func (enc *Encoder) AddBool(value bool) error {
} else {
enc.writeString("false")
}
- return nil
}
// AddBoolKey adds a bool to be encoded, must be used inside an object as it will encode a key.
-func (enc *Encoder) AddBoolKey(key string, value bool) error {
+func (enc *Encoder) AddBoolKey(key string, value bool) {
r, ok := enc.getPreviousRune()
if ok && r != '{' && r != '[' {
enc.writeByte(',')
@@ -50,5 +49,4 @@ func (enc *Encoder) AddBoolKey(key string, value bool) error {
enc.writeString(key)
enc.writeBytes(objKey)
enc.buf = strconv.AppendBool(enc.buf, value)
- return nil
}
diff --git a/encode_interface.go b/encode_interface.go
@@ -48,75 +48,85 @@ func (enc *Encoder) Encode(v interface{}) error {
}
// AddInterface adds an interface{} to be encoded, must be used inside a slice or array encoding (does not encode a key)
-func (enc *Encoder) AddInterface(value interface{}) error {
+func (enc *Encoder) AddInterface(value interface{}) {
switch vt := value.(type) {
case string:
- return enc.AddString(vt)
+ enc.AddString(vt)
case bool:
- return enc.AddBool(vt)
+ enc.AddBool(vt)
case MarshalerArray:
- return enc.AddArray(vt)
+ enc.AddArray(vt)
case MarshalerObject:
- return enc.AddObject(vt)
+ enc.AddObject(vt)
case int:
- return enc.AddInt(vt)
+ enc.AddInt(vt)
case int64:
- return enc.AddInt(int(vt))
+ enc.AddInt(int(vt))
case int32:
- return enc.AddInt(int(vt))
+ enc.AddInt(int(vt))
case int8:
- return enc.AddInt(int(vt))
+ enc.AddInt(int(vt))
case uint64:
- return enc.AddInt(int(vt))
+ enc.AddInt(int(vt))
case uint32:
- return enc.AddInt(int(vt))
+ enc.AddInt(int(vt))
case uint16:
- return enc.AddInt(int(vt))
+ enc.AddInt(int(vt))
case uint8:
- return enc.AddInt(int(vt))
+ enc.AddInt(int(vt))
case float64:
- return enc.AddFloat(vt)
+ enc.AddFloat(vt)
case float32:
- return enc.AddFloat32(vt)
+ enc.AddFloat32(vt)
+ default:
+ t := reflect.TypeOf(vt)
+ if t != nil {
+ enc.err = InvalidMarshalError(fmt.Sprintf(invalidMarshalErrorMsg, t.String()))
+ return
+ }
+ return
}
-
- return nil
}
// AddInterfaceKey adds an interface{} to be encoded, must be used inside an object as it will encode a key
-func (enc *Encoder) AddInterfaceKey(key string, value interface{}) error {
+func (enc *Encoder) AddInterfaceKey(key string, value interface{}) {
switch vt := value.(type) {
case string:
- return enc.AddStringKey(key, vt)
+ enc.AddStringKey(key, vt)
case bool:
- return enc.AddBoolKey(key, vt)
+ enc.AddBoolKey(key, vt)
case MarshalerArray:
- return enc.AddArrayKey(key, value.(MarshalerArray))
+ enc.AddArrayKey(key, vt)
case MarshalerObject:
- return enc.AddObjectKey(key, value.(MarshalerObject))
+ enc.AddObjectKey(key, vt)
case int:
- return enc.AddIntKey(key, vt)
+ enc.AddIntKey(key, vt)
case int64:
- return enc.AddIntKey(key, int(vt))
+ enc.AddIntKey(key, int(vt))
case int32:
- return enc.AddIntKey(key, int(vt))
+ enc.AddIntKey(key, int(vt))
case int16:
- return enc.AddIntKey(key, int(vt))
+ enc.AddIntKey(key, int(vt))
case int8:
- return enc.AddIntKey(key, int(vt))
+ enc.AddIntKey(key, int(vt))
case uint64:
- return enc.AddIntKey(key, int(vt))
+ enc.AddIntKey(key, int(vt))
case uint32:
- return enc.AddIntKey(key, int(vt))
+ enc.AddIntKey(key, int(vt))
case uint16:
- return enc.AddIntKey(key, int(vt))
+ enc.AddIntKey(key, int(vt))
case uint8:
- return enc.AddIntKey(key, int(vt))
+ enc.AddIntKey(key, int(vt))
case float64:
- return enc.AddFloatKey(key, vt)
+ enc.AddFloatKey(key, vt)
case float32:
- return enc.AddFloat32Key(key, vt)
+ enc.AddFloat32Key(key, vt)
+ default:
+ t := reflect.TypeOf(vt)
+ if t != nil {
+ enc.err = InvalidMarshalError(fmt.Sprintf(invalidMarshalErrorMsg, t.String()))
+ return
+ }
+ return
}
-
- return nil
}
diff --git a/encode_number.go b/encode_number.go
@@ -55,11 +55,11 @@ func (enc *Encoder) EncodeFloat(n float64) error {
// encodeFloat encodes a float64 to JSON
func (enc *Encoder) encodeFloat(n float64) ([]byte, error) {
- enc.buf = strconv.AppendFloat(enc.buf, float64(n), 'f', -1, 64)
+ enc.buf = strconv.AppendFloat(enc.buf, n, 'f', -1, 64)
return enc.buf, nil
}
-// EncodeFloat encodes a float32 to JSON
+// EncodeFloat32 encodes a float32 to JSON
func (enc *Encoder) EncodeFloat32(n float32) error {
if enc.isPooled == 1 {
panic(InvalidUsagePooledEncoderError("Invalid usage of pooled encoder"))
@@ -78,39 +78,34 @@ func (enc *Encoder) encodeFloat32(n float32) ([]byte, error) {
}
// AddInt adds an int to be encoded, must be used inside a slice or array encoding (does not encode a key)
-func (enc *Encoder) AddInt(value int) error {
+func (enc *Encoder) AddInt(value int) {
r, ok := enc.getPreviousRune()
if ok && r != '[' {
enc.writeByte(',')
}
enc.buf = strconv.AppendInt(enc.buf, int64(value), 10)
- return nil
}
// AddFloat adds a float64 to be encoded, must be used inside a slice or array encoding (does not encode a key)
-func (enc *Encoder) AddFloat(value float64) error {
+func (enc *Encoder) AddFloat(value float64) {
r, ok := enc.getPreviousRune()
if ok && r != '[' {
enc.writeByte(',')
}
enc.buf = strconv.AppendFloat(enc.buf, value, 'f', -1, 64)
-
- return nil
}
-// AddFloat adds a float32 to be encoded, must be used inside a slice or array encoding (does not encode a key)
-func (enc *Encoder) AddFloat32(value float32) error {
+// AddFloat32 adds a float32 to be encoded, must be used inside a slice or array encoding (does not encode a key)
+func (enc *Encoder) AddFloat32(value float32) {
r, ok := enc.getPreviousRune()
if ok && r != '[' {
enc.writeByte(',')
}
enc.buf = strconv.AppendFloat(enc.buf, float64(value), 'f', -1, 32)
-
- return nil
}
// AddIntKey adds an int to be encoded, must be used inside an object as it will encode a key
-func (enc *Encoder) AddIntKey(key string, value int) error {
+func (enc *Encoder) AddIntKey(key string, value int) {
r, ok := enc.getPreviousRune()
if ok && r != '{' && r != '[' {
enc.writeByte(',')
@@ -119,12 +114,10 @@ func (enc *Encoder) AddIntKey(key string, value int) error {
enc.writeString(key)
enc.writeBytes(objKey)
enc.buf = strconv.AppendInt(enc.buf, int64(value), 10)
-
- return nil
}
// AddFloatKey adds a float64 to be encoded, must be used inside an object as it will encode a key
-func (enc *Encoder) AddFloatKey(key string, value float64) error {
+func (enc *Encoder) AddFloatKey(key string, value float64) {
r, ok := enc.getPreviousRune()
if ok && r != '{' && r != '[' {
enc.writeByte(',')
@@ -133,12 +126,10 @@ func (enc *Encoder) AddFloatKey(key string, value float64) error {
enc.writeString(key)
enc.writeBytes(objKey)
enc.buf = strconv.AppendFloat(enc.buf, value, 'f', -1, 64)
-
- return nil
}
// AddFloat32Key adds a float32 to be encoded, must be used inside an object as it will encode a key
-func (enc *Encoder) AddFloat32Key(key string, value float32) error {
+func (enc *Encoder) AddFloat32Key(key string, value float32) {
r, ok := enc.getPreviousRune()
if ok && r != '{' && r != '[' {
enc.writeByte(',')
@@ -148,6 +139,4 @@ func (enc *Encoder) AddFloat32Key(key string, value float32) error {
enc.writeByte('"')
enc.writeByte(':')
enc.buf = strconv.AppendFloat(enc.buf, float64(value), 'f', -1, 32)
-
- return nil
}
diff --git a/encode_object.go b/encode_object.go
@@ -10,8 +10,12 @@ func (enc *Encoder) EncodeObject(v MarshalerObject) error {
if enc.isPooled == 1 {
panic(InvalidUsagePooledEncoderError("Invalid usage of pooled encoder"))
}
- _, _ = enc.encodeObject(v)
- _, err := enc.write()
+ _, err := enc.encodeObject(v)
+ if err != nil {
+ enc.err = err
+ return err
+ }
+ _, err = enc.write()
if err != nil {
enc.err = err
return err
@@ -23,14 +27,14 @@ func (enc *Encoder) encodeObject(v MarshalerObject) ([]byte, error) {
enc.writeByte('{')
v.MarshalObject(enc)
enc.writeByte('}')
- return enc.buf, nil
+ return enc.buf, enc.err
}
// AddObject adds an object to be encoded, must be used inside a slice or array encoding (does not encode a key)
// value must implement MarshalerObject
-func (enc *Encoder) AddObject(value MarshalerObject) error {
+func (enc *Encoder) AddObject(value MarshalerObject) {
if value.IsNil() {
- return nil
+ return
}
r, ok := enc.getPreviousRune()
if ok && r != '[' {
@@ -39,14 +43,13 @@ func (enc *Encoder) AddObject(value MarshalerObject) error {
enc.writeByte('{')
value.MarshalObject(enc)
enc.writeByte('}')
- return nil
}
// AddObjectKey adds a struct to be encoded, must be used inside an object as it will encode a key
// value must implement MarshalerObject
-func (enc *Encoder) AddObjectKey(key string, value MarshalerObject) error {
+func (enc *Encoder) AddObjectKey(key string, value MarshalerObject) {
if value.IsNil() {
- return nil
+ return
}
r, ok := enc.getPreviousRune()
if ok && r != '{' && r != '[' {
@@ -57,5 +60,4 @@ func (enc *Encoder) AddObjectKey(key string, value MarshalerObject) error {
enc.writeBytes(objKeyObj)
value.MarshalObject(enc)
enc.writeByte('}')
- return nil
}
diff --git a/encode_object_test.go b/encode_object_test.go
@@ -43,6 +43,18 @@ func (t *testObject) MarshalObject(enc *Encoder) {
enc.AddBoolKey("testBool", t.testBool)
}
+type testObjectWithUnknownType struct {
+ unknownType struct{}
+}
+
+func (t *testObjectWithUnknownType) IsNil() bool {
+ return t == nil
+}
+
+func (t *testObjectWithUnknownType) MarshalObject(enc *Encoder) {
+ enc.AddInterfaceKey("unknownType", t.unknownType)
+}
+
func TestEncoderObjectBasic(t *testing.T) {
r, err := Marshal(&testObject{"漢字", 1, 1, 1, 1, 1, 1, 1, 1, 1, 1.1, 1.1, true})
assert.Nil(t, err, "Error should be nil")
@@ -66,6 +78,14 @@ func TestEncoderObjectBasicEncoderApi(t *testing.T) {
)
}
+func TestEncoderObjectInterfaceEncoderApiError(t *testing.T) {
+ builder := &strings.Builder{}
+ enc := NewEncoder(builder)
+ err := enc.EncodeObject(&testObjectWithUnknownType{struct{}{}})
+ assert.NotNil(t, err, "Error should not be nil")
+ assert.Equal(t, "Invalid type struct {} provided to Marshal", err.Error(), "err.Error() should be 'Invalid type struct {} provided to Marshal'")
+}
+
func TestEncoderObjectBasicEncoderApiError(t *testing.T) {
w := TestWriterError("")
enc := NewEncoder(w)
diff --git a/encode_pool.go b/encode_pool.go
@@ -19,6 +19,7 @@ func BorrowEncoder(w io.Writer) *Encoder {
case enc := <-encPool:
enc.isPooled = 0
enc.w = w
+ enc.err = nil
enc.buf = make([]byte, 0)
return enc
default:
diff --git a/encode_stream.go b/encode_stream.go
@@ -117,17 +117,15 @@ func (s *StreamEncoder) AddObject(v MarshalerObject) error {
}
// AddInt adds an int to be encoded, must be used inside a slice or array encoding (does not encode a key)
-func (s *StreamEncoder) AddInt(value int) error {
+func (s *StreamEncoder) AddInt(value int) {
s.buf = strconv.AppendInt(s.buf, int64(value), 10)
s.Encoder.writeByte(s.delimiter)
- return nil
}
// AddFloat adds a float64 to be encoded, must be used inside a slice or array encoding (does not encode a key)
-func (s *StreamEncoder) AddFloat(value float64) error {
+func (s *StreamEncoder) AddFloat(value float64) {
s.buf = strconv.AppendFloat(s.buf, value, 'f', -1, 64)
s.Encoder.writeByte(s.delimiter)
- return nil
}
// Non exposed
diff --git a/encode_stream_pool.go b/encode_stream_pool.go
@@ -20,6 +20,7 @@ func (s stream) BorrowEncoder(w io.Writer) *StreamEncoder {
case streamEnc := <-streamEncPool:
streamEnc.isPooled = 0
streamEnc.w = w
+ streamEnc.err = nil
streamEnc.done = make(chan struct{}, 1)
streamEnc.Encoder.buf = make([]byte, 0, 512)
streamEnc.nConsumer = 1
diff --git a/encode_stream_test.go b/encode_stream_test.go
@@ -26,7 +26,8 @@ func (s StreamChanInt) MarshalStream(enc *StreamEncoder) error {
case <-enc.Done():
return enc.Err()
case o := <-s:
- return enc.AddInt(o)
+ enc.AddInt(o)
+ return nil
}
}
@@ -37,7 +38,8 @@ func (s StreamChanFloat) MarshalStream(enc *StreamEncoder) error {
case <-enc.Done():
return enc.Err()
case o := <-s:
- return enc.AddFloat(o)
+ enc.AddFloat(o)
+ return nil
}
}
diff --git a/encode_string.go b/encode_string.go
@@ -23,7 +23,7 @@ func (enc *Encoder) encodeString(s string) ([]byte, error) {
}
// AddString adds a string to be encoded, must be used inside a slice or array encoding (does not encode a key)
-func (enc *Encoder) AddString(value string) error {
+func (enc *Encoder) AddString(value string) {
r, ok := enc.getPreviousRune()
if ok && r != '[' {
enc.writeByte(',')
@@ -31,12 +31,10 @@ func (enc *Encoder) AddString(value string) error {
enc.writeByte('"')
enc.writeString(value)
enc.writeByte('"')
-
- return nil
}
// AddStringKey adds a string to be encoded, must be used inside an object as it will encode a key
-func (enc *Encoder) AddStringKey(key, value string) error {
+func (enc *Encoder) AddStringKey(key, value string) {
// grow to avoid allocs (length of key/value + quotes)
r, ok := enc.getPreviousRune()
if ok && r != '{' && r != '[' {
@@ -47,6 +45,4 @@ func (enc *Encoder) AddStringKey(key, value string) error {
enc.writeBytes(objKeyStr)
enc.writeString(value)
enc.writeByte('"')
-
- return nil
}