diff --git a/decoder.go b/decoder.go index 1303d10..fa1aeba 100644 --- a/decoder.go +++ b/decoder.go @@ -81,10 +81,17 @@ func (dec *Decoder) NDecode() (ret interface{}, err error) { 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) + l := binary.BigEndian.Uint32(st) + b := make([]byte, l) + + var rl int + if rl, err = dec.r.Read(b); err != nil || rl != int(l) { + return nil, fmt.Errorf("ssob: Cannot decode value: %w", err) } + + _, ret, err = unmarshalVal(b) + if err != nil { + return ret, err + } + return getVal(ret).Interface(), err } diff --git a/encoder.go b/encoder.go index f3c4323..ef03336 100644 --- a/encoder.go +++ b/encoder.go @@ -69,7 +69,23 @@ func (enc *Encoder) EncodeValue(value reflect.Value) (err error) { func (enc *Encoder) NEncode(e interface{}) (err error) { RegisterType(e) - return enc.encode(e, 0) + for _, t := range cacheTypes.ntypes { + slog.LOG_DEBUGFLN("t: %v", t) + } + + var b []byte + if b, err = marshalVal(e); err != nil { + return fmt.Errorf("ssob: Cannot encode value: %w", err) + } + + enc.mutex.Lock() + defer enc.mutex.Unlock() + + if _, err = enc.w.Write(b); err != nil { + return fmt.Errorf("ssob: Cannot encode value: %w", err) + } + + return nil } func (enc *Encoder) encode(e interface{}, indirectLevel int) (err error) { diff --git a/marshal.go b/marshal.go index c48a0bc..ba82128 100644 --- a/marshal.go +++ b/marshal.go @@ -6,8 +6,6 @@ import ( "io" "math" "reflect" - - "gitea.olznet.de/OlzNet/slog" ) func MarshalString(in string) (ret []byte) { @@ -486,10 +484,11 @@ func baseTypeMarshaller(e interface{}, w io.Writer) (err error) { } func marshalBool(e bool) (ret []byte) { - ret = make([]byte, ST_ID_SIZE+1) - ret[0] = 1 + ret = make([]byte, 1) if e == true { ret[0] = 0 + } else { + ret[0] = 1 } return ret } @@ -581,12 +580,12 @@ func marshalPtrIfNil(e interface{}, ntype *NType) (ie interface{}, ret []byte, i 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 } + nl++ } ret = append(ret, marshalTypeId(ntype.ValType)...) @@ -602,14 +601,27 @@ func marshalError(e interface{}, ntype *NType) (ret []byte, err error) { return ret, err } + errorString := false for i := 0; i < ntype.Indirection; i++ { + t := reflect.TypeOf(v.Interface()) + + if t.String() == "errors.errorString" { + errorString = true + break + } 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 } + nl++ + } + + if errorString { + ret = append(ret, marshalTypeId(ST_STRING)...) + ret = append(ret, marshalString(fmt.Sprintf("%v", v.Interface()))...) + return ret, err } ierr, ok := v.Interface().(error) @@ -795,7 +807,6 @@ func marshalStruct(e interface{}, ntype *NType) (ret []byte, err error) { 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 @@ -837,16 +848,18 @@ func marshalVal(e interface{}) (ret []byte, err error) { 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)...) + // nil + bytes = append(bytes, marshalBool(true)...) + //bytes = append(bytes, marshalTypeId(ST_NIL)...) bytes = append(bytes, marshalNil(nl)...) } else { + bytes = append(bytes, marshalBool(false)...) if tbytes, err := marshalType(i, n); err != nil { return ret, err } else { diff --git a/types.go b/types.go index 1d5f654..c1f839d 100644 --- a/types.go +++ b/types.go @@ -368,6 +368,7 @@ func parseType(t reflect.Type) (ret nallocFunc, mainTypeId uint32, indirection i break } } + //return vret return vret.Interface() } @@ -386,18 +387,11 @@ func parseType(t reflect.Type) (ret nallocFunc, mainTypeId uint32, indirection i 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()) - 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, valType, base, sfields, arrayLen, fmt.Errorf("ssob: Failed receiving type '%s': %w", typ.Elem(), err) } @@ -407,11 +401,7 @@ func parseType(t reflect.Type) (ret nallocFunc, mainTypeId uint32, indirection i 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, valType, base, sfields, arrayLen, fmt.Errorf("ssob: Failed receiving type '%s': %w", typ.Elem(), err) } @@ -420,11 +410,8 @@ func parseType(t reflect.Type) (ret nallocFunc, mainTypeId uint32, indirection i 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, valType, base, sfields, arrayLen, fmt.Errorf("ssob: Failed receiving type '%s': %w", typ.Elem(), err) } @@ -433,11 +420,8 @@ func parseType(t reflect.Type) (ret nallocFunc, mainTypeId uint32, indirection i 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, valType, base, sfields, arrayLen, fmt.Errorf("ssob: Failed receiving type '%s': %w", typ.Elem(), err) } @@ -446,7 +430,6 @@ func parseType(t reflect.Type) (ret nallocFunc, mainTypeId uint32, indirection i 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) @@ -458,18 +441,13 @@ func parseType(t reflect.Type) (ret nallocFunc, mainTypeId uint32, indirection i sfields = append(sfields, sfield) } } - base = false + base = true } 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, valType, base, sfields, arrayLen, fmt.Errorf("ssob: Failed receiving type '%s': %w", typ.Elem(), err) } @@ -477,7 +455,6 @@ func parseType(t reflect.Type) (ret nallocFunc, mainTypeId uint32, indirection i } else { // Key vt, err := getTypeByNameRegister(typ.Key().String(), typ.Key()) - slog.LOG_DEBUGFLN("vt: %v", vt) if err != nil { return ret, mainTypeId, indirection, valType, base, sfields, arrayLen, fmt.Errorf("ssob: Failed receiving type '%s': %w", typ.Elem(), err) } @@ -485,7 +462,6 @@ func parseType(t reflect.Type) (ret nallocFunc, mainTypeId uint32, indirection i // Val vt, err = getTypeByNameRegister(typ.Elem().String(), typ.Elem()) - slog.LOG_DEBUGFLN("vt: %v", vt) if err != nil { return ret, mainTypeId, indirection, valType, base, sfields, arrayLen, fmt.Errorf("ssob: Failed receiving type '%s': %w", typ.Elem(), err) } @@ -495,11 +471,8 @@ func parseType(t reflect.Type) (ret nallocFunc, mainTypeId uint32, indirection i 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, valType, base, sfields, arrayLen, fmt.Errorf("ssob: Failed receiving type '%s': %w", typ.Elem(), err) } @@ -537,7 +510,6 @@ 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.ValType, base, ret.structFields, ret.arrayLen, err = parseType(t) return ret, base, err @@ -565,12 +537,12 @@ func registerType(t reflect.Type) (err error) { 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) } } + slog.LOG_DEBUGFLN("Type: %v registered", t) return err } @@ -613,6 +585,61 @@ func indirectType(e interface{}) (ret interface{}, ntype *NType, nilLevel uint16 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 { @@ -623,7 +650,5 @@ func RegisterType(e interface{}) (err error) { return err } - b, ee := marshalVal(e) - slog.LOG_DEBUGFLN("Bytes: %v | err: %v", b, ee) - return ee + return nil } diff --git a/unmarshal.go b/unmarshal.go index c8a9cba..46c450e 100644 --- a/unmarshal.go +++ b/unmarshal.go @@ -696,3 +696,342 @@ func baseTypeUnmarshaller(e uint32, r io.Reader) (ret interface{}, err error) { return ret, err } + +func unmarshalBool(e []byte) (ie []byte, ret bool) { + if e[0] == 0 { + ret = true + } else { + ret = false + } + return e[1:], ret +} + +func unmarshalUint8(e []byte) (ie []byte, ret uint8) { + return e[1:], uint8(byte(e[0])) +} + +func unmarshalUint16(e []byte) (ie []byte, ret uint16) { + return e[2:], binary.BigEndian.Uint16(e) +} + +func unmarshalUint32(e []byte) (ie []byte, ret uint32) { + return e[4:], binary.BigEndian.Uint32(e) +} + +func unmarshalUint64(e []byte) (ie []byte, ret uint64) { + return e[8:], binary.BigEndian.Uint64(e) +} + +func unmarshalInt8(e []byte) (ie []byte, ret int8) { + return e[1:], int8(byte(e[0])) +} + +func unmarshalInt16(e []byte) (ie []byte, ret int16) { + return e[2:], int16(binary.BigEndian.Uint16(e)) +} + +func unmarshalInt32(e []byte) (ie []byte, ret int32) { + return e[4:], int32(binary.BigEndian.Uint32(e)) +} + +func unmarshalInt64(e []byte) (ie []byte, ret int64) { + return e[8:], int64(binary.BigEndian.Uint64(e)) +} + +func unmarshalFloat32(e []byte) (ie []byte, ret float32) { + return e[4:], float32(math.Float32frombits(binary.BigEndian.Uint32(e))) +} + +func unmarshalFloat64(e []byte) (ie []byte, ret float64) { + return e[8:], float64(math.Float64frombits(binary.BigEndian.Uint64(e))) +} + +func unmarshalString(e []byte) (ie []byte, ret string) { + slen := binary.BigEndian.Uint32(e) + ret = string(e[4 : 4+slen]) + return e[4+slen:], ret +} + +func unmarshalNil(e []byte) (ie []byte, ret uint16) { + return unmarshalUint16(e) +} + +func unmarshalPtrIfNil(e []byte, ntype *NType) (ie []byte, ret interface{}, isNil bool, err error) { + if ntype.Indirection == 0 { + return e, nil, false, err + } + + ret = ntype.alloc() + + var nl uint16 + ie, eId := unmarshalTypeId(e) + if eId == ST_NIL { + ie, nl = unmarshalNil(ie) + err = setTypeNil(ret, int(nl)) + return ie, ret, true, err + } + + if ntype.ValType == ST_ERROR { + return e, ret, false, err + } + + if eId != ntype.ValType { + return ie, ret, false, fmt.Errorf("Type mismatch") + } + + return ie, ret, false, err +} + +func unmarshalError(e []byte, ntype *NType) (ie []byte, ret interface{}, err error) { + ret = ntype.alloc() + + var nl uint16 + ie, eId := unmarshalTypeId(e) + if eId == ST_NIL { + ie, nl = unmarshalNil(ie) + err = setTypeNil(ret, int(nl)) + return ie, ret, err + } + + if eId != ST_STRING { + return ie, ret, fmt.Errorf("Type mismatch") + } + ie, v := unmarshalString(ie) + + err = setTypeVal(ret, fmt.Errorf(v), ntype) + return ie, ret, err +} + +func unmarshalTypeId(e []byte) (ie []byte, ret uint32) { + return unmarshalUint32(e) +} + +func unmarshalCommon(e []byte, ntype *NType) (ie []byte, ret interface{}, err error) { + ctype := getTypeById(ntype.ValType) + if ctype == nil { + return e, ret, fmt.Errorf("ssob: Unknown common type '%d': %w", ntype.ValType, ErrTypeUnknown) + } + + // pointer could be nil + ie, ptrNil, isNil, err := unmarshalPtrIfNil(e, ntype) + if err != nil { + return ie, ret, fmt.Errorf("ssob: Cannot unmarshal common type '%s': %w", ntype.Name, err) + } + + if ptrNil != nil { + if isNil { + return ie, ptrNil, err + } + ret = ptrNil + } + if ret == nil { + ret = ntype.alloc() + } + + switch ctype.Id { + case ST_BOOL: + var v bool + ie, v = unmarshalBool(ie) + setTypeVal(ret, v, ntype) + return ie, ret, err + case ST_UINT8: + var v uint8 + ie, v = unmarshalUint8(ie) + setTypeVal(ret, v, ntype) + return ie, ret, err + case ST_UINT16: + var v uint16 + ie, v = unmarshalUint16(ie) + setTypeVal(ret, v, ntype) + return ie, ret, err + case ST_UINT32: + var v uint32 + ie, v = unmarshalUint32(ie) + setTypeVal(ret, v, ntype) + return ie, ret, err + case ST_UINT64: + var v uint64 + ie, v = unmarshalUint64(ie) + setTypeVal(ret, v, ntype) + return ie, ret, err + case ST_INT8: + var v int8 + ie, v = unmarshalInt8(ie) + setTypeVal(ret, v, ntype) + return ie, ret, err + case ST_INT16: + var v int16 + ie, v = unmarshalInt16(ie) + setTypeVal(ret, v, ntype) + return ie, ret, err + case ST_INT32: + var v int32 + ie, v = unmarshalInt32(ie) + setTypeVal(ret, v, ntype) + return ie, ret, err + case ST_INT64: + var v int64 + ie, v = unmarshalInt64(ie) + setTypeVal(ret, v, ntype) + return ie, ret, err + case ST_FLOAT32: + var v float32 + ie, v = unmarshalFloat32(ie) + setTypeVal(ret, v, ntype) + return ie, ret, err + case ST_FLOAT64: + var v float64 + ie, v = unmarshalFloat64(ie) + setTypeVal(ret, v, ntype) + return ie, ret, err + case ST_STRING: + var v string + ie, v = unmarshalString(ie) + setTypeVal(ret, v, ntype) + return ie, ret, err + case ST_ERROR: + return unmarshalError(ie, ntype) + default: + return ie, ret, fmt.Errorf("ssob: Unknown common type '%d': %w", ctype.Id, ErrTypeUnknown) + } +} + +func unmarshalSlice(e []byte, ntype *NType) (ie []byte, ret interface{}, err error) { + ret = ntype.alloc() + rv := getVal(ret) + ie, l := unmarshalUint32(e) + + stype := getTypeById(ntype.ValType) + if stype == nil { + return ie, ret, fmt.Errorf("ssob: Unknown type '%d': %w", ntype.ValType, ErrTypeUnknown) + } + + var v interface{} + for i := 0; i < int(l); i++ { + ie, v, err = unmarshalType(ie, stype) + if err != nil { + return ie, ret, err + } + + rv.Set(reflect.Append(rv, getVal(v))) + } + + return ie, ret, err +} + +func unmarshalArray(e []byte, ntype *NType) (ie []byte, ret interface{}, err error) { + ret = ntype.alloc() + rv := getVal(ret) + + stype := getTypeById(ntype.ValType) + if stype == nil { + return ie, ret, fmt.Errorf("ssob: Unknown type '%d': %w", ntype.ValType, ErrTypeUnknown) + } + + var v interface{} + ie = e + for i := 0; i < ntype.arrayLen; i++ { + ie, v, err = unmarshalType(ie, stype) + if err != nil { + return ie, ret, err + } + rv.Index(i).Set(getVal(v)) + } + + return ie, ret, err +} + +func unmarshalStruct(e []byte, ntype *NType) (ie []byte, ret interface{}, err error) { + ret = ntype.alloc() + rv := getVal(ret) + ie = e + + stype := getTypeById(ntype.ValType) + if stype == nil { + return ie, ret, fmt.Errorf("ssob: Unknown type '%d': %w", ntype.ValType, ErrTypeUnknown) + } + + var v interface{} + for i, field := range stype.structFields { + for j := i; j < rv.NumField(); j++ { + if rv.Field(j).CanSet() { + ftype := getTypeById(field.Id) + if ftype == nil { + return ie, ret, fmt.Errorf("ssob: Unknown type '%d': %w", field.Id, ErrTypeUnknown) + } + + ie, v, err = unmarshalType(ie, ftype) + if err != nil { + return ie, ret, err + } + rv.Field(j).Set(getVal(v)) + break + } + } + } + + return ie, ret, err +} + +func unmarshalInterface(e []byte, ntype *NType) (ie []byte, ret interface{}, err error) { + ie = e + stype := getTypeById(ntype.ValType) + if stype == nil { + return ie, ret, fmt.Errorf("ssob: Unknown type '%d': %w", ntype.ValType, ErrTypeUnknown) + } + + return unmarshalCommon(ie, ntype) +} + +func unmarshalType(e []byte, ntype *NType) (ie []byte, ret interface{}, err error) { + switch ntype.MainTypeId { + case ST_COMMON: + return unmarshalCommon(e, ntype) + case ST_SLICE: + return unmarshalSlice(e, ntype) + case ST_ARRAY: + return unmarshalArray(e, ntype) + case ST_STRUCT: + return unmarshalStruct(e, ntype) + case ST_INTERFACE: + return unmarshalInterface(e, ntype) + default: + return e, ret, fmt.Errorf("ssob: Unknown type '%d': %w", ntype.MainTypeId, ErrTypeUnknown) + } +} + +func unmarshalVal(e []byte) (ie []byte, ret interface{}, err error) { + if len(e) < ST_ID_SIZE { + return ie, ret, fmt.Errorf("ssob: Cannot unmarshal: %w", ErrValueInvalid) + } + + // type id + var tid uint32 + ie, tid = unmarshalTypeId(e) + vt := getTypeById(tid) + if vt == nil { + return ie, ret, fmt.Errorf("ssob: Unknown type '%d': %w", tid, ErrTypeUnknown) + } + + // alloc + ret = vt.alloc() + + // check for nil + if len(ie) < 1 { + return ie, ret, fmt.Errorf("ssob: Cannot unmarshal: %w", ErrValueInvalid) + } + ie, isNil := unmarshalBool(ie) + if isNil { + if len(ie) < 2 { + return ie, ret, fmt.Errorf("ssob: Cannot unmarshal: %w", ErrValueInvalid) + } + ie, nl := unmarshalNil(ie) + if int(nl) > vt.Indirection { + return ie, ret, fmt.Errorf("ssob: Cannot unmarshal: %w", ErrValueInvalid) + } + err = setTypeNil(ret, int(nl)) + return ie, ret, err + } + + return unmarshalType(ie, vt) +}