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 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_MINTERFACE = 5 ) type StructField struct { Id uint32 Name string Tag string SId int } 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 ST_INTERFACE = 15 ) func init() { cacheTypes.NextId = 128 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 interfaceType := &NType{ "interface {}", ST_INTERFACE, 0, ST_INTERFACE, ST_INTERFACE, nil, 0, func() interface{} { return new(interface{}) }, } cacheTypes.ntypes[ST_INTERFACE] = interfaceType cacheTypes.nnames["interface {}"] = interfaceType } 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, 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, err } valType = vt.Id base = false mainTypeId = ST_ARRAY 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, 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) slog.LOG_DEBUGFLN("ts: %v", val.Field(i).Type().String()) slog.LOG_DEBUGFLN("tt: %v", val.Field(i).Type()) vt, err := getTypeByNameRegister(val.Field(i).Type().String(), val.Field(i).Type()) if err != nil { return ret, mainTypeId, indirection, valType, base, sfields, arrayLen, err } sfield.Id = vt.Id sfield.SId = i 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, 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, err } valType = vt.Id // Val vt, err = getTypeByNameRegister(typ.Elem().String(), typ.Elem()) if err != nil { return ret, mainTypeId, indirection, valType, base, sfields, arrayLen, 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, 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 ErrTypeInvalid } if getTypeByName(t.String()) != nil { return nil } var base bool ntype, base, err := createType(t) if err != nil { return err } ntype.Id = cacheTypes.NextId if base { ntype.ValType = ntype.Id } cacheTypes.ntypes[ntype.Id] = ntype cacheTypes.nnames[ntype.Name] = ntype cacheTypes.NextId += 1 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, ErrTypeInvalid } v = reflect.ValueOf(e) if v.IsNil() { return t, v, 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++ { if v, err = indirectValue(v); err != nil { return nil, ntype, nilLevel, ErrValueInvalid } if v.IsValid() && v.IsNil() { nilLevel += uint16(i) return nil, ntype, nilLevel, err } } if v, err = indirectValue(v); err != nil { return nil, ntype, nilLevel, err } return v.Interface(), ntype, nilLevel, err } func setTypeNil(e interface{}, indirection int) (err error) { var v reflect.Value if v, err = getValPtr(e); err != nil { return err } if v, err = indirectValue(v); err != nil { if indirection > 0 { return ErrValueInvalid } } for i := 0; i < indirection; i++ { if v, err = indirectValue(v); err != nil { return err } } if v.IsValid() && !v.IsNil() { v.Set(reflect.Zero(reflect.TypeOf(v.Interface()))) } return err } func setTypeVal(e interface{}, val interface{}, ntype *NType) (err error) { var v reflect.Value if v, err = getValPtr(e); err != nil { return err } if v, err = indirectValue(v); err != nil { return err } for i := 0; i < ntype.Indirection; i++ { if v, err = indirectValue(v); err != nil { return err } } v.Set(reflect.ValueOf(val)) return err } func getValPtr(e interface{}) (ret reflect.Value, err error) { v := reflect.ValueOf(e) if !v.IsValid() || v.Kind() != reflect.Ptr || v.IsNil() { err = ErrValueInvalid } return v, err } func getVal(e interface{}) (ret reflect.Value) { v := reflect.ValueOf(e) if !v.IsValid() || v.Kind() != reflect.Ptr || v.IsNil() { return v } return reflect.Indirect(v) } func indirectValue(v reflect.Value) (ret reflect.Value, err error) { if !v.IsValid() || v.Kind() != reflect.Ptr { return v, ErrValueInvalid } ret = reflect.Indirect(v) return ret, err } func valueIsNil(v reflect.Value) (ret bool) { ret = false if !v.IsValid() || v.Kind() == reflect.Invalid || (v.Kind() == reflect.Ptr && v.IsNil()) { ret = true } return ret } func traverseValuePtr(v reflect.Value) (ret reflect.Value) { ret = v if !ret.IsValid() || ret.Kind() != reflect.Ptr { return ret } else { ret = reflect.Indirect(ret) return traverseValuePtr(ret) } } func parseInterface(e interface{}) (rett reflect.Type, retv reflect.Value, err error) { t := reflect.TypeOf(e) if t == nil || t.Kind() != reflect.Ptr { return nil, reflect.ValueOf(e), ErrTypeInvalid } if t.Elem().Kind() == reflect.Interface { rett = reflect.TypeOf(reflect.Indirect(reflect.ValueOf(e)).Interface()) retv = reflect.New(rett) retv.Elem().Set(reflect.ValueOf(reflect.Indirect(reflect.ValueOf(e)).Interface())) slog.LOG_DEBUGFLN("rett: %v", rett) slog.LOG_DEBUGFLN("retv: %v", retv) return rett, retv, nil } slog.LOG_DEBUGFLN("t: %v", t) slog.LOG_DEBUGFLN("v: %v", reflect.ValueOf(e)) return t, reflect.ValueOf(e), nil } func RegisterType(e interface{}) (err error) { //t := reflect.TypeOf(e) t, _, err := parseInterface(e) if err != nil { return err } 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 }