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) }