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 marshalFunc func(interface{}) ([]byte, 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 ) type StructField struct { Id uint32 Name string Tag string } type NType struct { Name string Id uint32 Indirection int MainTypeId uint32 ValType uint32 structFields []*StructField arrayLen int 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 ST_NIL = 14 ) 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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) }, 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, valType uint32, base bool, sfields []*StructField, arrayLen int, 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 return vret.Interface() } sfields = []*StructField{} arrayLen = 0 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 } else { switch val.Kind() { case reflect.Slice: typ := reflect.TypeOf(val.Interface()) vt, err := getTypeByNameRegister(typ.Elem().String(), typ.Elem()) if err != nil { return ret, mainTypeId, indirection, valType, base, sfields, arrayLen, fmt.Errorf("ssob: Failed receiving type '%s': %w", typ.Elem(), err) } valType = vt.Id base = false mainTypeId = ST_SLICE case reflect.Array: typ := reflect.TypeOf(val.Interface()) arrayLen = val.Len() vt, err := getTypeByNameRegister(typ.Elem().String(), typ.Elem()) if err != nil { return ret, mainTypeId, indirection, valType, base, sfields, arrayLen, fmt.Errorf("ssob: Failed receiving type '%s': %w", typ.Elem(), err) } valType = vt.Id base = false mainTypeId = ST_ARRAY case reflect.Interface: typ := reflect.TypeOf(nval.Interface()) if !base { vt, err := getTypeByNameRegister(typ.Elem().String(), typ.Elem()) if err != nil { return ret, mainTypeId, indirection, valType, base, sfields, arrayLen, fmt.Errorf("ssob: Failed receiving type '%s': %w", typ.Elem(), err) } valType = vt.Id } mainTypeId = ST_INTERFACE case reflect.Struct: typ := reflect.TypeOf(val.Interface()) if !base { vt, err := getTypeByNameRegister(typ.String(), typ) if err != nil { return ret, mainTypeId, indirection, valType, base, sfields, arrayLen, fmt.Errorf("ssob: Failed receiving type '%s': %w", typ.Elem(), err) } valType = vt.Id } else { sl := val.NumField() for i := 0; i < sl; i++ { if val.Field(i).CanSet() { sfield := new(StructField) sfield.Name = val.Type().Field(i).Name sfield.Tag = string(val.Type().Field(i).Tag) vt, err := getTypeByNameRegister(val.Field(i).Type().String(), val.Field(i).Type()) if err != nil { return ret, mainTypeId, indirection, valType, base, sfields, arrayLen, fmt.Errorf("ssob: Failed receiving type '%s': %w", typ.Elem(), err) } sfield.Id = vt.Id sfields = append(sfields, sfield) } } base = true } mainTypeId = ST_STRUCT case reflect.Map: typ := reflect.TypeOf(val.Interface()) if !base { vt, err := getTypeByNameRegister(typ.String(), typ) if err != nil { return ret, mainTypeId, indirection, valType, base, sfields, arrayLen, fmt.Errorf("ssob: Failed receiving type '%s': %w", typ.Elem(), err) } valType = vt.Id } else { // Key vt, err := getTypeByNameRegister(typ.Key().String(), typ.Key()) if err != nil { return ret, mainTypeId, indirection, valType, base, sfields, arrayLen, fmt.Errorf("ssob: Failed receiving type '%s': %w", typ.Elem(), err) } valType = vt.Id // Val vt, err = getTypeByNameRegister(typ.Elem().String(), typ.Elem()) if err != nil { return ret, mainTypeId, indirection, valType, base, sfields, arrayLen, fmt.Errorf("ssob: Failed receiving type '%s': %w", typ.Elem(), err) } valType = vt.Id base = false } mainTypeId = ST_MAP default: typ := reflect.TypeOf(val.Interface()) if !base { vt, err := getTypeByNameRegister(typ.Kind().String(), typ) if err != nil { return ret, mainTypeId, indirection, valType, base, sfields, arrayLen, fmt.Errorf("ssob: Failed receiving type '%s': %w", typ.Elem(), err) } valType = vt.Id } mainTypeId = ST_COMMON } break } } return ret, mainTypeId, indirection, valType, base, sfields, arrayLen, 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() ret.alloc, ret.MainTypeId, ret.Indirection, ret.ValType, base, ret.structFields, ret.arrayLen, 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.ValType = ntype.Id } cacheTypes.ntypes[ntype.Id] = ntype cacheTypes.nnames[ntype.Name] = ntype cacheTypes.NextId += 1 if ntype.MainTypeId == ST_STRUCT { for _, f := range ntype.structFields { slog.LOG_DEBUGFLN(" Field: %v", f) } } slog.LOG_DEBUGFLN("Type: %v registered", t) 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 setTypeNil(e interface{}, indirection int) (err error) { v := reflect.ValueOf(e) if v.Kind() != reflect.Ptr || v.IsNil() { return fmt.Errorf("ssob: Not a pointer: %w", ErrValueInvalid) } v = reflect.Indirect(v) if (v.Kind() != reflect.Ptr || v.IsNil()) && indirection > 0 { return fmt.Errorf("ssob: Not a pointer: %w", ErrValueInvalid) } for i := 0; i < indirection; i++ { v = reflect.Indirect(v) if v.Kind() != reflect.Ptr || v.IsNil() { return fmt.Errorf("ssob: Not a pointer: %w", ErrValueInvalid) } } slog.LOG_DEBUGFLN("test") if !v.IsNil() { v.Set(reflect.Zero(reflect.TypeOf(v.Interface()))) } return err } func setTypeVal(e interface{}, val interface{}, ntype *NType) (err error) { v := reflect.ValueOf(e) if v.Kind() != reflect.Ptr || v.IsNil() { return fmt.Errorf("ssob: Not a pointer: %w", ErrValueInvalid) } v = reflect.Indirect(v) for i := 0; i < ntype.Indirection; i++ { if v.Kind() != reflect.Ptr || v.IsNil() { return fmt.Errorf("ssob: Not a pointer: %w", ErrValueInvalid) } v = reflect.Indirect(v) } v.Set(reflect.ValueOf(val)) return err } func getVal(e interface{}) (ret reflect.Value) { v := reflect.ValueOf(e) if v.Kind() != reflect.Ptr || v.IsNil() { return v } return reflect.Indirect(v) } func RegisterType(e interface{}) (err error) { t := reflect.TypeOf(e) 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 } return nil }