diff --git a/decoder.go b/decoder.go index 783280e..1303d10 100644 --- a/decoder.go +++ b/decoder.go @@ -7,6 +7,8 @@ import ( "io" "reflect" "sync" + + "gitea.olznet.de/OlzNet/slog" ) type Decoder struct { @@ -21,21 +23,23 @@ func NewDecoder(r io.Reader) *Decoder { } func (dec *Decoder) Decode(e interface{}) (err error) { - return dec.DecodeValue(reflect.ValueOf(e)) -} - -func (dec *Decoder) DecodeValue(value reflect.Value) (err error) { - if value.Type() == reflect.TypeOf(errors.New("")) || value.Type() == reflect.TypeOf((*error)(nil)) { + t := reflect.TypeOf(e) + slog.LOG_DEBUGFLN("Dec: %v", t) + if t == reflect.TypeOf(errors.New("")) || t == reflect.TypeOf((*error)(nil)) { var errstr string if err = dec.Decode(&errstr); err != nil { return err } if errstr != "" { - *value.Interface().(*error) = errors.New(errstr) + *e.(*error) = errors.New(errstr) } return nil } + return dec.DecodeValue(reflect.ValueOf(e)) +} + +func (dec *Decoder) DecodeValue(value reflect.Value) (err error) { if value.Kind() == reflect.Invalid { return fmt.Errorf("ssob: Cannot decode nil: %w", ErrValueInvalid) } @@ -66,3 +70,21 @@ func (dec *Decoder) DecodeValue(value reflect.Value) (err error) { _, err = unmarshal(value.Interface(), bb) return err } + +func (dec *Decoder) NDecode() (ret interface{}, err error) { + st := make([]byte, ST_ID_SIZE) + + dec.mutex.Lock() + defer dec.mutex.Unlock() + + if err = binary.Read(dec.r, binary.BigEndian, st); err != nil { + return nil, err + } + + stype := binary.BigEndian.Uint32(st) + if t, ok := cacheTypes.types[stype]; !ok { + return nil, fmt.Errorf("ssob: Decode type '%d' not registered: %w", stype, ErrTypeUnknown) + } else { + return t.unmarshal(dec.r) + } +} diff --git a/encoder.go b/encoder.go index df1c97f..f3c4323 100644 --- a/encoder.go +++ b/encoder.go @@ -7,6 +7,8 @@ import ( "io" "reflect" "sync" + + "gitea.olznet.de/OlzNet/slog" ) type Encoder struct { @@ -21,18 +23,26 @@ func NewEncoder(w io.Writer) *Encoder { } func (enc *Encoder) Encode(e interface{}) (err error) { + t := reflect.TypeOf(e) + slog.LOG_DEBUGFLN("Enc: %v", t) + if t == reflect.TypeOf(errors.New("")) || t == reflect.TypeOf((*error)(nil)).Elem() { + if reflect.ValueOf(e).IsNil() { + return enc.Encode(string("")) + } else { + return enc.Encode(e.(error).Error()) + } + } else if t == reflect.TypeOf((*error)(nil)) { + if reflect.Indirect(reflect.ValueOf(e)).IsNil() { + return enc.Encode(string("")) + } else { + return enc.Encode((*e.(*error)).Error()) + } + } + return enc.EncodeValue(reflect.ValueOf(e)) } 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 fmt.Errorf("ssob: Cannot encode nil: %w", ErrValueInvalid) } @@ -56,3 +66,43 @@ func (enc *Encoder) EncodeValue(value reflect.Value) (err error) { return binary.Write(enc.w, binary.BigEndian, w) } + +func (enc *Encoder) NEncode(e interface{}) (err error) { + RegisterType(e) + return enc.encode(e, 0) +} + +func (enc *Encoder) encode(e interface{}, indirectLevel int) (err error) { + t := reflect.TypeOf(e) + + if t.Kind() == reflect.Invalid { + return fmt.Errorf("ssob: Cannot encode nil: %w", ErrValueInvalid) + } + + v := reflect.ValueOf(e) + //slog.LOG_DEBUGFLN("ssob: encode t.name: %s", t.Name()) + //slog.LOG_DEBUGFLN("ssob: encode t.kind: %s", t.Kind()) + slog.LOG_DEBUGFLN("ssob: encode v.type: %s", v.Type()) + switch t.Kind() { + case reflect.Ptr: + if v.IsNil() { + return fmt.Errorf("ssob: Cannot encode nil pointer: %w", ErrValueInvalid) + } + p := reflect.Indirect(v) + return enc.encode(p.Interface(), indirectLevel+1) + case reflect.Struct: + return fmt.Errorf("ssob: Type '%s' named '%s' unknown: %w", t.Kind().String(), t.Name(), ErrTypeUnknown) + case reflect.Slice: + return fmt.Errorf("ssob: Type '%s' with types '%s' unknown: %w", t.Kind().String(), t.Elem().Kind().String(), ErrTypeUnknown) + case reflect.Array: + return fmt.Errorf("ssob: Type '%s' with types '%s' unknown: %w", t.Kind().String(), t.Name(), ErrTypeUnknown) + default: + if v, ok := cacheTypes.names[t.Kind().String()]; !ok { + return fmt.Errorf("ssob: Type '%s' unknown: %w", t.Kind().String(), ErrTypeUnknown) + } else { + enc.mutex.Lock() + defer enc.mutex.Unlock() + return cacheTypes.types[v].marshal(e, enc.w) + } + } +} diff --git a/go.mod b/go.mod index bddc18e..418d236 100644 --- a/go.mod +++ b/go.mod @@ -1,3 +1,5 @@ module gitea.olznet.de/OlzNet/ssob go 1.15 + +require gitea.olznet.de/OlzNet/slog v1.2.4 diff --git a/go.sum b/go.sum new file mode 100644 index 0000000..e2446b9 --- /dev/null +++ b/go.sum @@ -0,0 +1,2 @@ +gitea.olznet.de/OlzNet/slog v1.2.4 h1:22/+57/2J7EnFQAwT6xRENgvPeI2RwSmOWuXwkujpf4= +gitea.olznet.de/OlzNet/slog v1.2.4/go.mod h1:xHB0ZnXIXFdnISKpWvDnrBSl4dGB3rzQji36n2sbJXg= diff --git a/marshal.go b/marshal.go index 67f25b8..eb8f1be 100644 --- a/marshal.go +++ b/marshal.go @@ -3,6 +3,7 @@ package ssob import ( "encoding/binary" "fmt" + "io" "math" "reflect" ) @@ -416,3 +417,68 @@ func marshal(e interface{}) (ret []byte, err error) { func RegisterEncoder(name string, f MarshalFunc) { encoderCache[name] = f } + +func baseTypeMarshaller(e interface{}, w io.Writer) (err error) { + var sb []byte + + switch e.(type) { + case bool: + sb = make([]byte, ST_ID_SIZE+1) + binary.BigEndian.PutUint32(sb, ST_BOOL) + if e.(bool) == true { + sb[ST_ID_SIZE] = 0 + } else { + sb[ST_ID_SIZE] = 1 + } + case uint8: + sb = make([]byte, ST_ID_SIZE+1) + binary.BigEndian.PutUint32(sb, ST_UINT8) + sb[ST_ID_SIZE] = byte(e.(uint8)) + case uint16: + sb = make([]byte, ST_ID_SIZE+2) + binary.BigEndian.PutUint32(sb, ST_UINT16) + binary.BigEndian.PutUint16(sb[ST_ID_SIZE:], e.(uint16)) + case uint32: + sb = make([]byte, ST_ID_SIZE+4) + binary.BigEndian.PutUint32(sb, ST_UINT32) + binary.BigEndian.PutUint32(sb[ST_ID_SIZE:], e.(uint32)) + case uint64: + sb = make([]byte, ST_ID_SIZE+8) + binary.BigEndian.PutUint32(sb, ST_UINT64) + binary.BigEndian.PutUint64(sb[ST_ID_SIZE:], e.(uint64)) + case int8: + sb = make([]byte, ST_ID_SIZE+1) + binary.BigEndian.PutUint32(sb[ST_ID_SIZE:], ST_INT8) + sb[ST_ID_SIZE] = byte(e.(int8)) + case int16: + sb = make([]byte, ST_ID_SIZE+2) + binary.BigEndian.PutUint32(sb, ST_INT16) + binary.BigEndian.PutUint16(sb[ST_ID_SIZE:], uint16(e.(int16))) + case int32: + sb = make([]byte, ST_ID_SIZE+4) + binary.BigEndian.PutUint32(sb, ST_INT32) + binary.BigEndian.PutUint32(sb[ST_ID_SIZE:], uint32(e.(int32))) + case int64: + sb = make([]byte, ST_ID_SIZE+8) + binary.BigEndian.PutUint32(sb, ST_INT64) + binary.BigEndian.PutUint64(sb[ST_ID_SIZE:], uint64(e.(int64))) + case float32: + sb = make([]byte, ST_ID_SIZE+4) + binary.BigEndian.PutUint32(sb, ST_FLOAT32) + binary.BigEndian.PutUint32(sb[ST_ID_SIZE:], math.Float32bits(e.(float32))) + case float64: + sb = make([]byte, ST_ID_SIZE+8) + binary.BigEndian.PutUint32(sb, ST_FLOAT64) + binary.BigEndian.PutUint64(sb[ST_ID_SIZE:], math.Float64bits(e.(float64))) + case string: + slen := len(e.(string)) + sb = make([]byte, ST_ID_SIZE+slen+4) + binary.BigEndian.PutUint32(sb, ST_STRING) + binary.BigEndian.PutUint32(sb[ST_ID_SIZE:], uint32(slen)) + copy(sb[ST_ID_SIZE+4:], []byte(e.(string))) + default: + return fmt.Errorf("ssob: Unknown type: %s: %w", reflect.TypeOf(e), ErrValueInvalid) + } + + return binary.Write(w, binary.BigEndian, sb) +} diff --git a/types.go b/types.go new file mode 100644 index 0000000..b7debd6 --- /dev/null +++ b/types.go @@ -0,0 +1,569 @@ +package ssob + +import ( + "fmt" + "io" + "reflect" + + "gitea.olznet.de/OlzNet/slog" +) + +type allocatorFunc func(vals ...interface{}) interface{} +type marshallerFunc func(interface{}, io.Writer) error +type unmarshallerFunc func(io.Reader) (interface{}, error) + +type nallocFunc func() interface{} + +type RegisteredTypes struct { + NextId uint32 + types map[uint32]Type + names map[string]uint32 + ntypes map[uint32]*NType + nnames map[string]*NType +} + +const ( + ST_COMMON = 0 + ST_SLICE = 1 + ST_ARRAY = 2 + ST_STRUCT = 3 + ST_MAP = 4 + ST_INTERFACE = 5 + ST_STRUCT_FIELD = 6 +) + +type StructField struct { + Name string + Tag string +} + +type NType struct { + Name string + Id uint32 + Indirection int + MainTypeId uint32 + ValTypes []uint32 + structFields []*StructField + alloc nallocFunc +} + +type Type struct { + Name string + Id uint32 + alloc allocatorFunc + marshal marshallerFunc + unmarshal unmarshallerFunc +} + +type baseType struct { +} + +var cacheTypes RegisteredTypes + +const ( + ST_ID_SIZE = 4 +) + +const ( + ST_INVALID = 0 + ST_BOOL = 1 + ST_UINT8 = 2 + ST_UINT16 = 3 + ST_UINT32 = 4 + ST_UINT64 = 5 + ST_INT8 = 6 + ST_INT16 = 7 + ST_INT32 = 8 + ST_INT64 = 9 + ST_FLOAT32 = 10 + ST_FLOAT64 = 11 + ST_STRING = 12 + ST_ERROR = 13 +) + +func init() { + cacheTypes.NextId = 128 + cacheTypes.types = make(map[uint32]Type) + cacheTypes.names = make(map[string]uint32) + cacheTypes.ntypes = make(map[uint32]*NType) + cacheTypes.nnames = make(map[string]*NType) + + boolType := &NType{ + "bool", ST_BOOL, 0, ST_COMMON, []uint32{ST_BOOL}, + nil, 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) }, + } + 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) }, + } + 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) }, + } + 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) }, + } + 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) }, + } + 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) }, + } + 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) }, + } + 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) }, + } + 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) }, + } + 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) }, + } + 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) }, + } + 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) }, + } + cacheTypes.ntypes[ST_ERROR] = errorType + cacheTypes.nnames["error"] = errorType + + cacheTypes.types[ST_BOOL] = Type{ + "bool", ST_BOOL, + func(vals ...interface{}) interface{} { return new(bool) }, + baseTypeMarshaller, + func(r io.Reader) (interface{}, error) { return baseTypeUnmarshaller(ST_BOOL, r) }, + } + cacheTypes.names["bool"] = ST_BOOL + + cacheTypes.types[ST_UINT8] = Type{ + "uint8", ST_UINT8, + func(vals ...interface{}) interface{} { return new(uint8) }, + baseTypeMarshaller, + func(r io.Reader) (interface{}, error) { return baseTypeUnmarshaller(ST_UINT8, r) }, + } + cacheTypes.names["uint8"] = ST_UINT8 + + cacheTypes.types[ST_UINT16] = Type{ + "uint16", ST_UINT16, + func(vals ...interface{}) interface{} { return new(uint16) }, + baseTypeMarshaller, + func(r io.Reader) (interface{}, error) { return baseTypeUnmarshaller(ST_UINT16, r) }, + } + cacheTypes.names["uint16"] = ST_UINT16 + + cacheTypes.types[ST_UINT32] = Type{ + "uint32", ST_UINT32, + func(vals ...interface{}) interface{} { return new(uint32) }, + baseTypeMarshaller, + func(r io.Reader) (interface{}, error) { return baseTypeUnmarshaller(ST_UINT32, r) }, + } + cacheTypes.names["uint32"] = ST_UINT32 + + cacheTypes.types[ST_UINT64] = Type{ + "uint64", ST_UINT64, + func(vals ...interface{}) interface{} { return new(uint64) }, + baseTypeMarshaller, + func(r io.Reader) (interface{}, error) { return baseTypeUnmarshaller(ST_UINT64, r) }, + } + cacheTypes.names["uint64"] = ST_UINT64 + + cacheTypes.types[ST_INT8] = Type{ + "int8", ST_INT8, + func(vals ...interface{}) interface{} { return new(int8) }, + baseTypeMarshaller, + func(r io.Reader) (interface{}, error) { return baseTypeUnmarshaller(ST_INT8, r) }, + } + cacheTypes.names["int8"] = ST_UINT8 + + cacheTypes.types[ST_INT16] = Type{ + "int16", ST_INT16, + func(vals ...interface{}) interface{} { return new(int16) }, + baseTypeMarshaller, + func(r io.Reader) (interface{}, error) { return baseTypeUnmarshaller(ST_INT16, r) }, + } + cacheTypes.names["int16"] = ST_INT16 + + cacheTypes.types[ST_INT32] = Type{ + "int32", ST_INT32, + func(vals ...interface{}) interface{} { return new(int32) }, + baseTypeMarshaller, + func(r io.Reader) (interface{}, error) { return baseTypeUnmarshaller(ST_INT32, r) }, + } + cacheTypes.names["int32"] = ST_INT32 + + cacheTypes.types[ST_INT64] = Type{ + "int64", ST_INT64, + func(vals ...interface{}) interface{} { return new(int64) }, + baseTypeMarshaller, + func(r io.Reader) (interface{}, error) { return baseTypeUnmarshaller(ST_INT64, r) }, + } + cacheTypes.names["int64"] = ST_INT64 + + cacheTypes.types[ST_FLOAT32] = Type{ + "float32", ST_FLOAT32, + func(vals ...interface{}) interface{} { return new(float32) }, + baseTypeMarshaller, + func(r io.Reader) (interface{}, error) { return baseTypeUnmarshaller(ST_FLOAT32, r) }, + } + cacheTypes.names["float32"] = ST_FLOAT32 + + cacheTypes.types[ST_FLOAT64] = Type{ + "float64", ST_FLOAT64, + func(vals ...interface{}) interface{} { return new(float64) }, + baseTypeMarshaller, + func(r io.Reader) (interface{}, error) { return baseTypeUnmarshaller(ST_FLOAT64, r) }, + } + cacheTypes.names["float64"] = ST_FLOAT64 + + cacheTypes.types[ST_STRING] = Type{ + "string", ST_STRING, + func(vals ...interface{}) interface{} { return new(string) }, + baseTypeMarshaller, + func(r io.Reader) (interface{}, error) { return baseTypeUnmarshaller(ST_STRING, r) }, + } + cacheTypes.names["string"] = ST_STRING +} + +func getTypeId(e interface{}, indirectLevel int) (id uint32, level int) { + level = indirectLevel + t := reflect.TypeOf(e) + + if t.Kind() == reflect.Invalid { + return ST_INVALID, level + } + + v := reflect.ValueOf(e) + switch t.Kind() { + case reflect.Ptr: + if v.IsNil() { + return ST_INVALID, level + } + p := reflect.Indirect(v) + level += 1 + return getTypeId(p.Interface(), level) + } + + if id, ok := cacheTypes.names[t.Kind().String()]; ok { + return id, level + } + + return ST_INVALID, level +} + +func getIndirection(e interface{}, level int) (indirection int, maintype uint32, typ reflect.Type) { + indirection = level + maintype = ST_COMMON + + t := reflect.TypeOf(e) + v := reflect.ValueOf(e) + + switch t.Kind() { + case reflect.Ptr: + if v.IsNil() { + return indirection, maintype, t + } + p := reflect.Indirect(v) + indirection += 1 + return getIndirection(p.Interface(), indirection) + case reflect.Slice: + maintype = ST_SLICE + case reflect.Array: + maintype = ST_ARRAY + case reflect.Struct: + maintype = ST_STRUCT + } + + return indirection, maintype, t +} + +func getTypeById(id uint32) (ret *NType) { + if ret, ok := cacheTypes.ntypes[id]; !ok { + return nil + } else { + return ret + } +} + +func getTypeByName(name string) (ret *NType) { + if ret, ok := cacheTypes.nnames[name]; !ok { + return nil + } else { + return ret + } +} + +func parseType(t reflect.Type) (ret nallocFunc, mainTypeId uint32, indirection int, valTypes []uint32, base bool, sfields []*StructField, err error) { + indirection = 0 + ret = func() interface{} { + vret := reflect.New(t) + val := vret.Elem() + + for { + if val.Kind() == reflect.Ptr { + val.Set(reflect.New(val.Type().Elem())) + val = val.Elem() + } else { + break + } + } + return vret.Interface() + } + + valTypes = []uint32{} + sfields = []*StructField{} + vret := reflect.New(t) + val := vret.Elem() + nval := vret + + base = true + + for { + if val.Kind() == reflect.Ptr { + nval = nval.Elem() + val.Set(reflect.New(val.Type().Elem())) + val = val.Elem() + indirection += 1 + base = false + slog.LOG_DEBUGFLN("Indirection: %d", indirection) + } else { + slog.LOG_DEBUGFLN("ELSE: %v", t) + + switch val.Kind() { + case reflect.Slice: + typ := reflect.TypeOf(val.Interface()) + slog.LOG_DEBUGFLN("typ.Kind(): %s", typ.Kind()) + slog.LOG_DEBUGFLN("val.Type(): %s", typ.Elem()) + 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) + } + valTypes = append(valTypes, vt.Id) + base = false + mainTypeId = ST_SLICE + case reflect.Array: + typ := reflect.TypeOf(val.Interface()) + slog.LOG_DEBUGFLN("typ.Kind(): %s", typ.Kind()) + slog.LOG_DEBUGFLN("val.Type(): %s", typ.Elem()) + 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) + } + valTypes = append(valTypes, uint32(val.Len())) + valTypes = append(valTypes, vt.Id) + base = false + mainTypeId = ST_ARRAY + case reflect.Interface: + typ := reflect.TypeOf(nval.Interface()) + slog.LOG_DEBUGFLN("val.Type(): %s", typ.Elem()) + slog.LOG_DEBUGFLN("INTERFACE") + if !base { + 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) + } + valTypes = append(valTypes, vt.Id) + } + mainTypeId = ST_INTERFACE + case reflect.Struct: + typ := reflect.TypeOf(val.Interface()) + slog.LOG_DEBUGFLN("typ.Kind(): %s", typ.String()) + slog.LOG_DEBUGFLN("STRUCT") + if !base { + 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) + } + valTypes = append(valTypes, vt.Id) + } else { + sl := val.NumField() + for i := 0; i < sl; i++ { + if val.Field(i).CanSet() { + slog.LOG_DEBUGFLN("Struct '%s': Field '%d' '%s' -> '%v'", typ.String(), i, val.Type().Field(i).Name, val.Field(i).Type()) + 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) + } + valTypes = append(valTypes, vt.Id) + } + } + base = false + } + mainTypeId = ST_STRUCT + case reflect.Map: + typ := reflect.TypeOf(val.Interface()) + slog.LOG_DEBUGFLN("typ.Kind(): %s", typ.String()) + slog.LOG_DEBUGFLN("MAP") + slog.LOG_DEBUGFLN("key: %s", typ.Key()) + slog.LOG_DEBUGFLN("val: %s", typ.Elem()) + if !base { + 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) + } + valTypes = append(valTypes, 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) + } + valTypes = append(valTypes, 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) + } + valTypes = append(valTypes, vt.Id) + base = false + } + mainTypeId = ST_MAP + default: + typ := reflect.TypeOf(val.Interface()) + slog.LOG_DEBUGFLN("typ.Kind(): %s", typ.Kind()) + slog.LOG_DEBUGFLN("COMMON") + if !base { + 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) + } + valTypes = append(valTypes, vt.Id) + } + mainTypeId = ST_COMMON + } + break + } + } + + return ret, mainTypeId, indirection, valTypes, base, sfields, err +} + +func getTypeByNameRegister(name string, t reflect.Type) (ret *NType, err error) { + if ret = getTypeByName(name); ret != nil { + return ret, err + } + + if err = registerType(t); err != nil { + return ret, err + } + + if ret = getTypeByName(name); ret == nil { + return ret, fmt.Errorf("ssob: Failed registering type '%s'", name) + } + + return ret, err +} + +func createType(t reflect.Type) (ret *NType, base bool, err error) { + if t == nil { + return ret, base, fmt.Errorf("ssob: Cannot create Type from nil: %w", ErrTypeInvalid) + } + + 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) + + return ret, base, err +} + +func registerType(t reflect.Type) (err error) { + if t == nil || t.Kind() == reflect.Invalid { + return fmt.Errorf("ssob: Cannot register nil: %w", ErrTypeInvalid) + } + + if getTypeByName(t.String()) != nil { + return nil + } + + var base bool + ntype, base, err := createType(t) + if err != nil { + return fmt.Errorf("ssob: Cannot register type '%s': %w", t, err) + } + ntype.Id = cacheTypes.NextId + if base { + ntype.ValTypes = []uint32{ntype.Id} + } + cacheTypes.ntypes[ntype.Id] = ntype + cacheTypes.nnames[ntype.Name] = ntype + cacheTypes.NextId += 1 + + slog.LOG_DEBUGFLN("Registered type: %v", ntype) + if ntype.MainTypeId == ST_STRUCT { + for _, f := range ntype.structFields { + slog.LOG_DEBUGFLN(" Field: %v", f) + } + } + + return err +} + +func RegisterType(e interface{}) (err error) { + t := reflect.TypeOf(e) + return registerType(t) +} diff --git a/unmarshal.go b/unmarshal.go index d656aaf..c8a9cba 100644 --- a/unmarshal.go +++ b/unmarshal.go @@ -3,6 +3,7 @@ package ssob import ( "encoding/binary" "fmt" + "io" "math" "reflect" ) @@ -592,3 +593,106 @@ func unmarshal(e interface{}, in []byte) (n int, err error) { func RegisterDecoder(name string, f func(e interface{}, in []byte) (n int, err error)) { decoderCache[name] = f } + +func baseTypeUnmarshaller(e uint32, r io.Reader) (ret interface{}, err error) { + switch e { + case ST_BOOL: + sb := make([]byte, 1) + if err = binary.Read(r, binary.BigEndian, sb); err != nil { + return nil, fmt.Errorf("ssob: Decode bool failed: %w: %s", ErrValueInvalid, err.Error()) + } + ret = cacheTypes.types[ST_BOOL].alloc() + if sb[0] == byte(0) { + *(ret.(*bool)) = true + } else { + *(ret.(*bool)) = false + } + case ST_UINT8: + sb := make([]byte, 1) + if err = binary.Read(r, binary.BigEndian, sb); err != nil { + return nil, fmt.Errorf("ssob: Decode uint8 failed: %w: %s", ErrValueInvalid, err.Error()) + } + ret = cacheTypes.types[ST_UINT8].alloc() + *(ret.(*uint8)) = uint8(sb[0]) + case ST_UINT16: + sb := make([]byte, 2) + if err = binary.Read(r, binary.BigEndian, sb); err != nil { + return nil, fmt.Errorf("ssob: Decode uint16 failed: %w: %s", ErrValueInvalid, err.Error()) + } + ret = cacheTypes.types[ST_UINT16].alloc() + *(ret.(*uint16)) = binary.BigEndian.Uint16(sb[0:2]) + case ST_UINT32: + sb := make([]byte, 4) + if err = binary.Read(r, binary.BigEndian, sb); err != nil { + return nil, fmt.Errorf("ssob: Decode uint32 failed: %w: %s", ErrValueInvalid, err.Error()) + } + ret = cacheTypes.types[ST_UINT32].alloc() + *(ret.(*uint32)) = binary.BigEndian.Uint32(sb[0:4]) + case ST_UINT64: + sb := make([]byte, 8) + if err = binary.Read(r, binary.BigEndian, sb); err != nil { + return nil, fmt.Errorf("ssob: Decode uint64 failed: %w: %s", ErrValueInvalid, err.Error()) + } + ret = cacheTypes.types[ST_UINT64].alloc() + *(ret.(*uint64)) = binary.BigEndian.Uint64(sb[0:8]) + case ST_INT8: + sb := make([]byte, 1) + if err = binary.Read(r, binary.BigEndian, sb); err != nil { + return nil, fmt.Errorf("ssob: Decode int8 failed: %w: %s", ErrValueInvalid, err.Error()) + } + ret = cacheTypes.types[ST_INT8].alloc() + *(ret.(*int8)) = int8(sb[0]) + case ST_INT16: + sb := make([]byte, 2) + if err = binary.Read(r, binary.BigEndian, sb); err != nil { + return nil, fmt.Errorf("ssob: Decode int16 failed: %w: %s", ErrValueInvalid, err.Error()) + } + ret = cacheTypes.types[ST_INT16].alloc() + *(ret.(*int16)) = int16(binary.BigEndian.Uint16(sb[0:2])) + case ST_INT32: + sb := make([]byte, 4) + if err = binary.Read(r, binary.BigEndian, sb); err != nil { + return nil, fmt.Errorf("ssob: Decode int32 failed: %w: %s", ErrValueInvalid, err.Error()) + } + ret = cacheTypes.types[ST_INT32].alloc() + *(ret.(*int32)) = int32(binary.BigEndian.Uint32(sb[0:4])) + case ST_INT64: + sb := make([]byte, 8) + if err = binary.Read(r, binary.BigEndian, sb); err != nil { + return nil, fmt.Errorf("ssob: Decode int64 failed: %w: %s", ErrValueInvalid, err.Error()) + } + ret = cacheTypes.types[ST_INT64].alloc() + *(ret.(*int64)) = int64(binary.BigEndian.Uint64(sb[0:8])) + case ST_FLOAT32: + sb := make([]byte, 4) + if err = binary.Read(r, binary.BigEndian, sb); err != nil { + return nil, fmt.Errorf("ssob: Decode float32 failed: %w: %s", ErrValueInvalid, err.Error()) + } + ret = cacheTypes.types[ST_FLOAT32].alloc() + *(ret.(*float32)) = float32(math.Float32frombits(binary.BigEndian.Uint32(sb[0:4]))) + case ST_FLOAT64: + sb := make([]byte, 8) + if err = binary.Read(r, binary.BigEndian, sb); err != nil { + return nil, fmt.Errorf("ssob: Decode float64 failed: %w: %s", ErrValueInvalid, err.Error()) + } + ret = cacheTypes.types[ST_FLOAT64].alloc() + *(ret.(*float64)) = float64(math.Float64frombits(binary.BigEndian.Uint64(sb[0:8]))) + case ST_STRING: + sb := make([]byte, 4) + if err = binary.Read(r, binary.BigEndian, sb); err != nil { + return nil, fmt.Errorf("ssob: Decode string failed: %w: %s", ErrValueInvalid, err.Error()) + } + slen := binary.BigEndian.Uint32(sb[0:4]) + ret = cacheTypes.types[ST_STRING].alloc() + + sb = make([]byte, slen) + if err = binary.Read(r, binary.BigEndian, sb); err != nil { + return nil, fmt.Errorf("ssob: Decode string failed: %w: %s", ErrValueInvalid, err.Error()) + } + *(ret.(*string)) = string(sb) + default: + return nil, fmt.Errorf("ssob: Unknown type: %d: %w", e, ErrTypeInvalid) + } + + return ret, err +}