forked from cerc-io/ipld-eth-server
36533f7c3f
Fixes for new geth version
188 lines
6.3 KiB
Go
188 lines
6.3 KiB
Go
package obj
|
|
|
|
import (
|
|
"fmt"
|
|
"reflect"
|
|
|
|
"github.com/polydawn/refmt/obj/atlas"
|
|
. "github.com/polydawn/refmt/tok"
|
|
)
|
|
|
|
/*
|
|
A lovely mechanism to stash unmarshalMachine objects pre-allocated and avoid mallocs.
|
|
Works together with the Atlas: the Atlas says what kind of machinery is needed;
|
|
the unmarshalSlab "allocates" it and returns it upon your request.
|
|
*/
|
|
type unmarshalSlab struct {
|
|
atlas atlas.Atlas
|
|
rows []unmarshalSlabRow
|
|
}
|
|
|
|
type unmarshalSlabRow struct {
|
|
ptrDerefDelegateUnmarshalMachine
|
|
unmarshalMachinePrimitive
|
|
unmarshalMachineWildcard
|
|
unmarshalMachineMapStringWildcard
|
|
unmarshalMachineSliceWildcard
|
|
unmarshalMachineArrayWildcard
|
|
unmarshalMachineStructAtlas
|
|
unmarshalMachineTransform
|
|
unmarshalMachineUnionKeyed
|
|
|
|
errThunkUnmarshalMachine
|
|
}
|
|
|
|
/*
|
|
Return a reference to a machine from the slab.
|
|
*You must release() when done.*
|
|
|
|
Errors -- including "no info in Atlas for this type" -- are expressed by
|
|
returning a machine that is a constantly-erroring thunk.
|
|
*/
|
|
func (slab *unmarshalSlab) requisitionMachine(rt reflect.Type) UnmarshalMachine {
|
|
// Acquire a row.
|
|
off := len(slab.rows)
|
|
slab.grow()
|
|
row := &slab.rows[off]
|
|
|
|
// Indirect pointers as necessary.
|
|
// Keep count of how many times we do this; we'll use this again at the end.
|
|
peelCount := 0
|
|
for rt.Kind() == reflect.Ptr {
|
|
rt = rt.Elem()
|
|
peelCount++
|
|
}
|
|
|
|
// Figure out what machinery to use at heart.
|
|
mach := _yieldUnmarshalMachinePtr(row, slab.atlas, rt)
|
|
// If nil answer, we had no match: yield an error thunk.
|
|
if mach == nil {
|
|
mach := &row.errThunkUnmarshalMachine
|
|
mach.err = fmt.Errorf("no machine found")
|
|
return mach
|
|
}
|
|
|
|
// If no indirection steps, return;
|
|
// otherwise wrap it in the ptrDeref machine and return that.
|
|
if peelCount == 0 {
|
|
return mach
|
|
}
|
|
row.ptrDerefDelegateUnmarshalMachine.UnmarshalMachine = mach
|
|
row.ptrDerefDelegateUnmarshalMachine.peelCount = peelCount
|
|
return &row.ptrDerefDelegateUnmarshalMachine
|
|
}
|
|
|
|
func _yieldUnmarshalMachinePtr(row *unmarshalSlabRow, atl atlas.Atlas, rt reflect.Type) UnmarshalMachine {
|
|
rtid := reflect.ValueOf(rt).Pointer()
|
|
|
|
// Check primitives first; cheapest (and unoverridable).
|
|
switch rtid {
|
|
case rtid_bool,
|
|
rtid_string,
|
|
rtid_int, rtid_int8, rtid_int16, rtid_int32, rtid_int64,
|
|
rtid_uint, rtid_uint8, rtid_uint16, rtid_uint32, rtid_uint64, rtid_uintptr,
|
|
rtid_float32, rtid_float64,
|
|
rtid_bytes:
|
|
row.unmarshalMachinePrimitive.kind = rt.Kind()
|
|
return &row.unmarshalMachinePrimitive
|
|
}
|
|
|
|
// Consult atlas second.
|
|
if entry, ok := atl.Get(rtid); ok {
|
|
return _yieldUnmarshalMachinePtrForAtlasEntry(row, entry, atl)
|
|
}
|
|
|
|
// If no specific behavior found, use default behavior based on kind.
|
|
switch rt.Kind() {
|
|
|
|
case reflect.Bool,
|
|
reflect.String,
|
|
reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64,
|
|
reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr,
|
|
reflect.Float32, reflect.Float64:
|
|
row.unmarshalMachinePrimitive.kind = rt.Kind()
|
|
return &row.unmarshalMachinePrimitive
|
|
case reflect.Slice:
|
|
// un-typedef'd byte slices were handled already, but a typedef'd one still gets gets treated like a special kind:
|
|
if rt.Elem().Kind() == reflect.Uint8 {
|
|
row.unmarshalMachinePrimitive.kind = rt.Kind()
|
|
return &row.unmarshalMachinePrimitive
|
|
}
|
|
return &row.unmarshalMachineSliceWildcard
|
|
case reflect.Array:
|
|
// arrays of bytes have a similar special case to slices for when they're typedefed.
|
|
if rt.Elem().Kind() == reflect.Uint8 {
|
|
row.unmarshalMachinePrimitive.kind = rt.Kind()
|
|
return &row.unmarshalMachinePrimitive
|
|
}
|
|
return &row.unmarshalMachineArrayWildcard
|
|
case reflect.Map:
|
|
return &row.unmarshalMachineMapStringWildcard
|
|
case reflect.Struct:
|
|
// TODO here we could also invoke automatic atlas autogen, if configured to be permitted
|
|
mach := &row.errThunkUnmarshalMachine
|
|
mach.err = fmt.Errorf("missing an atlas entry describing how to unmarshal type %v (and auto-atlasing for structs is not enabled)", rt)
|
|
return mach
|
|
case reflect.Interface:
|
|
return &row.unmarshalMachineWildcard
|
|
case reflect.Func:
|
|
panic(fmt.Errorf("functions cannot be unmarshalled!"))
|
|
case reflect.Ptr:
|
|
panic(fmt.Errorf("unreachable: ptrs must already be resolved"))
|
|
default:
|
|
panic(fmt.Errorf("excursion %s", rt.Kind()))
|
|
}
|
|
}
|
|
|
|
// given that we already have an atlasEntry in mind, yield a configured machine for it.
|
|
// it seems odd that this might still require a whole atlas, but tis so;
|
|
// some things (e.g. transform funcs) need to get additional machinery for delegation.
|
|
func _yieldUnmarshalMachinePtrForAtlasEntry(row *unmarshalSlabRow, entry *atlas.AtlasEntry, atl atlas.Atlas) UnmarshalMachine {
|
|
// Switch across which of the union of configurations is applicable.
|
|
switch {
|
|
case entry.UnmarshalTransformFunc != nil:
|
|
// Return a machine that calls the func(s), then later a real machine.
|
|
// The entry.UnmarshalTransformTargetType is used to do a recursive lookup.
|
|
// We can't just call the func here because we're still working off typeinfo
|
|
// and don't have a real value to transform until later.
|
|
row.unmarshalMachineTransform.trFunc = entry.UnmarshalTransformFunc
|
|
row.unmarshalMachineTransform.recv_rt = entry.UnmarshalTransformTargetType
|
|
// Pick delegate without growing stack. (This currently means recursive transform won't fly.)
|
|
row.unmarshalMachineTransform.delegate = _yieldUnmarshalMachinePtr(row, atl, entry.UnmarshalTransformTargetType)
|
|
return &row.unmarshalMachineTransform
|
|
case entry.StructMap != nil:
|
|
row.unmarshalMachineStructAtlas.cfg = entry
|
|
return &row.unmarshalMachineStructAtlas
|
|
case entry.UnionKeyedMorphism != nil:
|
|
row.unmarshalMachineUnionKeyed.cfg = entry.UnionKeyedMorphism
|
|
return &row.unmarshalMachineUnionKeyed
|
|
default:
|
|
panic("invalid atlas entry")
|
|
}
|
|
}
|
|
|
|
// Returns the top row of the slab. Useful for machines that need to delegate
|
|
// to another type that's definitely not their own (comes up for the wildcard delegators).
|
|
func (s *unmarshalSlab) tip() *unmarshalSlabRow {
|
|
return &s.rows[len(s.rows)-1]
|
|
}
|
|
|
|
func (s *unmarshalSlab) grow() {
|
|
s.rows = append(s.rows, unmarshalSlabRow{})
|
|
}
|
|
|
|
func (s *unmarshalSlab) release() {
|
|
s.rows = s.rows[0 : len(s.rows)-1]
|
|
}
|
|
|
|
type errThunkUnmarshalMachine struct {
|
|
err error
|
|
}
|
|
|
|
func (m *errThunkUnmarshalMachine) Reset(_ *unmarshalSlab, _ reflect.Value, _ reflect.Type) error {
|
|
return m.err
|
|
}
|
|
func (m *errThunkUnmarshalMachine) Step(d *Unmarshaller, s *unmarshalSlab, tok *Token) (done bool, err error) {
|
|
return true, m.err
|
|
}
|