Add stack of previous values to converter

This commit is contained in:
Daniel Smith 2014-11-24 20:06:43 -08:00
parent 7f2d0c0f71
commit 77521a33d3

View File

@ -100,32 +100,34 @@ type Meta struct {
// scope contains information about an ongoing conversion. // scope contains information about an ongoing conversion.
type scope struct { type scope struct {
converter *Converter converter *Converter
meta *Meta meta *Meta
flags FieldMatchingFlags flags FieldMatchingFlags
srcTagStack []reflect.StructTag
destTagStack []reflect.StructTag // srcStack & destStack are separate because they may not have a 1:1
// relationship.
srcStack scopeStack
destStack scopeStack
} }
// push adds a level to the src/dest tag stacks. type scopeStackElem struct {
func (s *scope) push() { tag reflect.StructTag
s.srcTagStack = append(s.srcTagStack, "") value reflect.Value
s.destTagStack = append(s.destTagStack, "")
} }
// pop removes a level to the src/dest tag stacks. type scopeStack []scopeStackElem
func (s *scope) pop() {
n := len(s.srcTagStack) func (s *scopeStack) pop() {
s.srcTagStack = s.srcTagStack[:n-1] n := len(*s)
s.destTagStack = s.destTagStack[:n-1] *s = (*s)[:n-1]
} }
func (s *scope) setSrcTag(tag reflect.StructTag) { func (s *scopeStack) push(e scopeStackElem) {
s.srcTagStack[len(s.srcTagStack)-1] = tag *s = append(*s, e)
} }
func (s *scope) setDestTag(tag reflect.StructTag) { func (s *scopeStack) top() *scopeStackElem {
s.destTagStack[len(s.destTagStack)-1] = tag return &(*s)[len(*s)-1]
} }
// Convert continues a conversion. // Convert continues a conversion.
@ -135,12 +137,12 @@ func (s *scope) Convert(src, dest interface{}, flags FieldMatchingFlags) error {
// SrcTag returns the tag of the struct containing the current source item, if any. // SrcTag returns the tag of the struct containing the current source item, if any.
func (s *scope) SrcTag() reflect.StructTag { func (s *scope) SrcTag() reflect.StructTag {
return s.srcTagStack[len(s.srcTagStack)-1] return s.srcStack.top().tag
} }
// DestTag returns the tag of the struct containing the current dest item, if any. // DestTag returns the tag of the struct containing the current dest item, if any.
func (s *scope) DestTag() reflect.StructTag { func (s *scope) DestTag() reflect.StructTag {
return s.destTagStack[len(s.destTagStack)-1] return s.destStack.top().tag
} }
// Flags returns the flags with which the current conversion was started. // Flags returns the flags with which the current conversion was started.
@ -265,7 +267,9 @@ func (c *Converter) Convert(src, dest interface{}, flags FieldMatchingFlags, met
flags: flags, flags: flags,
meta: meta, meta: meta,
} }
s.push() // Easy way to make SrcTag and DestTag never fail // Leave something on the stack, so that calls to struct tag getters never fail.
s.srcStack.push(scopeStackElem{})
s.destStack.push(scopeStackElem{})
return c.convert(sv, dv, s) return c.convert(sv, dv, s)
} }
@ -305,8 +309,10 @@ func (c *Converter) convert(sv, dv reflect.Value, scope *scope) error {
c.Debug.Logf("Trying to convert '%v' to '%v'", st, dt) c.Debug.Logf("Trying to convert '%v' to '%v'", st, dt)
} }
scope.push() scope.srcStack.push(scopeStackElem{value: sv})
defer scope.pop() scope.destStack.push(scopeStackElem{value: dv})
defer scope.srcStack.pop()
defer scope.destStack.pop()
switch dv.Kind() { switch dv.Kind() {
case reflect.Struct: case reflect.Struct:
@ -375,11 +381,11 @@ func (c *Converter) convertStruct(sv, dv reflect.Value, scope *scope) error {
if sf.IsValid() { if sf.IsValid() {
// No need to check error, since we know it's valid. // No need to check error, since we know it's valid.
field, _ := st.FieldByName(f.Name) field, _ := st.FieldByName(f.Name)
scope.setSrcTag(field.Tag) scope.srcStack.top().tag = field.Tag
} }
if df.IsValid() { if df.IsValid() {
field, _ := dt.FieldByName(f.Name) field, _ := dt.FieldByName(f.Name)
scope.setDestTag(field.Tag) scope.destStack.top().tag = field.Tag
} }
// TODO: set top level of scope.src/destTagStack with these field tags here. // TODO: set top level of scope.src/destTagStack with these field tags here.
if !df.IsValid() || !sf.IsValid() { if !df.IsValid() || !sf.IsValid() {