ssob/unsafe_unmarshal.go

721 lines
21 KiB
Go

package ssob
import (
"encoding/binary"
"fmt"
"reflect"
"unsafe"
)
func UnsafeUnmarshalString(in []byte) (ret string, n int, err error) {
if len(in) < 4 {
return "", 0, fmt.Errorf("ssob: Decoding string: %w", ErrTypeInvalid)
}
l := int32(binary.BigEndian.Uint32(in))
if len(in[4:]) < int(l) {
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, fmt.Errorf("ssob: Decoding bool: %w", ErrTypeInvalid)
}
if in[0] == byte(0) {
return true, 1, nil
}
return false, 1, nil
}
func UnsafeUnmarshalInt8(in []byte) (ret int8, n int, err error) {
if len(in) < 1 {
return 0, 0, fmt.Errorf("ssob: Decoding int8: %w", ErrTypeInvalid)
}
return int8(in[0]), 1, nil
}
func UnsafeUnmarshalUint8(in []byte) (ret uint8, n int, err error) {
if len(in) < 1 {
return 0, 0, fmt.Errorf("ssob: Decoding uint8: %w", ErrTypeInvalid)
}
return uint8(in[0]), 1, nil
}
func UnsafeUnmarshalInt16(in []byte) (ret int16, n int, err error) {
if len(in) < 2 {
return 0, 0, fmt.Errorf("ssob: Decoding int16: %w", ErrTypeInvalid)
}
var out int16
start := unsafe.Pointer(&out)
if littleEndian {
*(*byte)(unsafe.Pointer(uintptr(start) + sPtr*uintptr(0))) = in[1]
*(*byte)(unsafe.Pointer(uintptr(start) + sPtr*uintptr(1))) = in[0]
} else {
*(*byte)(unsafe.Pointer(uintptr(start) + sPtr*uintptr(0))) = in[0]
*(*byte)(unsafe.Pointer(uintptr(start) + sPtr*uintptr(1))) = in[1]
}
return out, 2, nil
}
func UnsafeUnmarshalUint16(in []byte) (ret uint16, n int, err error) {
if len(in) < 2 {
return 0, 0, fmt.Errorf("ssob: Decoding uint16: %w", ErrTypeInvalid)
}
var out uint16
start := unsafe.Pointer(&out)
if littleEndian {
*(*byte)(unsafe.Pointer(uintptr(start) + sPtr*uintptr(0))) = in[1]
*(*byte)(unsafe.Pointer(uintptr(start) + sPtr*uintptr(1))) = in[0]
} else {
*(*byte)(unsafe.Pointer(uintptr(start) + sPtr*uintptr(0))) = in[0]
*(*byte)(unsafe.Pointer(uintptr(start) + sPtr*uintptr(1))) = in[1]
}
return out, 2, nil
}
func UnsafeUnmarshalInt32(in []byte) (ret int32, n int, err error) {
if len(in) < 4 {
return 0, 0, fmt.Errorf("ssob: Decoding int32: %w", ErrTypeInvalid)
}
var out int32
start := unsafe.Pointer(&out)
if littleEndian {
*(*byte)(unsafe.Pointer(uintptr(start) + sPtr*uintptr(0))) = in[3]
*(*byte)(unsafe.Pointer(uintptr(start) + sPtr*uintptr(1))) = in[2]
*(*byte)(unsafe.Pointer(uintptr(start) + sPtr*uintptr(2))) = in[1]
*(*byte)(unsafe.Pointer(uintptr(start) + sPtr*uintptr(3))) = in[0]
} else {
*(*byte)(unsafe.Pointer(uintptr(start) + sPtr*uintptr(0))) = in[0]
*(*byte)(unsafe.Pointer(uintptr(start) + sPtr*uintptr(1))) = in[1]
*(*byte)(unsafe.Pointer(uintptr(start) + sPtr*uintptr(2))) = in[2]
*(*byte)(unsafe.Pointer(uintptr(start) + sPtr*uintptr(3))) = in[3]
}
return out, 4, nil
}
func UnsafeUnmarshalUint32(in []byte) (ret uint32, n int, err error) {
if len(in) < 4 {
return 0, 0, fmt.Errorf("ssob: Decoding uint32: %w", ErrTypeInvalid)
}
var out uint32
start := unsafe.Pointer(&out)
if littleEndian {
*(*byte)(unsafe.Pointer(uintptr(start) + sPtr*uintptr(0))) = in[3]
*(*byte)(unsafe.Pointer(uintptr(start) + sPtr*uintptr(1))) = in[2]
*(*byte)(unsafe.Pointer(uintptr(start) + sPtr*uintptr(2))) = in[1]
*(*byte)(unsafe.Pointer(uintptr(start) + sPtr*uintptr(3))) = in[0]
} else {
*(*byte)(unsafe.Pointer(uintptr(start) + sPtr*uintptr(0))) = in[0]
*(*byte)(unsafe.Pointer(uintptr(start) + sPtr*uintptr(1))) = in[1]
*(*byte)(unsafe.Pointer(uintptr(start) + sPtr*uintptr(2))) = in[2]
*(*byte)(unsafe.Pointer(uintptr(start) + sPtr*uintptr(3))) = in[3]
}
return out, 4, nil
}
func UnsafeUnmarshalFloat32(in []byte) (ret float32, n int, err error) {
if len(in) < 4 {
return 0, 0, fmt.Errorf("ssob: Decoding float32: %w", ErrTypeInvalid)
}
var out float32
start := unsafe.Pointer(&out)
if littleEndian {
*(*byte)(unsafe.Pointer(uintptr(start) + sPtr*uintptr(0))) = in[3]
*(*byte)(unsafe.Pointer(uintptr(start) + sPtr*uintptr(1))) = in[2]
*(*byte)(unsafe.Pointer(uintptr(start) + sPtr*uintptr(2))) = in[1]
*(*byte)(unsafe.Pointer(uintptr(start) + sPtr*uintptr(3))) = in[0]
} else {
*(*byte)(unsafe.Pointer(uintptr(start) + sPtr*uintptr(0))) = in[0]
*(*byte)(unsafe.Pointer(uintptr(start) + sPtr*uintptr(1))) = in[1]
*(*byte)(unsafe.Pointer(uintptr(start) + sPtr*uintptr(2))) = in[2]
*(*byte)(unsafe.Pointer(uintptr(start) + sPtr*uintptr(3))) = in[3]
}
return out, 4, nil
}
func UnsafeUnmarshalInt64(in []byte) (ret int64, n int, err error) {
if len(in) < 8 {
return 0, 0, fmt.Errorf("ssob: Decoding int64: %w", ErrTypeInvalid)
}
var out int64
start := unsafe.Pointer(&out)
if littleEndian {
*(*byte)(unsafe.Pointer(uintptr(start) + sPtr*uintptr(0))) = in[7]
*(*byte)(unsafe.Pointer(uintptr(start) + sPtr*uintptr(1))) = in[6]
*(*byte)(unsafe.Pointer(uintptr(start) + sPtr*uintptr(2))) = in[5]
*(*byte)(unsafe.Pointer(uintptr(start) + sPtr*uintptr(3))) = in[4]
*(*byte)(unsafe.Pointer(uintptr(start) + sPtr*uintptr(4))) = in[3]
*(*byte)(unsafe.Pointer(uintptr(start) + sPtr*uintptr(5))) = in[2]
*(*byte)(unsafe.Pointer(uintptr(start) + sPtr*uintptr(6))) = in[1]
*(*byte)(unsafe.Pointer(uintptr(start) + sPtr*uintptr(7))) = in[0]
} else {
*(*byte)(unsafe.Pointer(uintptr(start) + sPtr*uintptr(0))) = in[0]
*(*byte)(unsafe.Pointer(uintptr(start) + sPtr*uintptr(1))) = in[1]
*(*byte)(unsafe.Pointer(uintptr(start) + sPtr*uintptr(2))) = in[2]
*(*byte)(unsafe.Pointer(uintptr(start) + sPtr*uintptr(3))) = in[3]
*(*byte)(unsafe.Pointer(uintptr(start) + sPtr*uintptr(4))) = in[4]
*(*byte)(unsafe.Pointer(uintptr(start) + sPtr*uintptr(5))) = in[5]
*(*byte)(unsafe.Pointer(uintptr(start) + sPtr*uintptr(6))) = in[6]
*(*byte)(unsafe.Pointer(uintptr(start) + sPtr*uintptr(7))) = in[7]
}
return out, 8, nil
}
func UnsafeUnmarshalUint64(in []byte) (ret uint64, n int, err error) {
if len(in) < 8 {
return 0, 0, fmt.Errorf("ssob: Decoding uint64: %w", ErrTypeInvalid)
}
var out uint64
start := unsafe.Pointer(&out)
if littleEndian {
*(*byte)(unsafe.Pointer(uintptr(start) + sPtr*uintptr(0))) = in[7]
*(*byte)(unsafe.Pointer(uintptr(start) + sPtr*uintptr(1))) = in[6]
*(*byte)(unsafe.Pointer(uintptr(start) + sPtr*uintptr(2))) = in[5]
*(*byte)(unsafe.Pointer(uintptr(start) + sPtr*uintptr(3))) = in[4]
*(*byte)(unsafe.Pointer(uintptr(start) + sPtr*uintptr(4))) = in[3]
*(*byte)(unsafe.Pointer(uintptr(start) + sPtr*uintptr(5))) = in[2]
*(*byte)(unsafe.Pointer(uintptr(start) + sPtr*uintptr(6))) = in[1]
*(*byte)(unsafe.Pointer(uintptr(start) + sPtr*uintptr(7))) = in[0]
} else {
*(*byte)(unsafe.Pointer(uintptr(start) + sPtr*uintptr(0))) = in[0]
*(*byte)(unsafe.Pointer(uintptr(start) + sPtr*uintptr(1))) = in[1]
*(*byte)(unsafe.Pointer(uintptr(start) + sPtr*uintptr(2))) = in[2]
*(*byte)(unsafe.Pointer(uintptr(start) + sPtr*uintptr(3))) = in[3]
*(*byte)(unsafe.Pointer(uintptr(start) + sPtr*uintptr(4))) = in[4]
*(*byte)(unsafe.Pointer(uintptr(start) + sPtr*uintptr(5))) = in[5]
*(*byte)(unsafe.Pointer(uintptr(start) + sPtr*uintptr(6))) = in[6]
*(*byte)(unsafe.Pointer(uintptr(start) + sPtr*uintptr(7))) = in[7]
}
return out, 8, nil
}
func UnsafeUnmarshalFloat64(in []byte) (ret float64, n int, err error) {
if len(in) < 8 {
return 0, 0, fmt.Errorf("ssob: Decoding float64: %w", ErrTypeInvalid)
}
var out float64
start := unsafe.Pointer(&out)
if littleEndian {
*(*byte)(unsafe.Pointer(uintptr(start) + sPtr*uintptr(0))) = in[7]
*(*byte)(unsafe.Pointer(uintptr(start) + sPtr*uintptr(1))) = in[6]
*(*byte)(unsafe.Pointer(uintptr(start) + sPtr*uintptr(2))) = in[5]
*(*byte)(unsafe.Pointer(uintptr(start) + sPtr*uintptr(3))) = in[4]
*(*byte)(unsafe.Pointer(uintptr(start) + sPtr*uintptr(4))) = in[3]
*(*byte)(unsafe.Pointer(uintptr(start) + sPtr*uintptr(5))) = in[2]
*(*byte)(unsafe.Pointer(uintptr(start) + sPtr*uintptr(6))) = in[1]
*(*byte)(unsafe.Pointer(uintptr(start) + sPtr*uintptr(7))) = in[0]
} else {
*(*byte)(unsafe.Pointer(uintptr(start) + sPtr*uintptr(0))) = in[0]
*(*byte)(unsafe.Pointer(uintptr(start) + sPtr*uintptr(1))) = in[1]
*(*byte)(unsafe.Pointer(uintptr(start) + sPtr*uintptr(2))) = in[2]
*(*byte)(unsafe.Pointer(uintptr(start) + sPtr*uintptr(3))) = in[3]
*(*byte)(unsafe.Pointer(uintptr(start) + sPtr*uintptr(4))) = in[4]
*(*byte)(unsafe.Pointer(uintptr(start) + sPtr*uintptr(5))) = in[5]
*(*byte)(unsafe.Pointer(uintptr(start) + sPtr*uintptr(6))) = in[6]
*(*byte)(unsafe.Pointer(uintptr(start) + sPtr*uintptr(7))) = in[7]
}
return out, 8, nil
}
var unsafeDecoderCache map[string]unmarshalFunc
func init() {
unsafeDecoderCache = make(map[string]unmarshalFunc)
RegisterUnsafeDecoder("bool", func(e interface{}, in []byte) (n int, err error) {
if i, ok := e.(*bool); ok {
*i, n, err = UnsafeUnmarshalBool(in)
return n, nil
}
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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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 fmt.Errorf("ssob: invalid type: %w", ErrTypeInvalid)
case reflect.Array:
f := func(e interface{}, in []byte) (n int, err error) {
t := reflect.TypeOf(e)
v := reflect.ValueOf(e)
pos := 0
if t.Kind() != reflect.Ptr || v.IsNil() {
return 0, fmt.Errorf("ssob: Cannot unmarshal to nil pointer: %w", ErrValueInvalid)
}
l, r, err := UnsafeUnmarshalInt32(in)
pos += r
if err != nil {
return pos, err
}
ti := v.Elem()
if int(l) != 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())
r, err := unsafeUnmarshal(e.Interface(), in[pos:])
pos += r
if err != nil {
return pos, err
}
ti.Index(i).Set(reflect.Indirect(e))
}
return pos, nil
}
unsafeDecoderCache[string(t.Kind())] = f
case reflect.Slice:
f := func(e interface{}, in []byte) (n int, err error) {
t := reflect.TypeOf(e)
v := reflect.ValueOf(e)
pos := 0
if t.Kind() != reflect.Ptr || v.IsNil() {
return 0, fmt.Errorf("ssob: Cannot unmarshal to nil pointer: %w", ErrValueInvalid)
}
l, r, err := UnsafeUnmarshalInt32(in)
pos += r
if err != nil {
return pos, err
}
ti := v.Elem()
ti.Set(reflect.MakeSlice(reflect.TypeOf(ti.Interface()), 0, ti.Cap()))
for i := 0; i < int(l); i++ {
e := reflect.New(reflect.TypeOf(ti.Interface()).Elem())
r, err := unsafeUnmarshal(e.Interface(), in[pos:])
pos += r
if err != nil {
return pos, err
}
ti.Set(reflect.Append(ti, reflect.Indirect(e)))
}
return pos, nil
}
unsafeDecoderCache[string(t.Kind())] = f
case reflect.Struct:
zt := reflect.New(t)
n := zt.Elem().NumField()
mfields := []int{}
for i := 0; i < n; i++ {
if zt.Elem().Field(i).CanSet() {
mfields = append(mfields, i)
}
}
if len(mfields) == 0 {
return fmt.Errorf("ssob: No exported fields for %s: %w", string(t.Name()), ErrParseFailed)
}
f := func(e interface{}, in []byte) (n int, err error) {
t := reflect.TypeOf(e)
v := reflect.ValueOf(e)
pos := 0
if t.Kind() != reflect.Ptr || v.IsNil() {
return 0, fmt.Errorf("ssob: Cannot unmarshal to nil pointer: %w", ErrValueInvalid)
}
vi := reflect.Indirect(v)
for _, i := range mfields {
ni, err := unsafeUnmarshal(vi.Field(i).Addr().Interface(), in[pos:])
pos += ni
if err != nil {
return pos, err
}
}
return pos, nil
}
unsafeDecoderCache[t.Name()] = f
case reflect.Map:
f := func(e interface{}, in []byte) (n int, err error) {
t := reflect.TypeOf(e)
v := reflect.ValueOf(e)
pos := 0
if t.Kind() != reflect.Ptr || v.IsNil() {
return 0, fmt.Errorf("ssob: Cannot unmarshal to nil pointer: %w", ErrValueInvalid)
}
l, r, err := UnsafeUnmarshalInt32(in)
pos += r
if err != nil {
return pos, err
}
vi := reflect.Indirect(v)
vt := reflect.TypeOf(vi.Interface())
tk := vt.Key()
tv := vt.Elem()
for i := int32(0); i < l; i++ {
ek := reflect.New(tk)
ev := reflect.New(tv)
r, err := unsafeUnmarshal(ek.Interface(), in[pos:])
pos += r
if err != nil {
return pos, err
}
r, err = unsafeUnmarshal(ev.Interface(), in[pos:])
pos += r
if err != nil {
return pos, err
}
vi.SetMapIndex(reflect.Indirect(ek), reflect.Indirect(ev))
}
return pos, nil
}
unsafeDecoderCache[string(t.Kind())] = f
case reflect.Bool:
f := func(e interface{}, in []byte) (n int, err error) {
v := reflect.ValueOf(e)
i := bool(false)
pos := 0
r, err := unsafeUnmarshalBaseType(&i, in[pos:])
pos += r
if err != nil {
return pos, err
}
v.Elem().SetBool(bool(i))
return pos, nil
}
unsafeDecoderCache[t.Name()] = f
case reflect.Uint8:
f := func(e interface{}, in []byte) (n int, err error) {
v := reflect.ValueOf(e)
i := uint8(0)
pos := 0
r, err := unsafeUnmarshalBaseType(&i, in[pos:])
pos += r
if err != nil {
return pos, err
}
v.Elem().SetUint(uint64(i))
return pos, nil
}
unsafeDecoderCache[t.Name()] = f
case reflect.Uint16:
f := func(e interface{}, in []byte) (n int, err error) {
v := reflect.ValueOf(e)
i := uint16(0)
pos := 0
r, err := unsafeUnmarshalBaseType(&i, in[pos:])
pos += r
if err != nil {
return pos, err
}
v.Elem().SetUint(uint64(i))
return pos, nil
}
unsafeDecoderCache[t.Name()] = f
case reflect.Uint32:
f := func(e interface{}, in []byte) (n int, err error) {
v := reflect.ValueOf(e)
i := uint32(0)
pos := 0
r, err := unsafeUnmarshalBaseType(&i, in[pos:])
pos += r
if err != nil {
return pos, err
}
v.Elem().SetUint(uint64(i))
return pos, nil
}
unsafeDecoderCache[t.Name()] = f
case reflect.Uint64:
f := func(e interface{}, in []byte) (n int, err error) {
v := reflect.ValueOf(e)
i := uint64(0)
pos := 0
r, err := unsafeUnmarshalBaseType(&i, in[pos:])
pos += r
if err != nil {
return pos, err
}
v.Elem().SetUint(uint64(i))
return pos, nil
}
unsafeDecoderCache[t.Name()] = f
case reflect.Int8:
f := func(e interface{}, in []byte) (n int, err error) {
v := reflect.ValueOf(e)
i := int8(0)
pos := 0
r, err := unsafeUnmarshalBaseType(&i, in[pos:])
pos += r
if err != nil {
return pos, err
}
v.Elem().SetInt(int64(i))
return pos, nil
}
unsafeDecoderCache[t.Name()] = f
case reflect.Int16:
f := func(e interface{}, in []byte) (n int, err error) {
v := reflect.ValueOf(e)
i := int16(0)
pos := 0
r, err := unsafeUnmarshalBaseType(&i, in[pos:])
pos += r
if err != nil {
return pos, err
}
v.Elem().SetInt(int64(i))
return pos, nil
}
unsafeDecoderCache[t.Name()] = f
case reflect.Int32:
f := func(e interface{}, in []byte) (n int, err error) {
v := reflect.ValueOf(e)
i := int32(0)
pos := 0
r, err := unsafeUnmarshalBaseType(&i, in[pos:])
pos += r
if err != nil {
return pos, err
}
v.Elem().SetInt(int64(i))
return pos, nil
}
unsafeDecoderCache[t.Name()] = f
case reflect.Int64:
f := func(e interface{}, in []byte) (n int, err error) {
v := reflect.ValueOf(e)
i := int64(0)
pos := 0
r, err := unsafeUnmarshalBaseType(&i, in[pos:])
pos += r
if err != nil {
return pos, err
}
v.Elem().SetInt(int64(i))
return pos, nil
}
unsafeDecoderCache[t.Name()] = f
case reflect.String:
f := func(e interface{}, in []byte) (n int, err error) {
v := reflect.ValueOf(e)
i := string("")
pos := 0
r, err := unsafeUnmarshalBaseType(&i, in[pos:])
pos += r
if err != nil {
return pos, err
}
v.Elem().SetString(i)
return pos, nil
}
unsafeDecoderCache[t.Name()] = f
default:
return fmt.Errorf("ssob: %s: %w", string(t.Name()), ErrTypeUnknown)
}
return nil
}
func unsafeUnmarshalBaseType(e interface{}, in []byte) (n int, err error) {
switch t := e.(type) {
case *bool:
return unsafeDecoderCache["bool"](t, in)
case *int8:
return unsafeDecoderCache["int8"](t, in)
case *uint8:
return unsafeDecoderCache["uint8"](t, in)
case *int16:
return unsafeDecoderCache["int16"](t, in)
case *uint16:
return unsafeDecoderCache["uint16"](t, in)
case *int32:
return unsafeDecoderCache["int32"](t, in)
case *uint32:
return unsafeDecoderCache["uint32"](t, in)
case *int64:
return unsafeDecoderCache["int64"](t, in)
case *uint64:
return unsafeDecoderCache["uint64"](t, in)
case *float32:
return unsafeDecoderCache["float32"](t, in)
case *float64:
return unsafeDecoderCache["float64"](t, in)
case *string:
return unsafeDecoderCache["string"](t, in)
default:
return 0, fmt.Errorf("ssob: No base type: %w", ErrTypeUnknown)
}
}
func unsafeUnmarshal(e interface{}, in []byte) (n int, err error) {
n, err = unsafeUnmarshalBaseType(e, in)
if err == nil {
return n, err
}
var key string
t := reflect.TypeOf(e)
v := reflect.ValueOf(e)
if t.Kind() != reflect.Ptr || v.IsNil() {
return 0, fmt.Errorf("ssob: Need a pointer that is fully allocated for unmarshalling: %w", ErrValueInvalid)
}
p := reflect.Indirect(v)
if p.Kind() != reflect.Ptr {
switch p.Kind() {
case reflect.Bool, reflect.Int8, reflect.Int16, reflect.Int32,
reflect.Int64, reflect.Uint8, reflect.Uint16, reflect.Uint32,
reflect.Uint64, reflect.String, reflect.Struct:
key = reflect.TypeOf(p.Interface()).Name()
default:
key = string(p.Kind())
}
if f, ok := unsafeDecoderCache[key]; ok {
return f(v.Interface(), in)
} else {
err = decRegisterUnsafe(p.Interface())
if err != nil {
return 0, err
}
return unsafeUnmarshal(e, in)
}
}
if !p.Elem().IsValid() {
err = allocType(v)
if err != nil {
return 0, err
}
p = reflect.Indirect(v)
}
return unsafeUnmarshal(p.Interface(), in)
}
func RegisterUnsafeDecoder(name string, f func(e interface{}, in []byte) (n int, err error)) {
unsafeDecoderCache[name] = f
}