From 8023e705301eec2510b6123068a207b32db18d29 Mon Sep 17 00:00:00 2001 From: Matthias Fulz Date: Thu, 2 Sep 2021 15:25:39 +0200 Subject: [PATCH] Marshalling implemented --- marshal.go | 377 +++++++++++++++++++++++++++++++++++++++++++++++++++++ types.go | 180 ++++++++++++++++--------- 2 files changed, 497 insertions(+), 60 deletions(-) diff --git a/marshal.go b/marshal.go index eb8f1be..c48a0bc 100644 --- a/marshal.go +++ b/marshal.go @@ -6,6 +6,8 @@ import ( "io" "math" "reflect" + + "gitea.olznet.de/OlzNet/slog" ) func MarshalString(in string) (ret []byte) { @@ -482,3 +484,378 @@ func baseTypeMarshaller(e interface{}, w io.Writer) (err error) { return binary.Write(w, binary.BigEndian, sb) } + +func marshalBool(e bool) (ret []byte) { + ret = make([]byte, ST_ID_SIZE+1) + ret[0] = 1 + if e == true { + ret[0] = 0 + } + return ret +} + +func marshalUint8(e uint8) (ret []byte) { + ret = make([]byte, 1) + ret[0] = byte(e) + return ret +} + +func marshalUint16(e uint16) (ret []byte) { + ret = make([]byte, 2) + binary.BigEndian.PutUint16(ret, e) + return ret +} + +func marshalUint32(e uint32) (ret []byte) { + ret = make([]byte, 4) + binary.BigEndian.PutUint32(ret, e) + return ret +} + +func marshalUint64(e uint64) (ret []byte) { + ret = make([]byte, 8) + binary.BigEndian.PutUint64(ret, e) + return ret +} + +func marshalInt8(e int8) (ret []byte) { + ret = make([]byte, 1) + ret[0] = byte(e) + return ret +} + +func marshalInt16(e int16) (ret []byte) { + ret = make([]byte, 2) + binary.BigEndian.PutUint16(ret, uint16(e)) + return ret +} + +func marshalInt32(e int32) (ret []byte) { + ret = make([]byte, 4) + binary.BigEndian.PutUint32(ret, uint32(e)) + return ret +} + +func marshalInt64(e int64) (ret []byte) { + ret = make([]byte, 8) + binary.BigEndian.PutUint64(ret, uint64(e)) + return ret +} + +func marshalFloat32(e float32) (ret []byte) { + ret = make([]byte, 4) + binary.BigEndian.PutUint32(ret, math.Float32bits(e)) + return ret +} + +func marshalFloat64(e float64) (ret []byte) { + ret = make([]byte, 8) + binary.BigEndian.PutUint64(ret, math.Float64bits(e)) + return ret +} + +func marshalString(e string) (ret []byte) { + slen := len(e) + ret = make([]byte, slen+4) + binary.BigEndian.PutUint32(ret, uint32(slen)) + copy(ret[4:], []byte(e)) + return ret +} + +func marshalNil(e uint16) (ret []byte) { + return marshalUint16(e) +} + +func marshalPtrIfNil(e interface{}, ntype *NType) (ie interface{}, ret []byte, isNil bool) { + if ntype.Indirection == 0 { + return e, nil, false + } + + nl := uint16(0) + v := reflect.ValueOf(e) + if v.Kind() == reflect.Invalid { + ret = append(ret, marshalTypeId(ST_NIL)...) + ret = append(ret, marshalNil(nl)...) + return e, ret, true + } + + for i := 0; i < ntype.Indirection; i++ { + v = reflect.Indirect(v) + nl++ + if v.Kind() == reflect.Invalid || (v.Kind() == reflect.Ptr && v.IsNil()) { + ret = append(ret, marshalTypeId(ST_NIL)...) + ret = append(ret, marshalNil(uint16(nl))...) + return e, ret, true + } + } + + ret = append(ret, marshalTypeId(ntype.ValType)...) + return v.Interface(), ret, false +} + +func marshalError(e interface{}, ntype *NType) (ret []byte, err error) { + nl := uint16(0) + v := reflect.ValueOf(e) + if v.Kind() == reflect.Invalid { + ret = append(ret, marshalTypeId(ST_NIL)...) + ret = append(ret, marshalNil(nl)...) + return ret, err + } + + for i := 0; i < ntype.Indirection; i++ { + v = reflect.Indirect(v) + nl++ + if v.Kind() == reflect.Invalid || v.IsNil() { + ret = append(ret, marshalTypeId(ST_NIL)...) + ret = append(ret, marshalNil(uint16(nl))...) + return ret, err + } + } + + ierr, ok := v.Interface().(error) + if !ok { + return ret, fmt.Errorf("Not an error interface '%v': %w", v.Interface(), ErrValueInvalid) + } + + ret = append(ret, marshalTypeId(ST_STRING)...) + ret = append(ret, marshalString(ierr.Error())...) + return ret, err +} + +func marshalTypeId(e uint32) (ret []byte) { + return marshalUint32(e) +} + +func marshalCommon(e interface{}, ntype *NType) (ret []byte, err error) { + ctype := getTypeById(ntype.ValType) + if ctype == nil { + return ret, fmt.Errorf("ssob: Unknown common type '%d': %w", ntype.ValType, ErrTypeUnknown) + } + + // pointer could be nil + e, ptrNil, isNil := marshalPtrIfNil(e, ntype) + if ptrNil != nil { + if isNil { + return ptrNil, err + } + ret = append(ret, ptrNil...) + } + + switch ctype.Id { + case ST_BOOL: + if ie, ok := e.(bool); !ok { + return ret, fmt.Errorf("ssob: Invalid interface type '%v' expected 'bool': %w", e, ErrTypeInvalid) + } else { + ret = append(ret, marshalBool(ie)...) + return ret, err + } + case ST_UINT8: + if ie, ok := e.(uint8); !ok { + return ret, fmt.Errorf("ssob: Invalid interface type '%v' expected 'uint8': %w", e, ErrTypeInvalid) + } else { + ret = append(ret, marshalUint8(ie)...) + return ret, err + } + case ST_UINT16: + if ie, ok := e.(uint16); !ok { + return ret, fmt.Errorf("ssob: Invalid interface type '%v' expected 'uint16': %w", e, ErrTypeInvalid) + } else { + ret = append(ret, marshalUint16(ie)...) + return ret, err + } + case ST_UINT32: + if ie, ok := e.(uint32); !ok { + return ret, fmt.Errorf("ssob: Invalid interface type '%v' expected 'uint32': %w", e, ErrTypeInvalid) + } else { + ret = append(ret, marshalUint32(ie)...) + return ret, err + } + case ST_UINT64: + if ie, ok := e.(uint64); !ok { + return ret, fmt.Errorf("ssob: Invalid interface type '%v' expected 'uint64': %w", e, ErrTypeInvalid) + } else { + ret = append(ret, marshalUint64(ie)...) + return ret, err + } + case ST_INT8: + if ie, ok := e.(int8); !ok { + return ret, fmt.Errorf("ssob: Invalid interface type '%v' expected 'int8': %w", e, ErrTypeInvalid) + } else { + ret = append(ret, marshalInt8(ie)...) + return ret, err + } + case ST_INT16: + if ie, ok := e.(int16); !ok { + return ret, fmt.Errorf("ssob: Invalid interface type '%v' expected 'int16': %w", e, ErrTypeInvalid) + } else { + ret = append(ret, marshalInt16(ie)...) + return ret, err + } + case ST_INT32: + if ie, ok := e.(int32); !ok { + return ret, fmt.Errorf("ssob: Invalid interface type '%v' expected 'int32': %w", e, ErrTypeInvalid) + } else { + ret = append(ret, marshalInt32(ie)...) + return ret, err + } + case ST_INT64: + if ie, ok := e.(int64); !ok { + return ret, fmt.Errorf("ssob: Invalid interface type '%v' expected 'int64': %w", e, ErrTypeInvalid) + } else { + ret = append(ret, marshalInt64(ie)...) + return ret, err + } + case ST_FLOAT32: + if ie, ok := e.(float32); !ok { + return ret, fmt.Errorf("ssob: Invalid interface type '%v' expected 'float32': %w", e, ErrTypeInvalid) + } else { + ret = append(ret, marshalFloat32(ie)...) + return ret, err + } + case ST_FLOAT64: + if ie, ok := e.(float64); !ok { + return ret, fmt.Errorf("ssob: Invalid interface type '%v' expected 'float64': %w", e, ErrTypeInvalid) + } else { + ret = append(ret, marshalFloat64(ie)...) + return ret, err + } + case ST_STRING: + if ie, ok := e.(string); !ok { + return ret, fmt.Errorf("ssob: Invalid interface type '%v' expected 'string': %w", e, ErrTypeInvalid) + } else { + ret = append(ret, marshalString(ie)...) + return ret, err + } + case ST_ERROR: + return marshalError(e, ntype) + default: + return ret, fmt.Errorf("ssob: Unknown common type '%d': %w", ctype.Id, ErrTypeUnknown) + } +} + +func marshalSlice(e interface{}, ntype *NType) (ret []byte, err error) { + v := reflect.ValueOf(e) + if v.Kind() != reflect.Slice { + return ret, fmt.Errorf("ssob: Invalid value '%v': %w", v.Kind(), ErrValueInvalid) + } + + stype := getTypeById(ntype.ValType) + if stype == nil { + return ret, fmt.Errorf("ssob: Unknown type '%d': %w", ntype.ValType, ErrTypeUnknown) + } + + l := v.Len() + ret = append(ret, marshalUint32(uint32(l))...) + for i := 0; i < l; i++ { + tbytes, err := marshalType(v.Index(i).Interface(), stype) + if err != nil { + return ret, err + } + ret = append(ret, tbytes...) + } + + return ret, err +} + +func marshalArray(e interface{}, ntype *NType) (ret []byte, err error) { + v := reflect.ValueOf(e) + if v.Kind() != reflect.Array { + return ret, fmt.Errorf("ssob: Invalid value '%v': %w", v.Kind(), ErrValueInvalid) + } + + stype := getTypeById(ntype.ValType) + if stype == nil { + return ret, fmt.Errorf("ssob: Unknown type '%d': %w", ntype.ValType, ErrTypeUnknown) + } + + for i := 0; i < ntype.arrayLen; i++ { + tbytes, err := marshalType(v.Index(i).Interface(), stype) + if err != nil { + return ret, err + } + ret = append(ret, tbytes...) + } + + return ret, err +} + +func marshalStruct(e interface{}, ntype *NType) (ret []byte, err error) { + v := reflect.ValueOf(e) + if v.Kind() != reflect.Struct { + return ret, fmt.Errorf("ssob: Invalid value '%v': %w", v.Kind(), ErrValueInvalid) + } + + stype := getTypeById(ntype.ValType) + if stype == nil { + return ret, fmt.Errorf("ssob: Unknown type '%d': %w", ntype.ValType, ErrTypeUnknown) + } + + for i, field := range stype.structFields { + ftype := getTypeById(field.Id) + if ftype == nil { + return ret, fmt.Errorf("ssob: Unknown type '%d': %w", field.Id, ErrTypeUnknown) + } + slog.LOG_DEBUGFLN("sfield: %v", ftype) + tbytes, err := marshalType(v.Field(i).Interface(), ftype) + if err != nil { + return ret, err + } + ret = append(ret, tbytes...) + } + + return ret, err +} + +func marshalInterface(e interface{}, ntype *NType) (ret []byte, err error) { + stype := getTypeById(ntype.ValType) + if stype == nil { + return ret, fmt.Errorf("ssob: Unknown type '%d': %w", ntype.ValType, ErrTypeUnknown) + } + + return marshalCommon(e, ntype) +} + +func marshalType(e interface{}, ntype *NType) (ret []byte, err error) { + switch ntype.MainTypeId { + case ST_COMMON: + return marshalCommon(e, ntype) + case ST_SLICE: + return marshalSlice(e, ntype) + case ST_ARRAY: + return marshalArray(e, ntype) + case ST_STRUCT: + return marshalStruct(e, ntype) + case ST_INTERFACE: + return marshalInterface(e, ntype) + default: + return ret, fmt.Errorf("ssob: Unknown type '%d': %w", ntype.MainTypeId, ErrTypeUnknown) + } +} + +func marshalVal(e interface{}) (ret []byte, err error) { + i, n, nl, err := indirectType(e) + if err != nil { + return ret, err + } + slog.LOG_DEBUGFLN("i: %v | n: %v | nl: %v | err: %v", i, n, nl, err) + + // type id + bytes := marshalTypeId(n.Id) + + // nil pointer + if i == nil { + bytes = append(bytes, marshalTypeId(ST_NIL)...) + bytes = append(bytes, marshalNil(nl)...) + } else { + if tbytes, err := marshalType(i, n); err != nil { + return ret, err + } else { + bytes = append(bytes, tbytes...) + } + } + + ret = append(ret, marshalUint32(uint32(len(bytes)))...) + ret = append(ret, bytes...) + + return ret, err +} diff --git a/types.go b/types.go index b7debd6..1d5f654 100644 --- a/types.go +++ b/types.go @@ -12,6 +12,7 @@ type allocatorFunc func(vals ...interface{}) interface{} type marshallerFunc func(interface{}, io.Writer) error type unmarshallerFunc func(io.Reader) (interface{}, error) +type marshalFunc func(interface{}) ([]byte, error) type nallocFunc func() interface{} type RegisteredTypes struct { @@ -23,16 +24,16 @@ type RegisteredTypes struct { } const ( - ST_COMMON = 0 - ST_SLICE = 1 - ST_ARRAY = 2 - ST_STRUCT = 3 - ST_MAP = 4 - ST_INTERFACE = 5 - ST_STRUCT_FIELD = 6 + ST_COMMON = 0 + ST_SLICE = 1 + ST_ARRAY = 2 + ST_STRUCT = 3 + ST_MAP = 4 + ST_INTERFACE = 5 ) type StructField struct { + Id uint32 Name string Tag string } @@ -42,8 +43,9 @@ type NType struct { Id uint32 Indirection int MainTypeId uint32 - ValTypes []uint32 + ValType uint32 structFields []*StructField + arrayLen int alloc nallocFunc } @@ -79,6 +81,7 @@ const ( ST_FLOAT64 = 11 ST_STRING = 12 ST_ERROR = 13 + ST_NIL = 14 ) func init() { @@ -89,96 +92,103 @@ func init() { cacheTypes.nnames = make(map[string]*NType) boolType := &NType{ - "bool", ST_BOOL, 0, ST_COMMON, []uint32{ST_BOOL}, - nil, func() interface{} { return new(bool) }, + "bool", ST_BOOL, 0, ST_COMMON, ST_BOOL, nil, + 0, func() interface{} { return new(bool) }, } cacheTypes.ntypes[ST_BOOL] = boolType cacheTypes.nnames["bool"] = boolType uint8Type := &NType{ - "uint8", ST_UINT8, 0, ST_COMMON, []uint32{ST_UINT8}, - nil, func() interface{} { return new(uint8) }, + "uint8", ST_UINT8, 0, ST_COMMON, ST_UINT8, nil, + 0, func() interface{} { return new(uint8) }, } cacheTypes.ntypes[ST_UINT8] = uint8Type cacheTypes.nnames["uint8"] = uint8Type uint16Type := &NType{ - "uint16", ST_UINT16, 0, ST_COMMON, []uint32{ST_UINT16}, - nil, func() interface{} { return new(uint16) }, + "uint16", ST_UINT16, 0, ST_COMMON, ST_UINT16, nil, + 0, func() interface{} { return new(uint16) }, } cacheTypes.ntypes[ST_UINT16] = uint16Type cacheTypes.nnames["uint16"] = uint16Type uint32Type := &NType{ - "uint32", ST_UINT32, 0, ST_COMMON, []uint32{ST_UINT32}, - nil, func() interface{} { return new(uint32) }, + "uint32", ST_UINT32, 0, ST_COMMON, ST_UINT32, nil, + 0, func() interface{} { return new(uint32) }, } cacheTypes.ntypes[ST_UINT32] = uint32Type cacheTypes.nnames["uint32"] = uint32Type uint64Type := &NType{ - "uint64", ST_UINT64, 0, ST_COMMON, []uint32{ST_UINT64}, - nil, func() interface{} { return new(uint64) }, + "uint64", ST_UINT64, 0, ST_COMMON, ST_UINT64, nil, + 0, func() interface{} { return new(uint64) }, } cacheTypes.ntypes[ST_UINT64] = uint64Type cacheTypes.nnames["uint64"] = uint64Type int8Type := &NType{ - "int8", ST_INT8, 0, ST_COMMON, []uint32{ST_INT8}, - nil, func() interface{} { return new(int8) }, + "int8", ST_INT8, 0, ST_COMMON, ST_INT8, nil, + 0, func() interface{} { return new(int8) }, } cacheTypes.ntypes[ST_INT8] = int8Type cacheTypes.nnames["int8"] = int8Type int16Type := &NType{ - "int16", ST_INT16, 0, ST_COMMON, []uint32{ST_INT16}, - nil, func() interface{} { return new(int16) }, + "int16", ST_INT16, 0, ST_COMMON, ST_INT16, nil, + 0, func() interface{} { return new(int16) }, } cacheTypes.ntypes[ST_INT16] = int16Type cacheTypes.nnames["int16"] = int16Type int32Type := &NType{ - "int32", ST_INT32, 0, ST_COMMON, []uint32{ST_INT32}, - nil, func() interface{} { return new(int32) }, + "int32", ST_INT32, 0, ST_COMMON, ST_INT32, nil, + 0, func() interface{} { return new(int32) }, } cacheTypes.ntypes[ST_INT32] = int32Type cacheTypes.nnames["int32"] = int32Type int64Type := &NType{ - "int64", ST_INT64, 0, ST_COMMON, []uint32{ST_INT64}, - nil, func() interface{} { return new(int64) }, + "int64", ST_INT64, 0, ST_COMMON, ST_INT64, nil, + 0, func() interface{} { return new(int64) }, } cacheTypes.ntypes[ST_INT64] = int64Type cacheTypes.nnames["int64"] = int64Type float32Type := &NType{ - "float32", ST_FLOAT32, 0, ST_COMMON, []uint32{ST_FLOAT32}, - nil, func() interface{} { return new(float32) }, + "float32", ST_FLOAT32, 0, ST_COMMON, ST_FLOAT32, nil, + 0, func() interface{} { return new(float32) }, } cacheTypes.ntypes[ST_FLOAT32] = float32Type cacheTypes.nnames["float32"] = float32Type float64Type := &NType{ - "float64", ST_FLOAT64, 0, ST_COMMON, []uint32{ST_FLOAT64}, - nil, func() interface{} { return new(float64) }, + "float64", ST_FLOAT64, 0, ST_COMMON, ST_FLOAT64, nil, + 0, func() interface{} { return new(float64) }, } cacheTypes.ntypes[ST_FLOAT64] = float64Type cacheTypes.nnames["float64"] = float64Type stringType := &NType{ - "string", ST_STRING, 0, ST_COMMON, []uint32{ST_STRING}, - nil, func() interface{} { return new(string) }, + "string", ST_STRING, 0, ST_COMMON, ST_STRING, nil, + 0, func() interface{} { return new(string) }, } cacheTypes.ntypes[ST_STRING] = stringType cacheTypes.nnames["string"] = stringType errorType := &NType{ - "error", ST_ERROR, 0, ST_COMMON, []uint32{ST_ERROR}, - nil, func() interface{} { return new(error) }, + "error", ST_ERROR, 0, ST_COMMON, ST_ERROR, nil, + 0, func() interface{} { return new(error) }, } cacheTypes.ntypes[ST_ERROR] = errorType cacheTypes.nnames["error"] = errorType + nilType := &NType{ + "nil", ST_NIL, 0, ST_NIL, ST_NIL, nil, + 0, func() interface{} { return nil }, + } + cacheTypes.ntypes[ST_NIL] = nilType + cacheTypes.nnames["nil"] = nilType + cacheTypes.types[ST_BOOL] = Type{ "bool", ST_BOOL, func(vals ...interface{}) interface{} { return new(bool) }, @@ -344,7 +354,7 @@ func getTypeByName(name string) (ret *NType) { } } -func parseType(t reflect.Type) (ret nallocFunc, mainTypeId uint32, indirection int, valTypes []uint32, base bool, sfields []*StructField, err error) { +func parseType(t reflect.Type) (ret nallocFunc, mainTypeId uint32, indirection int, valType uint32, base bool, sfields []*StructField, arrayLen int, err error) { indirection = 0 ret = func() interface{} { vret := reflect.New(t) @@ -361,8 +371,8 @@ func parseType(t reflect.Type) (ret nallocFunc, mainTypeId uint32, indirection i return vret.Interface() } - valTypes = []uint32{} sfields = []*StructField{} + arrayLen = 0 vret := reflect.New(t) val := vret.Elem() nval := vret @@ -385,25 +395,27 @@ func parseType(t reflect.Type) (ret nallocFunc, mainTypeId uint32, indirection i typ := reflect.TypeOf(val.Interface()) slog.LOG_DEBUGFLN("typ.Kind(): %s", typ.Kind()) slog.LOG_DEBUGFLN("val.Type(): %s", typ.Elem()) + slog.LOG_DEBUGFLN("SLICE") vt, err := getTypeByNameRegister(typ.Elem().String(), typ.Elem()) slog.LOG_DEBUGFLN("vt: %v", vt) if err != nil { - return ret, mainTypeId, indirection, valTypes, base, sfields, fmt.Errorf("ssob: Failed receiving type '%s': %w", typ.Elem(), err) + return ret, mainTypeId, indirection, valType, base, sfields, arrayLen, fmt.Errorf("ssob: Failed receiving type '%s': %w", typ.Elem(), err) } - valTypes = append(valTypes, vt.Id) + valType = vt.Id base = false mainTypeId = ST_SLICE case reflect.Array: typ := reflect.TypeOf(val.Interface()) + arrayLen = val.Len() slog.LOG_DEBUGFLN("typ.Kind(): %s", typ.Kind()) slog.LOG_DEBUGFLN("val.Type(): %s", typ.Elem()) + slog.LOG_DEBUGFLN("ARRAY") vt, err := getTypeByNameRegister(typ.Elem().String(), typ.Elem()) slog.LOG_DEBUGFLN("vt: %v", vt) if err != nil { - return ret, mainTypeId, indirection, valTypes, base, sfields, fmt.Errorf("ssob: Failed receiving type '%s': %w", typ.Elem(), err) + return ret, mainTypeId, indirection, valType, base, sfields, arrayLen, fmt.Errorf("ssob: Failed receiving type '%s': %w", typ.Elem(), err) } - valTypes = append(valTypes, uint32(val.Len())) - valTypes = append(valTypes, vt.Id) + valType = vt.Id base = false mainTypeId = ST_ARRAY case reflect.Interface: @@ -414,9 +426,9 @@ func parseType(t reflect.Type) (ret nallocFunc, mainTypeId uint32, indirection i vt, err := getTypeByNameRegister(typ.Elem().String(), typ.Elem()) slog.LOG_DEBUGFLN("vt: %v", vt) if err != nil { - return ret, mainTypeId, indirection, valTypes, base, sfields, fmt.Errorf("ssob: Failed receiving type '%s': %w", typ.Elem(), err) + return ret, mainTypeId, indirection, valType, base, sfields, arrayLen, fmt.Errorf("ssob: Failed receiving type '%s': %w", typ.Elem(), err) } - valTypes = append(valTypes, vt.Id) + valType = vt.Id } mainTypeId = ST_INTERFACE case reflect.Struct: @@ -427,9 +439,9 @@ func parseType(t reflect.Type) (ret nallocFunc, mainTypeId uint32, indirection i vt, err := getTypeByNameRegister(typ.String(), typ) slog.LOG_DEBUGFLN("vt: %v", vt) if err != nil { - return ret, mainTypeId, indirection, valTypes, base, sfields, fmt.Errorf("ssob: Failed receiving type '%s': %w", typ.Elem(), err) + return ret, mainTypeId, indirection, valType, base, sfields, arrayLen, fmt.Errorf("ssob: Failed receiving type '%s': %w", typ.Elem(), err) } - valTypes = append(valTypes, vt.Id) + valType = vt.Id } else { sl := val.NumField() for i := 0; i < sl; i++ { @@ -438,12 +450,12 @@ func parseType(t reflect.Type) (ret nallocFunc, mainTypeId uint32, indirection i sfield := new(StructField) sfield.Name = val.Type().Field(i).Name sfield.Tag = string(val.Type().Field(i).Tag) - sfields = append(sfields, sfield) vt, err := getTypeByNameRegister(val.Field(i).Type().String(), val.Field(i).Type()) if err != nil { - return ret, mainTypeId, indirection, valTypes, base, sfields, fmt.Errorf("ssob: Failed receiving type '%s': %w", typ.Elem(), err) + return ret, mainTypeId, indirection, valType, base, sfields, arrayLen, fmt.Errorf("ssob: Failed receiving type '%s': %w", typ.Elem(), err) } - valTypes = append(valTypes, vt.Id) + sfield.Id = vt.Id + sfields = append(sfields, sfield) } } base = false @@ -459,25 +471,25 @@ func parseType(t reflect.Type) (ret nallocFunc, mainTypeId uint32, indirection i vt, err := getTypeByNameRegister(typ.String(), typ) slog.LOG_DEBUGFLN("vt: %v", vt) if err != nil { - return ret, mainTypeId, indirection, valTypes, base, sfields, fmt.Errorf("ssob: Failed receiving type '%s': %w", typ.Elem(), err) + return ret, mainTypeId, indirection, valType, base, sfields, arrayLen, fmt.Errorf("ssob: Failed receiving type '%s': %w", typ.Elem(), err) } - valTypes = append(valTypes, vt.Id) + valType = vt.Id } else { // Key vt, err := getTypeByNameRegister(typ.Key().String(), typ.Key()) slog.LOG_DEBUGFLN("vt: %v", vt) if err != nil { - return ret, mainTypeId, indirection, valTypes, base, sfields, fmt.Errorf("ssob: Failed receiving type '%s': %w", typ.Elem(), err) + return ret, mainTypeId, indirection, valType, base, sfields, arrayLen, fmt.Errorf("ssob: Failed receiving type '%s': %w", typ.Elem(), err) } - valTypes = append(valTypes, vt.Id) + valType = vt.Id // Val vt, err = getTypeByNameRegister(typ.Elem().String(), typ.Elem()) slog.LOG_DEBUGFLN("vt: %v", vt) if err != nil { - return ret, mainTypeId, indirection, valTypes, base, sfields, fmt.Errorf("ssob: Failed receiving type '%s': %w", typ.Elem(), err) + return ret, mainTypeId, indirection, valType, base, sfields, arrayLen, fmt.Errorf("ssob: Failed receiving type '%s': %w", typ.Elem(), err) } - valTypes = append(valTypes, vt.Id) + valType = vt.Id base = false } mainTypeId = ST_MAP @@ -489,9 +501,9 @@ func parseType(t reflect.Type) (ret nallocFunc, mainTypeId uint32, indirection i vt, err := getTypeByNameRegister(typ.Kind().String(), typ) slog.LOG_DEBUGFLN("vt: %v", vt) if err != nil { - return ret, mainTypeId, indirection, valTypes, base, sfields, fmt.Errorf("ssob: Failed receiving type '%s': %w", typ.Elem(), err) + return ret, mainTypeId, indirection, valType, base, sfields, arrayLen, fmt.Errorf("ssob: Failed receiving type '%s': %w", typ.Elem(), err) } - valTypes = append(valTypes, vt.Id) + valType = vt.Id } mainTypeId = ST_COMMON } @@ -499,7 +511,7 @@ func parseType(t reflect.Type) (ret nallocFunc, mainTypeId uint32, indirection i } } - return ret, mainTypeId, indirection, valTypes, base, sfields, err + return ret, mainTypeId, indirection, valType, base, sfields, arrayLen, err } func getTypeByNameRegister(name string, t reflect.Type) (ret *NType, err error) { @@ -526,7 +538,7 @@ func createType(t reflect.Type) (ret *NType, base bool, err error) { ret = new(NType) ret.Name = t.String() slog.LOG_DEBUGFLN("t.Name(): %s", t) - ret.alloc, ret.MainTypeId, ret.Indirection, ret.ValTypes, base, ret.structFields, err = parseType(t) + ret.alloc, ret.MainTypeId, ret.Indirection, ret.ValType, base, ret.structFields, ret.arrayLen, err = parseType(t) return ret, base, err } @@ -547,7 +559,7 @@ func registerType(t reflect.Type) (err error) { } ntype.Id = cacheTypes.NextId if base { - ntype.ValTypes = []uint32{ntype.Id} + ntype.ValType = ntype.Id } cacheTypes.ntypes[ntype.Id] = ntype cacheTypes.nnames[ntype.Name] = ntype @@ -563,7 +575,55 @@ func registerType(t reflect.Type) (err error) { return err } +func splitType(e interface{}) (t reflect.Type, v reflect.Value, err error) { + t = reflect.TypeOf(e) + if t == nil || t.Kind() != reflect.Ptr { + return t, v, fmt.Errorf("ssob: Interface is not a valid address: %w", ErrTypeInvalid) + } + + v = reflect.ValueOf(e) + if v.IsNil() { + return t, v, fmt.Errorf("ssob: Got nil: %w", ErrValueInvalid) + } + + return t, v, err +} + +func indirectType(e interface{}) (ret interface{}, ntype *NType, nilLevel uint16, err error) { + nilLevel = 0 + + t, v, err := splitType(e) + if err != nil { + return nil, nil, nilLevel, err + } + + ntype, err = getTypeByNameRegister(t.Elem().String(), t.Elem()) + if err != nil { + return nil, nil, nilLevel, err + } + + for i := 0; i < ntype.Indirection; i++ { + v = reflect.Indirect(v) + if v.IsNil() { + nilLevel += uint16(i) + return nil, ntype, nilLevel, err + } + } + + return reflect.Indirect(v).Interface(), ntype, nilLevel, err +} + func RegisterType(e interface{}) (err error) { t := reflect.TypeOf(e) - return registerType(t) + if t == nil || t.Kind() != reflect.Ptr { + return fmt.Errorf("ssob: Interface is not a valid address: %w", ErrTypeInvalid) + } + + if err = registerType(t.Elem()); err != nil { + return err + } + + b, ee := marshalVal(e) + slog.LOG_DEBUGFLN("Bytes: %v | err: %v", b, ee) + return ee }