diff --git a/allocator.go b/allocator.go index 213dce7..bc01c4c 100644 --- a/allocator.go +++ b/allocator.go @@ -1,13 +1,13 @@ package ssob import ( - "errors" + "fmt" "reflect" ) func allocType(out reflect.Value) (err error) { if out.Type().Kind() != reflect.Ptr || out.IsNil() { - return errors.New("ssob: Error allocating type (Got nil pointer)") + return fmt.Errorf("ssob: Error allocating type (Got nil pointer): %w", ErrValueInvalid) } t := out.Elem().Type() diff --git a/decoder.go b/decoder.go index 886631e..783280e 100644 --- a/decoder.go +++ b/decoder.go @@ -3,6 +3,7 @@ package ssob import ( "encoding/binary" "errors" + "fmt" "io" "reflect" "sync" @@ -24,12 +25,23 @@ func (dec *Decoder) Decode(e interface{}) (err error) { } func (dec *Decoder) DecodeValue(value reflect.Value) (err error) { + if value.Type() == reflect.TypeOf(errors.New("")) || value.Type() == reflect.TypeOf((*error)(nil)) { + var errstr string + if err = dec.Decode(&errstr); err != nil { + return err + } + if errstr != "" { + *value.Interface().(*error) = errors.New(errstr) + } + return nil + } + if value.Kind() == reflect.Invalid { - return errors.New("ssob: Cannot decode nil value") + return fmt.Errorf("ssob: Cannot decode nil: %w", ErrValueInvalid) } if value.Kind() == reflect.Ptr && value.IsNil() { - return errors.New("ssob: Cannot decode nil of type " + value.Type().String()) + return fmt.Errorf("ssob: Cannot decode nil of type %s: %w", value.Type().String(), ErrValueInvalid) } dec.mutex.Lock() diff --git a/encoder.go b/encoder.go index b0b0b0d..df1c97f 100644 --- a/encoder.go +++ b/encoder.go @@ -3,6 +3,7 @@ package ssob import ( "encoding/binary" "errors" + "fmt" "io" "reflect" "sync" @@ -24,12 +25,20 @@ func (enc *Encoder) Encode(e interface{}) (err error) { } func (enc *Encoder) EncodeValue(value reflect.Value) (err error) { + if value.Type() == reflect.TypeOf(errors.New("")) || value.Type() == reflect.TypeOf((*error)(nil)).Elem() { + if value.IsNil() { + return enc.Encode(string("")) + } else { + return enc.Encode(value.Interface().(error).Error()) + } + } + if value.Kind() == reflect.Invalid { - return errors.New("ssob: Cannot encode nil value") + return fmt.Errorf("ssob: Cannot encode nil: %w", ErrValueInvalid) } if value.Kind() == reflect.Ptr && value.IsNil() { - return errors.New("ssob: Cannot encode nil of type " + value.Type().String()) + return fmt.Errorf("ssob: Cannot encode nil of type %s: %w", value.Type().String(), ErrValueInvalid) } bb, err := marshal(value.Interface()) diff --git a/error.go b/error.go new file mode 100644 index 0000000..ede5b19 --- /dev/null +++ b/error.go @@ -0,0 +1,9 @@ +package ssob + +import "errors" + +var ErrValueInvalid = errors.New("value invalid") +var ErrTypeInvalid = errors.New("type invalid") +var ErrTypeUnknown = errors.New("type unknown") +var ErrTypeMismatch = errors.New("type mismatch") +var ErrParseFailed = errors.New("parsing failed") diff --git a/marshal.go b/marshal.go index e52f8b0..67f25b8 100644 --- a/marshal.go +++ b/marshal.go @@ -2,7 +2,7 @@ package ssob import ( "encoding/binary" - "errors" + "fmt" "math" "reflect" ) @@ -98,85 +98,85 @@ func init() { if i, ok := e.(bool); ok { return MarshalBool(i), nil } - return nil, errors.New("ssob: Incompatible type - expected bool") + return nil, fmt.Errorf("ssob: Incompatible type - expected bool: %w", ErrTypeMismatch) }) RegisterEncoder("int8", func(e interface{}) (ret []byte, err error) { if i, ok := e.(int8); ok { return MarshalInt8(i), nil } - return nil, errors.New("ssob: Incompatible type - expected int8") + return nil, fmt.Errorf("ssob: Incompatible type - expected int8: %w", ErrTypeMismatch) }) RegisterEncoder("uint8", func(e interface{}) (ret []byte, err error) { if i, ok := e.(uint8); ok { return MarshalUint8(i), nil } - return nil, errors.New("ssob: Incompatible type - expected uint8") + return nil, fmt.Errorf("ssob: Incompatible type - expected uint8: %w", ErrTypeMismatch) }) RegisterEncoder("int16", func(e interface{}) (ret []byte, err error) { if i, ok := e.(int16); ok { return MarshalInt16(i), nil } - return nil, errors.New("ssob: Incompatible type - expected int16") + return nil, fmt.Errorf("ssob: Incompatible type - expected int16: %w", ErrTypeMismatch) }) RegisterEncoder("uint16", func(e interface{}) (ret []byte, err error) { if i, ok := e.(uint16); ok { return MarshalUint16(i), nil } - return nil, errors.New("ssob: Incompatible type - expected uint16") + return nil, fmt.Errorf("ssob: Incompatible type - expected uint16: %w", ErrTypeMismatch) }) RegisterEncoder("int32", func(e interface{}) (ret []byte, err error) { if i, ok := e.(int32); ok { return MarshalInt32(i), nil } - return nil, errors.New("ssob: Incompatible type - expected int32") + return nil, fmt.Errorf("ssob: Incompatible type - expected int32: %w", ErrTypeMismatch) }) RegisterEncoder("uint32", func(e interface{}) (ret []byte, err error) { if i, ok := e.(uint32); ok { return MarshalUint32(i), nil } - return nil, errors.New("ssob: Incompatible type - expected uint32") + return nil, fmt.Errorf("ssob: Incompatible type - expected uint32: %w", ErrTypeMismatch) }) RegisterEncoder("float32", func(e interface{}) (ret []byte, err error) { if i, ok := e.(float32); ok { return MarshalFloat32(i), nil } - return nil, errors.New("ssob: Incompatible type - expected float32") + return nil, fmt.Errorf("ssob: Incompatible type - expected float32: %w", ErrTypeMismatch) }) RegisterEncoder("int64", func(e interface{}) (ret []byte, err error) { if i, ok := e.(int64); ok { return MarshalInt64(i), nil } - return nil, errors.New("ssob: Incompatible type - expected int64") + return nil, fmt.Errorf("ssob: Incompatible type - expected int64: %w", ErrTypeMismatch) }) RegisterEncoder("uint64", func(e interface{}) (ret []byte, err error) { if i, ok := e.(uint64); ok { return MarshalUint64(i), nil } - return nil, errors.New("ssob: Incompatible type - expected uint64") + return nil, fmt.Errorf("ssob: Incompatible type - expected uint64: %w", ErrTypeMismatch) }) RegisterEncoder("float64", func(e interface{}) (ret []byte, err error) { if i, ok := e.(float64); ok { return MarshalFloat64(i), nil } - return nil, errors.New("ssob: Incompatible type - expected float64") + return nil, fmt.Errorf("ssob: Incompatible type - expected float64: %w", ErrTypeMismatch) }) RegisterEncoder("string", func(e interface{}) (ret []byte, err error) { if i, ok := e.(string); ok { return MarshalString(i), nil } - return nil, errors.New("ssob: Incompatible type - expected string") + return nil, fmt.Errorf("ssob: Incompatible type - expected string: %w", ErrTypeMismatch) }) } func encRegister(e interface{}) (err error) { t := reflect.TypeOf(e) if t == nil { - return errors.New("ssob: Invalid type") + return fmt.Errorf("ssob: nil type: %w", ErrTypeInvalid) } switch t.Kind() { case reflect.Invalid: - return errors.New("ssob: Invalid type") + return fmt.Errorf("ssob: invalid type: %w", ErrTypeInvalid) case reflect.Array: f := func(e interface{}) (ret []byte, err error) { v := reflect.ValueOf(e) @@ -257,7 +257,7 @@ func encRegister(e interface{}) (err error) { } } if len(mfields) == 0 { - return errors.New("ssob: No exported fields for " + string(t.Name())) + return fmt.Errorf("ssob: No exported fields for %s: %w", string(t.Name()), ErrParseFailed) } f := func(e interface{}) (ret []byte, err error) { @@ -340,7 +340,7 @@ func encRegister(e interface{}) (err error) { } encoderCache[t.Name()] = f default: - return errors.New("ssob: Unknown type " + string(t.Name())) + return fmt.Errorf("ssob: %s: %w", string(t.Name()), ErrTypeUnknown) } return nil @@ -373,7 +373,7 @@ func marshalBaseType(e interface{}) (ret []byte, err error) { case string: return encoderCache["string"](t) default: - return nil, errors.New("ssob: No base type") + return nil, fmt.Errorf("ssob: No base type: %w", ErrTypeUnknown) } } @@ -389,7 +389,7 @@ func marshal(e interface{}) (ret []byte, err error) { switch t.Kind() { case reflect.Ptr: if v.IsNil() { - return nil, errors.New("ssob: Cannot marshal nil pointer") + return nil, fmt.Errorf("ssob: Cannot marshal nil pointer: %w", ErrValueInvalid) } p := reflect.Indirect(v) return marshal(p.Interface()) diff --git a/unmarshal.go b/unmarshal.go index 0f1269d..d656aaf 100644 --- a/unmarshal.go +++ b/unmarshal.go @@ -2,26 +2,26 @@ package ssob import ( "encoding/binary" - "errors" + "fmt" "math" "reflect" ) func UnmarshalString(in []byte) (ret string, n int, err error) { if len(in) < 4 { - return "", 0, errors.New("ssob: Invalid input to decode string") + return "", 0, fmt.Errorf("ssob: Decoding string: %w", ErrTypeInvalid) } l := int32(binary.BigEndian.Uint32(in)) if len(in[4:]) < int(l) { - return "", 0, errors.New("ssob: Invalid length of string") + return "", 0, fmt.Errorf("ssob: Invalid length of string: %w", ErrValueInvalid) } return string(in[4 : l+4]), int(l) + 4, nil } func UnmarshalBool(in []byte) (ret bool, n int, err error) { if len(in) < 1 { - return false, 0, errors.New("ssob: Invalid input to decode bool") + return false, 0, fmt.Errorf("ssob: Decoding bool: %w", ErrTypeInvalid) } if in[0] == byte(0) { @@ -32,7 +32,7 @@ func UnmarshalBool(in []byte) (ret bool, n int, err error) { func UnmarshalInt8(in []byte) (ret int8, n int, err error) { if len(in) < 1 { - return 0, 0, errors.New("ssob: Invalid input to decode int8") + return 0, 0, fmt.Errorf("ssob: Decoding int8: %w", ErrTypeInvalid) } return int8(in[0]), 1, nil @@ -40,7 +40,7 @@ func UnmarshalInt8(in []byte) (ret int8, n int, err error) { func UnmarshalUint8(in []byte) (ret uint8, n int, err error) { if len(in) < 1 { - return 0, 0, errors.New("ssob: Invalid input to decode uint8") + return 0, 0, fmt.Errorf("ssob: Decoding uint8: %w", ErrTypeInvalid) } return uint8(in[0]), 1, nil @@ -48,7 +48,7 @@ func UnmarshalUint8(in []byte) (ret uint8, n int, err error) { func UnmarshalInt16(in []byte) (ret int16, n int, err error) { if len(in) < 2 { - return 0, 0, errors.New("ssob: Invalid input to decode int16") + return 0, 0, fmt.Errorf("ssob: Decoding int16: %w", ErrTypeInvalid) } return int16(binary.BigEndian.Uint16(in[0:2])), 2, nil @@ -56,7 +56,7 @@ func UnmarshalInt16(in []byte) (ret int16, n int, err error) { func UnmarshalUint16(in []byte) (ret uint16, n int, err error) { if len(in) < 2 { - return 0, 0, errors.New("ssob: Invalid input to decode uint16") + return 0, 0, fmt.Errorf("ssob: Decoding uint16: %w", ErrTypeInvalid) } return binary.BigEndian.Uint16(in[0:2]), 2, nil @@ -64,7 +64,7 @@ func UnmarshalUint16(in []byte) (ret uint16, n int, err error) { func UnmarshalInt32(in []byte) (ret int32, n int, err error) { if len(in) < 4 { - return 0, 0, errors.New("ssob: Invalid input to decode int32") + return 0, 0, fmt.Errorf("ssob: Decoding int32: %w", ErrTypeInvalid) } return int32(binary.BigEndian.Uint32(in[0:4])), 4, nil @@ -72,7 +72,7 @@ func UnmarshalInt32(in []byte) (ret int32, n int, err error) { func UnmarshalUint32(in []byte) (ret uint32, n int, err error) { if len(in) < 4 { - return 0, 0, errors.New("ssob: Invalid input to decode uint32") + return 0, 0, fmt.Errorf("ssob: Decoding uint32: %w", ErrTypeInvalid) } return binary.BigEndian.Uint32(in[0:4]), 4, nil @@ -80,7 +80,7 @@ func UnmarshalUint32(in []byte) (ret uint32, n int, err error) { func UnmarshalFloat32(in []byte) (ret float32, n int, err error) { if len(in) < 4 { - return 0, 0, errors.New("ssob: Invalid input to decode float32") + return 0, 0, fmt.Errorf("ssob: Decoding float32: %w", ErrTypeInvalid) } return float32(math.Float32frombits(binary.BigEndian.Uint32(in[0:4]))), 4, nil @@ -88,7 +88,7 @@ func UnmarshalFloat32(in []byte) (ret float32, n int, err error) { func UnmarshalInt64(in []byte) (ret int64, n int, err error) { if len(in) < 8 { - return 0, 0, errors.New("ssob: Invalid input to decode int64") + return 0, 0, fmt.Errorf("ssob: Decoding int64: %w", ErrTypeInvalid) } return int64(binary.BigEndian.Uint64(in[0:8])), 8, nil @@ -96,7 +96,7 @@ func UnmarshalInt64(in []byte) (ret int64, n int, err error) { func UnmarshalUint64(in []byte) (ret uint64, n int, err error) { if len(in) < 8 { - return 0, 0, errors.New("ssob: Invalid input to decode uint64") + return 0, 0, fmt.Errorf("ssob: Decoding uint64: %w", ErrTypeInvalid) } return binary.BigEndian.Uint64(in[0:8]), 8, nil @@ -104,7 +104,7 @@ func UnmarshalUint64(in []byte) (ret uint64, n int, err error) { func UnmarshalFloat64(in []byte) (ret float64, n int, err error) { if len(in) < 8 { - return 0, 0, errors.New("ssob: Invalid input to decode float64") + return 0, 0, fmt.Errorf("ssob: Decoding float64: %w", ErrTypeInvalid) } return float64(math.Float64frombits(binary.BigEndian.Uint64(in[0:8]))), 8, nil @@ -121,96 +121,96 @@ func init() { *i, n, err = UnmarshalBool(in) return n, err } - return 0, errors.New("ssob: Incompatible type - expected bool") + return 0, fmt.Errorf("ssob: Incompatible type - expected bool: %w", ErrTypeMismatch) }) RegisterDecoder("int8", func(e interface{}, in []byte) (n int, err error) { if i, ok := e.(*int8); ok { *i, n, err = UnmarshalInt8(in) return n, err } - return 0, errors.New("ssob: Incompatible type - expected int8") + return 0, fmt.Errorf("ssob: Incompatible type - expected int8: %w", ErrTypeMismatch) }) RegisterDecoder("uint8", func(e interface{}, in []byte) (n int, err error) { if i, ok := e.(*uint8); ok { *i, n, err = UnmarshalUint8(in) return n, err } - return 0, errors.New("ssob: Incompatible type - expected uint8") + return 0, fmt.Errorf("ssob: Incompatible type - expected uint8: %w", ErrTypeMismatch) }) RegisterDecoder("int16", func(e interface{}, in []byte) (n int, err error) { if i, ok := e.(*int16); ok { *i, n, err = UnmarshalInt16(in) return n, err } - return 0, errors.New("ssob: Incompatible type - expected int16") + return 0, fmt.Errorf("ssob: Incompatible type - expected int16: %w", ErrTypeMismatch) }) RegisterDecoder("uint16", func(e interface{}, in []byte) (n int, err error) { if i, ok := e.(*uint16); ok { *i, n, err = UnmarshalUint16(in) return n, err } - return 0, errors.New("ssob: Incompatible type - expected uint16") + return 0, fmt.Errorf("ssob: Incompatible type - expected uint16: %w", ErrTypeMismatch) }) RegisterDecoder("int32", func(e interface{}, in []byte) (n int, err error) { if i, ok := e.(*int32); ok { *i, n, err = UnmarshalInt32(in) return n, err } - return 0, errors.New("ssob: Incompatible type - expected int32") + return 0, fmt.Errorf("ssob: Incompatible type - expected int32: %w", ErrTypeMismatch) }) RegisterDecoder("uint32", func(e interface{}, in []byte) (n int, err error) { if i, ok := e.(*uint32); ok { *i, n, err = UnmarshalUint32(in) return n, err } - return 0, errors.New("ssob: Incompatible type - expected uint32") + return 0, fmt.Errorf("ssob: Incompatible type - expected uint32: %w", ErrTypeMismatch) }) RegisterDecoder("float32", func(e interface{}, in []byte) (n int, err error) { if i, ok := e.(*float32); ok { *i, n, err = UnmarshalFloat32(in) return n, err } - return 0, errors.New("ssob: Incompatible type - expected float32") + return 0, fmt.Errorf("ssob: Incompatible type - expected float32: %w", ErrTypeMismatch) }) RegisterDecoder("int64", func(e interface{}, in []byte) (n int, err error) { if i, ok := e.(*int64); ok { *i, n, err = UnmarshalInt64(in) return n, err } - return 0, errors.New("ssob: Incompatible type - expected int64") + return 0, fmt.Errorf("ssob: Incompatible type - expected int64: %w", ErrTypeMismatch) }) RegisterDecoder("uint64", func(e interface{}, in []byte) (n int, err error) { if i, ok := e.(*uint64); ok { *i, n, err = UnmarshalUint64(in) return n, err } - return 0, errors.New("ssob: Incompatible type - expected uint64") + return 0, fmt.Errorf("ssob: Incompatible type - expected uint64: %w", ErrTypeMismatch) }) RegisterDecoder("float64", func(e interface{}, in []byte) (n int, err error) { if i, ok := e.(*float64); ok { *i, n, err = UnmarshalFloat64(in) return n, err } - return 0, errors.New("ssob: Incompatible type - expected float64") + return 0, fmt.Errorf("ssob: Incompatible type - expected float64: %w", ErrTypeMismatch) }) RegisterDecoder("string", func(e interface{}, in []byte) (n int, err error) { if i, ok := e.(*string); ok { *i, n, err = UnmarshalString(in) return n, err } - return 0, errors.New("ssob: Incompatible type - expected string") + return 0, fmt.Errorf("ssob: Incompatible type - expected string: %w", ErrTypeMismatch) }) } func decRegister(e interface{}) (err error) { t := reflect.TypeOf(e) if t == nil { - return errors.New("ssob: Invalid type") + return fmt.Errorf("ssob: nil type: %w", ErrTypeInvalid) } switch t.Kind() { case reflect.Invalid: - return errors.New("ssob: Invalid type") + return fmt.Errorf("ssob: invalid type: %w", ErrTypeInvalid) case reflect.Array: f := func(e interface{}, in []byte) (n int, err error) { t := reflect.TypeOf(e) @@ -218,7 +218,7 @@ func decRegister(e interface{}) (err error) { pos := 0 if t.Kind() != reflect.Ptr || v.IsNil() { - return 0, errors.New("ssob: Cannot unmarshal to nil pointer") + return 0, fmt.Errorf("ssob: Cannot unmarshal to nil pointer: %w", ErrValueInvalid) } l, r, err := UnmarshalInt32(in) @@ -229,7 +229,7 @@ func decRegister(e interface{}) (err error) { ti := v.Elem() if int(l) != ti.Len() { - return pos, errors.New("ssob: Invalid array length. Expected " + string(l) + " got " + string(ti.Len())) + return pos, fmt.Errorf("ssob: Invalid array length. Expected %s got %s: %w", string(l), string(ti.Len()), ErrValueInvalid) } for i := 0; i < int(l); i++ { e := reflect.New(reflect.TypeOf(ti.Interface()).Elem()) @@ -250,7 +250,7 @@ func decRegister(e interface{}) (err error) { pos := 0 if t.Kind() != reflect.Ptr || v.IsNil() { - return 0, errors.New("ssob: Cannot unmarshal to nil pointer") + return 0, fmt.Errorf("ssob: Cannot unmarshal to nil pointer: %w", ErrValueInvalid) } l, r, err := UnmarshalInt32(in) @@ -283,7 +283,7 @@ func decRegister(e interface{}) (err error) { } } if len(mfields) == 0 { - return errors.New("ssob: No exported fields for " + string(t.Name())) + return fmt.Errorf("ssob: No exported fields for %s: %w", string(t.Name()), ErrParseFailed) } f := func(e interface{}, in []byte) (n int, err error) { @@ -292,7 +292,7 @@ func decRegister(e interface{}) (err error) { pos := 0 if t.Kind() != reflect.Ptr || v.IsNil() { - return 0, errors.New("ssob: Cannot unmarshal to nil pointer") + return 0, fmt.Errorf("ssob: Cannot unmarshal to nil pointer: %w", ErrValueInvalid) } vi := reflect.Indirect(v) @@ -314,7 +314,7 @@ func decRegister(e interface{}) (err error) { pos := 0 if t.Kind() != reflect.Ptr || v.IsNil() { - return 0, errors.New("ssob: Cannot unmarshal to nil pointer") + return 0, fmt.Errorf("ssob: Cannot unmarshal to nil pointer: %w", ErrValueInvalid) } l, r, err := UnmarshalInt32(in) @@ -507,7 +507,7 @@ func decRegister(e interface{}) (err error) { } decoderCache[t.Name()] = f default: - return errors.New("ssob: Unknown type " + string(t.Name())) + return fmt.Errorf("ssob: %s: %w", string(t.Name()), ErrTypeUnknown) } return nil @@ -540,7 +540,7 @@ func unmarshalBaseType(e interface{}, in []byte) (n int, err error) { case *string: return decoderCache["string"](t, in) default: - return 0, errors.New("ssob: No base type") + return 0, fmt.Errorf("ssob: No base type: %w", ErrTypeUnknown) } } @@ -554,7 +554,7 @@ func unmarshal(e interface{}, in []byte) (n int, err error) { t := reflect.TypeOf(e) v := reflect.ValueOf(e) if !v.IsValid() || t.Kind() != reflect.Ptr || v.IsNil() { - return 0, errors.New("ssob: Need a pointer that is fully allocated for unmarshalling") + return 0, fmt.Errorf("ssob: Need a pointer that is fully allocated for unmarshalling: %w", ErrValueInvalid) } p := reflect.Indirect(v) diff --git a/unsafe_decoder.go b/unsafe_decoder.go index f12c2ba..59a088e 100644 --- a/unsafe_decoder.go +++ b/unsafe_decoder.go @@ -2,7 +2,7 @@ package ssob import ( "encoding/binary" - "errors" + "fmt" "io" "reflect" "sync" @@ -25,11 +25,11 @@ func (dec *UnsafeDecoder) Decode(e interface{}) (err error) { func (dec *UnsafeDecoder) DecodeValue(value reflect.Value) (err error) { if value.Kind() == reflect.Invalid { - return errors.New("ssob: Cannot decode nil value") + return fmt.Errorf("ssob: Cannot decode nil: %w", ErrValueInvalid) } if value.Kind() == reflect.Ptr && value.IsNil() { - return errors.New("ssob: Cannot decode nil of type " + value.Type().String()) + return fmt.Errorf("ssob: Cannot decode nil of type %s: %w", value.Type().String(), ErrValueInvalid) } dec.mutex.Lock() diff --git a/unsafe_encoder.go b/unsafe_encoder.go index f9ac916..920059d 100644 --- a/unsafe_encoder.go +++ b/unsafe_encoder.go @@ -2,7 +2,7 @@ package ssob import ( "encoding/binary" - "errors" + "fmt" "io" "reflect" "sync" @@ -25,11 +25,11 @@ func (enc *UnsafeEncoder) Encode(e interface{}) (err error) { func (enc *UnsafeEncoder) EncodeValue(value reflect.Value) (err error) { if value.Kind() == reflect.Invalid { - return errors.New("ssob: Cannot encode nil value") + return fmt.Errorf("ssob: Cannot encode nil: %w", ErrValueInvalid) } if value.Kind() == reflect.Ptr && value.IsNil() { - return errors.New("ssob: Cannot encode nil of type " + value.Type().String()) + return fmt.Errorf("ssob: Cannot encode nil of type %s: %w", value.Type().String(), ErrValueInvalid) } bb, err := unsafeMarshal(value.Interface()) diff --git a/unsafe_marshal.go b/unsafe_marshal.go index e09ca0c..04c3050 100644 --- a/unsafe_marshal.go +++ b/unsafe_marshal.go @@ -1,7 +1,7 @@ package ssob import ( - "errors" + "fmt" "reflect" "unsafe" ) @@ -207,81 +207,85 @@ func init() { if i, ok := e.(bool); ok { return UnsafeMarshalBool(i), nil } - return nil, errors.New("ssob: Incompatible type - expected bool") + return nil, fmt.Errorf("ssob: Incompatible type - expected bool: %w", ErrTypeMismatch) }) RegisterUnsafeEncoder("int8", func(e interface{}) (ret []byte, err error) { if i, ok := e.(int8); ok { return UnsafeMarshalInt8(i), nil } - return nil, errors.New("ssob: Incompatible type - expected int8") + return nil, fmt.Errorf("ssob: Incompatible type - expected int8: %w", ErrTypeMismatch) }) RegisterUnsafeEncoder("uint8", func(e interface{}) (ret []byte, err error) { if i, ok := e.(uint8); ok { return UnsafeMarshalUint8(i), nil } - return nil, errors.New("ssob: Incompatible type - expected uint8") + return nil, fmt.Errorf("ssob: Incompatible type - expected uint8: %w", ErrTypeMismatch) }) RegisterUnsafeEncoder("int16", func(e interface{}) (ret []byte, err error) { if i, ok := e.(int16); ok { return UnsafeMarshalInt16(i), nil } - return nil, errors.New("ssob: Incompatible type - expected int16") + return nil, fmt.Errorf("ssob: Incompatible type - expected int16: %w", ErrTypeMismatch) }) RegisterUnsafeEncoder("uint16", func(e interface{}) (ret []byte, err error) { if i, ok := e.(uint16); ok { return UnsafeMarshalUint16(i), nil } - return nil, errors.New("ssob: Incompatible type - expected uint16") + return nil, fmt.Errorf("ssob: Incompatible type - expected uint16: %w", ErrTypeMismatch) }) RegisterUnsafeEncoder("int32", func(e interface{}) (ret []byte, err error) { if i, ok := e.(int32); ok { return UnsafeMarshalInt32(i), nil } - return nil, errors.New("ssob: Incompatible type - expected int32") + return nil, fmt.Errorf("ssob: Incompatible type - expected int32: %w", ErrTypeMismatch) }) RegisterUnsafeEncoder("uint32", func(e interface{}) (ret []byte, err error) { if i, ok := e.(uint32); ok { return UnsafeMarshalUint32(i), nil } - return nil, errors.New("ssob: Incompatible type - expected uint32") + return nil, fmt.Errorf("ssob: Incompatible type - expected uint32: %w", ErrTypeMismatch) }) RegisterUnsafeEncoder("float32", func(e interface{}) (ret []byte, err error) { if i, ok := e.(float32); ok { return UnsafeMarshalFloat32(i), nil } - return nil, errors.New("ssob: Incompatible type - expected float32") + return nil, fmt.Errorf("ssob: Incompatible type - expected float32: %w", ErrTypeMismatch) }) RegisterUnsafeEncoder("int64", func(e interface{}) (ret []byte, err error) { if i, ok := e.(int64); ok { return UnsafeMarshalInt64(i), nil } - return nil, errors.New("ssob: Incompatible type - expected int64") + return nil, fmt.Errorf("ssob: Incompatible type - expected int64: %w", ErrTypeMismatch) }) RegisterUnsafeEncoder("uint64", func(e interface{}) (ret []byte, err error) { if i, ok := e.(uint64); ok { return UnsafeMarshalUint64(i), nil } - return nil, errors.New("ssob: Incompatible type - expected uint64") + return nil, fmt.Errorf("ssob: Incompatible type - expected uint64: %w", ErrTypeMismatch) }) RegisterUnsafeEncoder("float64", func(e interface{}) (ret []byte, err error) { if i, ok := e.(float64); ok { return UnsafeMarshalFloat64(i), nil } - return nil, errors.New("ssob: Incompatible type - expected float64") + return nil, fmt.Errorf("ssob: Incompatible type - expected float64: %w", ErrTypeMismatch) }) RegisterUnsafeEncoder("string", func(e interface{}) (ret []byte, err error) { if i, ok := e.(string); ok { return UnsafeMarshalString(i), nil } - return nil, errors.New("ssob: Incompatible type - expected string") + return nil, fmt.Errorf("ssob: Incompatible type - expected string: %w", ErrTypeMismatch) }) } func encRegisterUnsafe(e interface{}) (err error) { t := reflect.TypeOf(e) + if t == nil { + return fmt.Errorf("ssob: nil type: %w", ErrTypeInvalid) + } + switch t.Kind() { case reflect.Invalid: - return errors.New("ssob: Invalid type") + return fmt.Errorf("ssob: invalid type: %w", ErrTypeInvalid) case reflect.Array: f := func(e interface{}) (ret []byte, err error) { v := reflect.ValueOf(e) @@ -362,7 +366,7 @@ func encRegisterUnsafe(e interface{}) (err error) { } } if len(mfields) == 0 { - return errors.New("ssob: No exported fields for " + string(t.Name())) + return fmt.Errorf("ssob: No exported fields for %s: %w", string(t.Name()), ErrParseFailed) } f := func(e interface{}) (ret []byte, err error) { @@ -445,7 +449,7 @@ func encRegisterUnsafe(e interface{}) (err error) { } unsafeEncoderCache[t.Name()] = f default: - return errors.New("ssob: Unknown type " + string(t.Name())) + return fmt.Errorf("ssob: %s: %w", string(t.Name()), ErrTypeUnknown) } return nil @@ -478,7 +482,7 @@ func unsafeMarshalBaseType(e interface{}) (ret []byte, err error) { case string: return unsafeEncoderCache["string"](t) default: - return nil, errors.New("ssob: No base type") + return nil, fmt.Errorf("ssob: No base type: %w", ErrTypeUnknown) } } @@ -494,7 +498,7 @@ func unsafeMarshal(e interface{}) (ret []byte, err error) { switch t.Kind() { case reflect.Ptr: if v.IsNil() { - return nil, errors.New("ssob: Cannot marshal nil pointer") + return nil, fmt.Errorf("ssob: Cannot marshal nil pointer: %w", ErrValueInvalid) } p := reflect.Indirect(v) return unsafeMarshal(p.Interface()) diff --git a/unsafe_unmarshal.go b/unsafe_unmarshal.go index dcd5c0d..a1b494b 100644 --- a/unsafe_unmarshal.go +++ b/unsafe_unmarshal.go @@ -2,26 +2,26 @@ package ssob import ( "encoding/binary" - "errors" + "fmt" "reflect" "unsafe" ) func UnsafeUnmarshalString(in []byte) (ret string, n int, err error) { if len(in) < 4 { - return "", 0, errors.New("ssob: Invalid input to decode string") + return "", 0, fmt.Errorf("ssob: Decoding string: %w", ErrTypeInvalid) } l := int32(binary.BigEndian.Uint32(in)) if len(in[4:]) < int(l) { - return "", 0, errors.New("ssob: Invalid length of string") + return "", 0, fmt.Errorf("ssob: Invalid length of string: %w", ErrValueInvalid) } return string(in[4 : l+4]), int(l) + 4, nil } func UnsafeUnmarshalBool(in []byte) (ret bool, n int, err error) { if len(in) < 1 { - return false, 0, errors.New("ssob: Invalid input to decode bool") + return false, 0, fmt.Errorf("ssob: Decoding bool: %w", ErrTypeInvalid) } if in[0] == byte(0) { @@ -32,7 +32,7 @@ func UnsafeUnmarshalBool(in []byte) (ret bool, n int, err error) { func UnsafeUnmarshalInt8(in []byte) (ret int8, n int, err error) { if len(in) < 1 { - return 0, 0, errors.New("ssob: Invalid input to decode int8") + return 0, 0, fmt.Errorf("ssob: Decoding int8: %w", ErrTypeInvalid) } return int8(in[0]), 1, nil @@ -40,7 +40,7 @@ func UnsafeUnmarshalInt8(in []byte) (ret int8, n int, err error) { func UnsafeUnmarshalUint8(in []byte) (ret uint8, n int, err error) { if len(in) < 1 { - return 0, 0, errors.New("ssob: Invalid input to decode uint8") + return 0, 0, fmt.Errorf("ssob: Decoding uint8: %w", ErrTypeInvalid) } return uint8(in[0]), 1, nil @@ -48,7 +48,7 @@ func UnsafeUnmarshalUint8(in []byte) (ret uint8, n int, err error) { func UnsafeUnmarshalInt16(in []byte) (ret int16, n int, err error) { if len(in) < 2 { - return 0, 0, errors.New("ssob: Invalid input to decode int16") + return 0, 0, fmt.Errorf("ssob: Decoding int16: %w", ErrTypeInvalid) } var out int16 @@ -66,7 +66,7 @@ func UnsafeUnmarshalInt16(in []byte) (ret int16, n int, err error) { func UnsafeUnmarshalUint16(in []byte) (ret uint16, n int, err error) { if len(in) < 2 { - return 0, 0, errors.New("ssob: Invalid input to decode uint16") + return 0, 0, fmt.Errorf("ssob: Decoding uint16: %w", ErrTypeInvalid) } var out uint16 @@ -84,7 +84,7 @@ func UnsafeUnmarshalUint16(in []byte) (ret uint16, n int, err error) { func UnsafeUnmarshalInt32(in []byte) (ret int32, n int, err error) { if len(in) < 4 { - return 0, 0, errors.New("ssob: Invalid input to decode int32") + return 0, 0, fmt.Errorf("ssob: Decoding int32: %w", ErrTypeInvalid) } var out int32 @@ -106,7 +106,7 @@ func UnsafeUnmarshalInt32(in []byte) (ret int32, n int, err error) { func UnsafeUnmarshalUint32(in []byte) (ret uint32, n int, err error) { if len(in) < 4 { - return 0, 0, errors.New("ssob: Invalid input to decode uint32") + return 0, 0, fmt.Errorf("ssob: Decoding uint32: %w", ErrTypeInvalid) } var out uint32 @@ -128,7 +128,7 @@ func UnsafeUnmarshalUint32(in []byte) (ret uint32, n int, err error) { func UnsafeUnmarshalFloat32(in []byte) (ret float32, n int, err error) { if len(in) < 4 { - return 0, 0, errors.New("ssob: Invalid input to decode float32") + return 0, 0, fmt.Errorf("ssob: Decoding float32: %w", ErrTypeInvalid) } var out float32 @@ -150,7 +150,7 @@ func UnsafeUnmarshalFloat32(in []byte) (ret float32, n int, err error) { func UnsafeUnmarshalInt64(in []byte) (ret int64, n int, err error) { if len(in) < 8 { - return 0, 0, errors.New("ssob: Invalid input to decode int64") + return 0, 0, fmt.Errorf("ssob: Decoding int64: %w", ErrTypeInvalid) } var out int64 @@ -180,7 +180,7 @@ func UnsafeUnmarshalInt64(in []byte) (ret int64, n int, err error) { func UnsafeUnmarshalUint64(in []byte) (ret uint64, n int, err error) { if len(in) < 8 { - return 0, 0, errors.New("ssob: Invalid input to decode uint64") + return 0, 0, fmt.Errorf("ssob: Decoding uint64: %w", ErrTypeInvalid) } var out uint64 @@ -210,7 +210,7 @@ func UnsafeUnmarshalUint64(in []byte) (ret uint64, n int, err error) { func UnsafeUnmarshalFloat64(in []byte) (ret float64, n int, err error) { if len(in) < 8 { - return 0, 0, errors.New("ssob: Invalid input to decode float64") + return 0, 0, fmt.Errorf("ssob: Decoding float64: %w", ErrTypeInvalid) } var out float64 @@ -247,92 +247,96 @@ func init() { *i, n, err = UnsafeUnmarshalBool(in) return n, nil } - return 0, errors.New("ssob: Incompatible type - expected bool") + return 0, fmt.Errorf("ssob: Incompatible type - expected bool: %w", ErrTypeMismatch) }) RegisterUnsafeDecoder("int8", func(e interface{}, in []byte) (n int, err error) { if i, ok := e.(*int8); ok { *i, n, err = UnsafeUnmarshalInt8(in) return n, nil } - return 0, errors.New("ssob: Incompatible type - expected int8") + return 0, fmt.Errorf("ssob: Incompatible type - expected int8: %w", ErrTypeMismatch) }) RegisterUnsafeDecoder("uint8", func(e interface{}, in []byte) (n int, err error) { if i, ok := e.(*uint8); ok { *i, n, err = UnsafeUnmarshalUint8(in) return n, nil } - return 0, errors.New("ssob: Incompatible type - expected uint8") + return 0, fmt.Errorf("ssob: Incompatible type - expected uint8: %w", ErrTypeMismatch) }) RegisterUnsafeDecoder("int16", func(e interface{}, in []byte) (n int, err error) { if i, ok := e.(*int16); ok { *i, n, err = UnsafeUnmarshalInt16(in) return n, nil } - return 0, errors.New("ssob: Incompatible type - expected int16") + return 0, fmt.Errorf("ssob: Incompatible type - expected int16: %w", ErrTypeMismatch) }) RegisterUnsafeDecoder("uint16", func(e interface{}, in []byte) (n int, err error) { if i, ok := e.(*uint16); ok { *i, n, err = UnsafeUnmarshalUint16(in) return n, nil } - return 0, errors.New("ssob: Incompatible type - expected uint16") + return 0, fmt.Errorf("ssob: Incompatible type - expected uint16: %w", ErrTypeMismatch) }) RegisterUnsafeDecoder("int32", func(e interface{}, in []byte) (n int, err error) { if i, ok := e.(*int32); ok { *i, n, err = UnsafeUnmarshalInt32(in) return n, nil } - return 0, errors.New("ssob: Incompatible type - expected int32") + return 0, fmt.Errorf("ssob: Incompatible type - expected int32: %w", ErrTypeMismatch) }) RegisterUnsafeDecoder("uint32", func(e interface{}, in []byte) (n int, err error) { if i, ok := e.(*uint32); ok { *i, n, err = UnsafeUnmarshalUint32(in) return n, nil } - return 0, errors.New("ssob: Incompatible type - expected uint32") + return 0, fmt.Errorf("ssob: Incompatible type - expected uint32: %w", ErrTypeMismatch) }) RegisterUnsafeDecoder("float32", func(e interface{}, in []byte) (n int, err error) { if i, ok := e.(*float32); ok { *i, n, err = UnsafeUnmarshalFloat32(in) return n, nil } - return 0, errors.New("ssob: Incompatible type - expected float32") + return 0, fmt.Errorf("ssob: Incompatible type - expected float32: %w", ErrTypeMismatch) }) RegisterUnsafeDecoder("int64", func(e interface{}, in []byte) (n int, err error) { if i, ok := e.(*int64); ok { *i, n, err = UnsafeUnmarshalInt64(in) return n, nil } - return 0, errors.New("ssob: Incompatible type - expected int64") + return 0, fmt.Errorf("ssob: Incompatible type - expected int64: %w", ErrTypeMismatch) }) RegisterUnsafeDecoder("uint64", func(e interface{}, in []byte) (n int, err error) { if i, ok := e.(*uint64); ok { *i, n, err = UnsafeUnmarshalUint64(in) return n, nil } - return 0, errors.New("ssob: Incompatible type - expected uint64") + return 0, fmt.Errorf("ssob: Incompatible type - expected uint64: %w", ErrTypeMismatch) }) RegisterUnsafeDecoder("float64", func(e interface{}, in []byte) (n int, err error) { if i, ok := e.(*float64); ok { *i, n, err = UnsafeUnmarshalFloat64(in) return n, nil } - return 0, errors.New("ssob: Incompatible type - expected float64") + return 0, fmt.Errorf("ssob: Incompatible type - expected float64: %w", ErrTypeMismatch) }) RegisterUnsafeDecoder("string", func(e interface{}, in []byte) (n int, err error) { if i, ok := e.(*string); ok { *i, n, err = UnsafeUnmarshalString(in) return n, nil } - return 0, errors.New("ssob: Incompatible type - expected string") + return 0, fmt.Errorf("ssob: Incompatible type - expected string: %w", ErrTypeMismatch) }) } func decRegisterUnsafe(e interface{}) (err error) { t := reflect.TypeOf(e) + if t == nil { + return fmt.Errorf("ssob: nil type: %w", ErrTypeInvalid) + } + switch t.Kind() { case reflect.Invalid: - return errors.New("ssob: Invalid type") + return fmt.Errorf("ssob: invalid type: %w", ErrTypeInvalid) case reflect.Array: f := func(e interface{}, in []byte) (n int, err error) { t := reflect.TypeOf(e) @@ -340,7 +344,7 @@ func decRegisterUnsafe(e interface{}) (err error) { pos := 0 if t.Kind() != reflect.Ptr || v.IsNil() { - return 0, errors.New("ssob: Cannot unmarshal to nil pointer") + return 0, fmt.Errorf("ssob: Cannot unmarshal to nil pointer: %w", ErrValueInvalid) } l, r, err := UnsafeUnmarshalInt32(in) @@ -351,7 +355,7 @@ func decRegisterUnsafe(e interface{}) (err error) { ti := v.Elem() if int(l) != ti.Len() { - return pos, errors.New("ssob: Invalid array length. Expected " + string(l) + " got " + string(ti.Len())) + return pos, fmt.Errorf("ssob: Invalid array length. Expected %s got %s: %w", string(l), string(ti.Len()), ErrValueInvalid) } for i := 0; i < int(l); i++ { e := reflect.New(reflect.TypeOf(ti.Interface()).Elem()) @@ -372,7 +376,7 @@ func decRegisterUnsafe(e interface{}) (err error) { pos := 0 if t.Kind() != reflect.Ptr || v.IsNil() { - return 0, errors.New("ssob: Cannot unmarshal to nil pointer") + return 0, fmt.Errorf("ssob: Cannot unmarshal to nil pointer: %w", ErrValueInvalid) } l, r, err := UnsafeUnmarshalInt32(in) @@ -405,7 +409,7 @@ func decRegisterUnsafe(e interface{}) (err error) { } } if len(mfields) == 0 { - return errors.New("ssob: No exported fields for " + string(t.Name())) + return fmt.Errorf("ssob: No exported fields for %s: %w", string(t.Name()), ErrParseFailed) } f := func(e interface{}, in []byte) (n int, err error) { @@ -414,7 +418,7 @@ func decRegisterUnsafe(e interface{}) (err error) { pos := 0 if t.Kind() != reflect.Ptr || v.IsNil() { - return 0, errors.New("ssob: Cannot unmarshal to nil pointer") + return 0, fmt.Errorf("ssob: Cannot unmarshal to nil pointer: %w", ErrValueInvalid) } vi := reflect.Indirect(v) @@ -436,7 +440,7 @@ func decRegisterUnsafe(e interface{}) (err error) { pos := 0 if t.Kind() != reflect.Ptr || v.IsNil() { - return 0, errors.New("ssob: Cannot unmarshal to nil pointer") + return 0, fmt.Errorf("ssob: Cannot unmarshal to nil pointer: %w", ErrValueInvalid) } l, r, err := UnsafeUnmarshalInt32(in) @@ -629,7 +633,7 @@ func decRegisterUnsafe(e interface{}) (err error) { } unsafeDecoderCache[t.Name()] = f default: - return errors.New("ssob: Unknown type " + string(t.Name())) + return fmt.Errorf("ssob: %s: %w", string(t.Name()), ErrTypeUnknown) } return nil @@ -662,7 +666,7 @@ func unsafeUnmarshalBaseType(e interface{}, in []byte) (n int, err error) { case *string: return unsafeDecoderCache["string"](t, in) default: - return 0, errors.New("ssob: No base type") + return 0, fmt.Errorf("ssob: No base type: %w", ErrTypeUnknown) } } @@ -676,7 +680,7 @@ func unsafeUnmarshal(e interface{}, in []byte) (n int, err error) { t := reflect.TypeOf(e) v := reflect.ValueOf(e) if t.Kind() != reflect.Ptr || v.IsNil() { - return 0, errors.New("ssob: Need a pointer that is fully allocated for unmarshalling") + return 0, fmt.Errorf("ssob: Need a pointer that is fully allocated for unmarshalling: %w", ErrValueInvalid) } p := reflect.Indirect(v)