// TAI64 (if nanoseconds=0), or TAI64N
// - uint, uint8, uint16, uint32, uint64
// - uuid.UUID
-func FromGo(v any) Item {
+func FromGo(v any) (Item, error) {
if v == nil {
- return Item{T: types.NIL}
+ return Item{T: types.NIL}, nil
}
rv := reflect.ValueOf(v)
if b, ok := v.([]byte); ok {
- return Item{T: types.Bin, V: b}
+ return Item{T: types.Bin, V: b}, nil
}
switch v := v.(type) {
case *Blob:
- return Item{T: types.Blob, V: *v}
+ return Item{T: types.Blob, V: *v}, nil
case Blob:
- return Item{T: types.Blob, V: v}
+ return Item{T: types.Blob, V: v}, nil
case time.Time:
t := tai64n.Leapsecs.Add(v)
var taiRaw []byte
tai.FromTime(t)
taiRaw = tai[:]
}
- return Item{T: types.TAI64, V: taiRaw}
+ return Item{T: types.TAI64, V: taiRaw}, nil
case *atom.Raw:
- return Item{T: types.Raw, V: *v}
+ return Item{T: types.Raw, V: *v}, nil
case atom.Raw:
- return Item{T: types.Raw, V: v}
+ return Item{T: types.Raw, V: v}, nil
case *big.Int:
- return Item{T: types.BigInt, V: v}
+ return Item{T: types.BigInt, V: v}, nil
}
switch reflect.TypeOf(v).Kind() {
case reflect.Pointer:
if rv.IsNil() {
- return Item{T: types.NIL}
+ return Item{T: types.NIL}, nil
}
return FromGo(rv.Elem().Interface())
case reflect.Slice:
var ret []Item
+ var err error
if anys, ok := v.([]any); ok {
for _, v := range anys {
- ret = append(ret, FromGo(v))
+ var item Item
+ item, err = FromGo(v)
+ if err != nil {
+ return item, err
+ }
+ ret = append(ret, item)
}
} else {
rv = reflect.ValueOf(v)
for i := 0; i < rv.Len(); i++ {
- ret = append(ret, FromGo(rv.Index(i).Interface()))
+ var item Item
+ item, err = FromGo(rv.Index(i).Interface())
+ if err != nil {
+ return item, err
+ }
+ ret = append(ret, item)
}
}
- return Item{T: types.List, V: ret}
+ return Item{T: types.List, V: ret}, nil
case reflect.Map:
ret := make(map[string]Item, rv.Len())
iter := rv.MapRange()
+ var err error
for iter.Next() {
- ret[iter.Key().String()] = FromGo(iter.Value().Interface())
+ var item Item
+ item, err = FromGo(iter.Value().Interface())
+ if err != nil {
+ return item, err
+ }
+ ret[iter.Key().String()] = item
}
- return Item{T: types.Map, V: ret}
+ return Item{T: types.Map, V: ret}, nil
}
{
t := rv.Type()
fv := rv.FieldByIndex(f.Index)
name, omit := structTagRead(f)
var empty bool
- item := FromGo(fv.Interface())
+ item, err := FromGo(fv.Interface())
+ if err != nil {
+ return item, err
+ }
switch item.T {
case types.NIL:
empty = true
ret[name] = item
}
}
- return Item{T: types.Map, V: ret}
+ return Item{T: types.Map, V: ret}, nil
}
}
switch v := v.(type) {
case bool:
- return Item{T: types.Bool, V: v}
+ return Item{T: types.Bool, V: v}, nil
case uuid.UUID:
- return Item{T: types.UUID, V: v}
+ return Item{T: types.UUID, V: v}, nil
case uint:
- return Item{T: types.UInt, V: uint64(v)}
+ return Item{T: types.UInt, V: uint64(v)}, nil
case uint8:
- return Item{T: types.UInt, V: uint64(v)}
+ return Item{T: types.UInt, V: uint64(v)}, nil
case uint16:
- return Item{T: types.UInt, V: uint64(v)}
+ return Item{T: types.UInt, V: uint64(v)}, nil
case uint32:
- return Item{T: types.UInt, V: uint64(v)}
+ return Item{T: types.UInt, V: uint64(v)}, nil
case uint64:
- return Item{T: types.UInt, V: v}
+ return Item{T: types.UInt, V: v}, nil
case int:
if v >= 0 {
- return Item{T: types.UInt, V: uint64(v)}
+ return Item{T: types.UInt, V: uint64(v)}, nil
}
- return Item{T: types.Int, V: int64(v)}
+ return Item{T: types.Int, V: int64(v)}, nil
case int8:
if v >= 0 {
- return Item{T: types.UInt, V: uint64(v)}
+ return Item{T: types.UInt, V: uint64(v)}, nil
}
- return Item{T: types.Int, V: int64(v)}
+ return Item{T: types.Int, V: int64(v)}, nil
case int16:
if v >= 0 {
- return Item{T: types.UInt, V: uint64(v)}
+ return Item{T: types.UInt, V: uint64(v)}, nil
}
- return Item{T: types.Int, V: int64(v)}
+ return Item{T: types.Int, V: int64(v)}, nil
case int32:
if v >= 0 {
- return Item{T: types.UInt, V: uint64(v)}
+ return Item{T: types.UInt, V: uint64(v)}, nil
}
- return Item{T: types.Int, V: int64(v)}
+ return Item{T: types.Int, V: int64(v)}, nil
case int64:
if v >= 0 {
- return Item{T: types.UInt, V: uint64(v)}
+ return Item{T: types.UInt, V: uint64(v)}, nil
}
- return Item{T: types.Int, V: v}
+ return Item{T: types.Int, V: v}, nil
case string:
- return Item{T: types.Str, V: v}
+ return Item{T: types.Str, V: v}, nil
default:
- panic(fmt.Errorf("unhandled type: %+v", v))
+ return Item{}, fmt.Errorf("unhandled type: %+v", v)
}
}
// Convert an item to various native Go types, atom.Raw, Blob, uuid.UUID.
// Pay attention that f TAI equals to leap second, then it is converted to Raw.
-func (item Item) ToGo() any {
+func (item Item) ToGo() (any, error) {
switch item.T {
case types.NIL:
- return nil
+ return nil, nil
case types.Bool:
- return item.V.(bool)
+ return item.V.(bool), nil
case types.UUID:
- return item.V.(uuid.UUID)
+ return item.V.(uuid.UUID), nil
case types.UInt:
- return item.V.(uint64)
+ return item.V.(uint64), nil
case types.Int:
- return item.V.(int64)
+ return item.V.(int64), nil
case types.List:
var ret []any
+ var err error
for _, v := range item.V.([]Item) {
- ret = append(ret, v.ToGo())
+ var e any
+ e, err = v.ToGo()
+ if err != nil {
+ return nil, err
+ }
+ ret = append(ret, e)
}
- return ret
+ return ret, nil
case types.Map:
ret := make(map[string]any)
+ var err error
for k, v := range item.V.(map[string]Item) {
- ret[k] = v.ToGo()
+ var e any
+ e, err = v.ToGo()
+ if err != nil {
+ return nil, err
+ }
+ ret[k] = e
}
- return ret
+ return ret, nil
case types.Blob:
- return item.V.(Blob)
+ return item.V.(Blob), nil
case types.BigInt:
- return item.V.(*big.Int)
+ return item.V.(*big.Int), nil
case types.Float:
panic("float is unsupported")
case types.TAI64:
tai := tai64n.TAI64(raw)
t, isLeap := tai64n.Leapsecs.Sub(tai.Time())
if isLeap {
- return atom.Raw{T: atom.TAI64, V: raw}
+ return atom.Raw{T: atom.TAI64, V: raw}, nil
}
- return t
+ return t, nil
case tai64n.TAI64NSize:
tai := tai64n.TAI64N(raw)
t, isLeap := tai64n.Leapsecs.Sub(tai.Time())
if isLeap {
- return atom.Raw{T: atom.TAI64N, V: raw}
+ return atom.Raw{T: atom.TAI64N, V: raw}, nil
}
- return t
+ return t, nil
case tai64n.TAI64NASize:
- return atom.Raw{T: atom.TAI64NA, V: raw}
+ return atom.Raw{T: atom.TAI64NA, V: raw}, nil
default:
- panic("unexpected TAI size")
+ panic("wrong TAI64 value")
}
case types.Bin:
- return item.V.([]byte)
+ return item.V.([]byte), nil
case types.Str:
- return item.V.(string)
+ return item.V.(string), nil
case types.Raw:
- return item.V.(atom.Raw)
+ return item.V.(atom.Raw), nil
default:
- panic(fmt.Errorf("unhandled type: %+v", item))
+ return nil, fmt.Errorf("unhandled type: %+v", item)
}
}