ipld-eth-server/vendor/github.com/polydawn/refmt/obj/unmarshalBuiltins.go
Elizabeth Engelman 36533f7c3f Update vendor directory and make necessary code changes
Fixes for new geth version
2019-09-25 16:32:27 -05:00

177 lines
5.2 KiB
Go

package obj
import (
"fmt"
"reflect"
. "github.com/polydawn/refmt/tok"
)
type ptrDerefDelegateUnmarshalMachine struct {
UnmarshalMachine // a delegate machine, already set for us by the slab
peelCount int // how deep the pointers go, already discoverd by the slab
ptr_rv reflect.Value // the top ptr, which we will use if setting to nil, or if we have to recursively make ptrs for `**X` types.
firstStep bool
}
func (mach *ptrDerefDelegateUnmarshalMachine) Reset(slab *unmarshalSlab, rv reflect.Value, _ reflect.Type) error {
mach.ptr_rv = rv
mach.firstStep = true
// we defer reseting the delegate machine until later, in case we get a nil, which can save a lot of time.
return nil
}
func (mach *ptrDerefDelegateUnmarshalMachine) Step(driver *Unmarshaller, slab *unmarshalSlab, tok *Token) (done bool, err error) {
// If first step: we have to do initializations.
if mach.firstStep {
mach.firstStep = false
// If nil: easy road. Nil the ptr.
if tok.Type == TNull {
mach.ptr_rv.Set(reflect.Zero(mach.ptr_rv.Type()))
return true, nil
}
// Walk the pointers: if some already exist, we accept them unmodified;
// if any are nil, make a new one, and recursively.
rv := mach.ptr_rv
for i := 0; i < mach.peelCount; i++ {
if rv.IsNil() {
rv.Set(reflect.New(rv.Type().Elem()))
rv = rv.Elem()
} else {
rv = rv.Elem()
}
}
if err := mach.UnmarshalMachine.Reset(slab, rv, rv.Type()); err != nil {
return true, err
}
}
// The remainder of the time: it's just delegation.
return mach.UnmarshalMachine.Step(driver, slab, tok)
}
type unmarshalMachinePrimitive struct {
kind reflect.Kind
rv reflect.Value
}
func (mach *unmarshalMachinePrimitive) Reset(_ *unmarshalSlab, rv reflect.Value, _ reflect.Type) error {
mach.rv = rv
return nil
}
func (mach *unmarshalMachinePrimitive) Step(_ *Unmarshaller, _ *unmarshalSlab, tok *Token) (done bool, err error) {
switch mach.kind {
case reflect.Bool:
switch tok.Type {
case TBool:
mach.rv.SetBool(tok.Bool)
return true, nil
default:
return true, ErrUnmarshalTypeCantFit{*tok, mach.rv, 0}
}
case reflect.String:
switch tok.Type {
case TString:
mach.rv.SetString(tok.Str)
return true, nil
default:
return true, ErrUnmarshalTypeCantFit{*tok, mach.rv, 0}
}
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
switch tok.Type {
case TInt:
mach.rv.SetInt(tok.Int)
return true, nil
case TUint:
mach.rv.SetInt(int64(tok.Uint)) // todo: overflow check
return true, nil
default:
return true, ErrUnmarshalTypeCantFit{*tok, mach.rv, 0}
}
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
switch tok.Type {
case TInt:
if tok.Int >= 0 {
mach.rv.SetUint(uint64(tok.Int))
return true, nil
}
return true, ErrUnmarshalTypeCantFit{*tok, mach.rv, 0}
case TUint:
mach.rv.SetUint(tok.Uint)
return true, nil
default:
return true, ErrUnmarshalTypeCantFit{*tok, mach.rv, 0}
}
case reflect.Float32, reflect.Float64:
switch tok.Type {
case TFloat64:
mach.rv.SetFloat(tok.Float64)
return true, nil
case TInt:
mach.rv.SetFloat(float64(tok.Int))
return true, nil
case TUint:
mach.rv.SetFloat(float64(tok.Uint))
return true, nil
default:
return true, ErrUnmarshalTypeCantFit{*tok, mach.rv, 0}
}
case reflect.Slice: // implicitly bytes; no other slices are "primitive"
switch tok.Type {
case TBytes:
mach.rv.SetBytes(tok.Bytes)
return true, nil
case TNull:
mach.rv.SetBytes(nil)
return true, nil
default:
return true, ErrUnmarshalTypeCantFit{*tok, mach.rv, 0}
}
case reflect.Array: // implicitly bytes; no other arrays are "primitive"
switch tok.Type {
case TBytes:
// Unfortunately, there does not seem to be any efficient way to bulk set the contents of a byte array via reflect.
// There are similar complaints regarding slices on the marshalling side: apparently, we have no choice but to loop.
n := mach.rv.Len()
// We match aggressively on length. If the provided input is too short, we reject that too: we assume you asked for a fixed-length array for a reason.
if len(tok.Bytes) != n {
return true, ErrUnmarshalTypeCantFit{*tok, mach.rv, n}
}
for i := 0; i < n; i++ {
mach.rv.Index(i).SetUint(uint64(tok.Bytes[i]))
}
return true, nil
case TNull:
if mach.rv.Len() != 0 {
return true, ErrUnmarshalTypeCantFit{*tok, mach.rv, 0}
}
mach.rv.SetBytes(nil)
return true, nil
default:
return true, ErrUnmarshalTypeCantFit{*tok, mach.rv, 0}
}
case reflect.Interface:
switch tok.Type {
case TString:
mach.rv.Set(reflect.ValueOf(tok.Str))
case TBytes:
mach.rv.Set(reflect.ValueOf(tok.Bytes))
case TBool:
mach.rv.Set(reflect.ValueOf(tok.Bool))
case TInt:
mach.rv.Set(reflect.ValueOf(tok.Int))
case TUint:
mach.rv.Set(reflect.ValueOf(tok.Uint))
case TFloat64:
mach.rv.Set(reflect.ValueOf(tok.Float64))
case TNull:
mach.rv.Set(reflect.ValueOf(nil))
default: // any of the other token types should not have been routed here to begin with.
panic(fmt.Errorf("unhandled: %v", mach.kind))
}
return true, nil
default:
panic(fmt.Errorf("unhandled: %v", mach.kind))
}
}