ipld-eth-server/vendor/github.com/polydawn/refmt/obj/marshalStruct.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

109 lines
3.1 KiB
Go

package obj
import (
"fmt"
"reflect"
"github.com/polydawn/refmt/obj/atlas"
. "github.com/polydawn/refmt/tok"
)
type marshalMachineStructAtlas struct {
cfg *atlas.AtlasEntry // set on initialization
target_rv reflect.Value
index int // Progress marker
value_rv reflect.Value // Next value (or nil if next step is key).
}
func (mach *marshalMachineStructAtlas) Reset(slab *marshalSlab, rv reflect.Value, _ reflect.Type) error {
mach.target_rv = rv
mach.index = -1
mach.value_rv = reflect.Value{}
slab.grow() // we'll reuse the same row for all fields
return nil
}
func (mach *marshalMachineStructAtlas) Step(driver *Marshaller, slab *marshalSlab, tok *Token) (done bool, err error) {
//fmt.Printf("--step on %#v: i=%d/%d v=%v\n", mach.target_rv, mach.index, len(mach.cfg.Fields), mach.value)
// Check boundaries and do the special steps or either start or end.
nEntries := len(mach.cfg.StructMap.Fields)
if mach.index < 0 {
tok.Type = TMapOpen
tok.Length = countEmittableStructFields(mach.cfg, mach.target_rv)
tok.Tagged = mach.cfg.Tagged
tok.Tag = mach.cfg.Tag
mach.index++
return false, nil
}
if mach.index == nEntries {
tok.Type = TMapClose
mach.index++
slab.release()
return true, nil
}
if mach.index > nEntries {
return true, fmt.Errorf("invalid state: entire struct (%d fields) already consumed", nEntries)
}
// If value loaded from last step, recurse into handling that.
fieldEntry := mach.cfg.StructMap.Fields[mach.index]
if mach.value_rv != (reflect.Value{}) {
child_rv := mach.value_rv
mach.index++
mach.value_rv = reflect.Value{}
return false, driver.Recurse(
tok,
child_rv,
fieldEntry.Type,
slab.yieldMachine(fieldEntry.Type),
)
}
// If value was nil, that indicates we're supposed to pick the value and yield a key.
// We have to look ahead to the value because if it's zero and tagged as
// omitEmpty, then we have to skip emitting the key as well.
for fieldEntry.Ignore {
mach.index++
if mach.index == nEntries {
tok.Type = TMapClose
mach.index++
slab.release()
return true, nil
}
fieldEntry = mach.cfg.StructMap.Fields[mach.index]
}
mach.value_rv = fieldEntry.ReflectRoute.TraverseToValue(mach.target_rv)
if fieldEntry.OmitEmpty && isEmptyValue(mach.value_rv) {
mach.value_rv = reflect.Value{}
mach.index++
return mach.Step(driver, slab, tok)
}
tok.Type = TString
tok.Str = fieldEntry.SerialName
return false, nil
}
// Count how many fields in a struct should actually be marshalled.
// Fields that are tagged omitEmpty and are isEmptyValue are not counted, and
// StructMapEntry used to flag ignored fields unmarshalling never count, so
// this number may be less than the number of fields in the AtlasEntry.StructMap.
func countEmittableStructFields(cfg *atlas.AtlasEntry, target_rv reflect.Value) int {
total := 0
for _, fieldEntry := range cfg.StructMap.Fields {
if fieldEntry.Ignore {
continue
}
if !fieldEntry.OmitEmpty {
total++
continue
}
if !isEmptyValue(fieldEntry.ReflectRoute.TraverseToValue(target_rv)) {
total++
continue
}
}
return total
}