forked from cerc-io/ipld-eth-server
36533f7c3f
Fixes for new geth version
113 lines
3.8 KiB
Go
113 lines
3.8 KiB
Go
package obj
|
|
|
|
import (
|
|
"fmt"
|
|
"reflect"
|
|
|
|
. "github.com/polydawn/refmt/tok"
|
|
)
|
|
|
|
type unmarshalMachineWildcard struct {
|
|
target_rv reflect.Value
|
|
target_rt reflect.Type
|
|
delegate UnmarshalMachine // actual machine, once we've demuxed with the first token.
|
|
holder_rv reflect.Value // if set, handle to slot where slice is stored; content must be placed into target at end.
|
|
}
|
|
|
|
func (mach *unmarshalMachineWildcard) Reset(_ *unmarshalSlab, rv reflect.Value, rt reflect.Type) error {
|
|
mach.target_rv = rv
|
|
mach.target_rt = rt
|
|
mach.delegate = nil
|
|
mach.holder_rv = reflect.Value{}
|
|
return nil
|
|
}
|
|
|
|
func (mach *unmarshalMachineWildcard) Step(driver *Unmarshaller, slab *unmarshalSlab, tok *Token) (done bool, err error) {
|
|
if mach.delegate == nil {
|
|
done, err = mach.prepareDemux(driver, slab, tok)
|
|
if done {
|
|
return
|
|
}
|
|
}
|
|
done, err = mach.delegate.Step(driver, slab, tok)
|
|
if !done {
|
|
return
|
|
}
|
|
if mach.holder_rv.IsValid() {
|
|
mach.target_rv.Set(mach.holder_rv)
|
|
}
|
|
return
|
|
}
|
|
|
|
func (mach *unmarshalMachineWildcard) prepareDemux(driver *Unmarshaller, slab *unmarshalSlab, tok *Token) (done bool, err error) {
|
|
// If a "tag" is set in the token, we try to follow that as a hint for
|
|
// any specifically customized behaviors for how this should be unmarshalled.
|
|
if tok.Tagged == true {
|
|
atlasEntry, exists := slab.atlas.GetEntryByTag(tok.Tag)
|
|
if !exists {
|
|
return true, fmt.Errorf("missing an unmarshaller for tag %v", tok.Tag)
|
|
}
|
|
value_rt := atlasEntry.Type
|
|
mach.holder_rv = reflect.New(value_rt).Elem()
|
|
mach.delegate = _yieldUnmarshalMachinePtr(slab.tip(), slab.atlas, value_rt)
|
|
if err := mach.delegate.Reset(slab, mach.holder_rv, value_rt); err != nil {
|
|
return true, err
|
|
}
|
|
return false, nil
|
|
}
|
|
|
|
// Switch on token type: we may be able to delegate to a primitive machine,
|
|
// but we may also need to initialize a container type and then hand off.
|
|
switch tok.Type {
|
|
case TMapOpen:
|
|
child := make(map[string]interface{})
|
|
child_rv := reflect.ValueOf(child)
|
|
mach.target_rv.Set(child_rv)
|
|
mach.delegate = &slab.tip().unmarshalMachineMapStringWildcard
|
|
if err := mach.delegate.Reset(slab, child_rv, child_rv.Type()); err != nil {
|
|
return true, err
|
|
}
|
|
return false, nil
|
|
|
|
case TArrOpen:
|
|
// Stdlib has very interesting branch here: 'case reflect.Interface: if v.NumMethod() == 0 {'
|
|
// If that matches, it goes on a *totally different* branch that leaves the reflective path entirely forever.
|
|
// (Which is kind of interesting, because it also means it will never reuse memory there. If you wanted that.)
|
|
|
|
// This definitely went through a few discovery steps...
|
|
// - https://play.golang.org/p/Qbtpxwh68e
|
|
// - https://play.golang.org/p/l5RQujLnDN
|
|
// - https://play.golang.org/p/Z2ilpPk0vk
|
|
// - https://play.golang.org/p/jV9VFDht6F -- finally getting somewhere good
|
|
|
|
holder := make([]interface{}, 0)
|
|
mach.holder_rv = reflect.ValueOf(&holder).Elem()
|
|
mach.delegate = &slab.tip().unmarshalMachineSliceWildcard
|
|
if err := mach.delegate.Reset(slab, mach.holder_rv, mach.holder_rv.Type()); err != nil {
|
|
return true, err
|
|
}
|
|
return false, nil
|
|
|
|
case TMapClose:
|
|
return true, ErrMalformedTokenStream{tok.Type, "start of value"}
|
|
|
|
case TArrClose:
|
|
return true, ErrMalformedTokenStream{tok.Type, "start of value"}
|
|
|
|
case TNull:
|
|
mach.target_rv.Set(reflect.Zero(mach.target_rt))
|
|
return true, nil
|
|
|
|
default:
|
|
// If it wasn't the start of composite, shell out to the machine for literals.
|
|
// Don't bother to replace our internal step func because literal machines are never multi-call,
|
|
// and this lets us avoid grabbing a pointer and it shuffling around.
|
|
delegateMach := slab.tip().unmarshalMachinePrimitive
|
|
delegateMach.kind = reflect.Interface
|
|
if err := delegateMach.Reset(slab, mach.target_rv, nil); err != nil {
|
|
return true, err
|
|
}
|
|
return delegateMach.Step(driver, slab, tok)
|
|
}
|
|
}
|