|
|
|
|
@ -156,9 +156,13 @@ func (w *walker) Exit(l reflectwalk.Location) error {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
switch l {
|
|
|
|
|
case reflectwalk.Array:
|
|
|
|
|
fallthrough
|
|
|
|
|
case reflectwalk.Map:
|
|
|
|
|
fallthrough
|
|
|
|
|
case reflectwalk.Slice:
|
|
|
|
|
w.replacePointerMaybe()
|
|
|
|
|
|
|
|
|
|
// Pop map off our container
|
|
|
|
|
w.cs = w.cs[:len(w.cs)-1]
|
|
|
|
|
case reflectwalk.MapValue:
|
|
|
|
|
@ -171,16 +175,27 @@ func (w *walker) Exit(l reflectwalk.Location) error {
|
|
|
|
|
// or in this case never adds it. We need to create a properly typed
|
|
|
|
|
// zero value so that this key can be set.
|
|
|
|
|
if !mv.IsValid() {
|
|
|
|
|
mv = reflect.Zero(m.Type().Elem())
|
|
|
|
|
mv = reflect.Zero(m.Elem().Type().Elem())
|
|
|
|
|
}
|
|
|
|
|
m.Elem().SetMapIndex(mk, mv)
|
|
|
|
|
case reflectwalk.ArrayElem:
|
|
|
|
|
// Pop off the value and the index and set it on the array
|
|
|
|
|
v := w.valPop()
|
|
|
|
|
i := w.valPop().Interface().(int)
|
|
|
|
|
if v.IsValid() {
|
|
|
|
|
a := w.cs[len(w.cs)-1]
|
|
|
|
|
ae := a.Elem().Index(i) // storing array as pointer on stack - so need Elem() call
|
|
|
|
|
if ae.CanSet() {
|
|
|
|
|
ae.Set(v)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
m.SetMapIndex(mk, mv)
|
|
|
|
|
case reflectwalk.SliceElem:
|
|
|
|
|
// Pop off the value and the index and set it on the slice
|
|
|
|
|
v := w.valPop()
|
|
|
|
|
i := w.valPop().Interface().(int)
|
|
|
|
|
if v.IsValid() {
|
|
|
|
|
s := w.cs[len(w.cs)-1]
|
|
|
|
|
se := s.Index(i)
|
|
|
|
|
se := s.Elem().Index(i)
|
|
|
|
|
if se.CanSet() {
|
|
|
|
|
se.Set(v)
|
|
|
|
|
}
|
|
|
|
|
@ -220,9 +235,9 @@ func (w *walker) Map(m reflect.Value) error {
|
|
|
|
|
// Create the map. If the map itself is nil, then just make a nil map
|
|
|
|
|
var newMap reflect.Value
|
|
|
|
|
if m.IsNil() {
|
|
|
|
|
newMap = reflect.Indirect(reflect.New(m.Type()))
|
|
|
|
|
newMap = reflect.New(m.Type())
|
|
|
|
|
} else {
|
|
|
|
|
newMap = reflect.MakeMap(m.Type())
|
|
|
|
|
newMap = wrapPtr(reflect.MakeMap(m.Type()))
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
w.cs = append(w.cs, newMap)
|
|
|
|
|
@ -287,9 +302,9 @@ func (w *walker) Slice(s reflect.Value) error {
|
|
|
|
|
|
|
|
|
|
var newS reflect.Value
|
|
|
|
|
if s.IsNil() {
|
|
|
|
|
newS = reflect.Indirect(reflect.New(s.Type()))
|
|
|
|
|
newS = reflect.New(s.Type())
|
|
|
|
|
} else {
|
|
|
|
|
newS = reflect.MakeSlice(s.Type(), s.Len(), s.Cap())
|
|
|
|
|
newS = wrapPtr(reflect.MakeSlice(s.Type(), s.Len(), s.Cap()))
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
w.cs = append(w.cs, newS)
|
|
|
|
|
@ -309,6 +324,31 @@ func (w *walker) SliceElem(i int, elem reflect.Value) error {
|
|
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (w *walker) Array(a reflect.Value) error {
|
|
|
|
|
if w.ignoring() {
|
|
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
w.lock(a)
|
|
|
|
|
|
|
|
|
|
newA := reflect.New(a.Type())
|
|
|
|
|
|
|
|
|
|
w.cs = append(w.cs, newA)
|
|
|
|
|
w.valPush(newA)
|
|
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (w *walker) ArrayElem(i int, elem reflect.Value) error {
|
|
|
|
|
if w.ignoring() {
|
|
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// We don't write the array here because elem might still be
|
|
|
|
|
// arbitrarily complex. Just record the index and continue on.
|
|
|
|
|
w.valPush(reflect.ValueOf(i))
|
|
|
|
|
|
|
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (w *walker) Struct(s reflect.Value) error {
|
|
|
|
|
if w.ignoring() {
|
|
|
|
|
return nil
|
|
|
|
|
@ -326,7 +366,10 @@ func (w *walker) Struct(s reflect.Value) error {
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
v = reflect.ValueOf(dup)
|
|
|
|
|
// We need to put a pointer to the value on the value stack,
|
|
|
|
|
// so allocate a new pointer and set it.
|
|
|
|
|
v = reflect.New(s.Type())
|
|
|
|
|
reflect.Indirect(v).Set(reflect.ValueOf(dup))
|
|
|
|
|
} else {
|
|
|
|
|
// No copier, we copy ourselves and allow reflectwalk to guide
|
|
|
|
|
// us deeper into the structure for copying.
|
|
|
|
|
@ -405,6 +448,23 @@ func (w *walker) replacePointerMaybe() {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
v := w.valPop()
|
|
|
|
|
|
|
|
|
|
// If the expected type is a pointer to an interface of any depth,
|
|
|
|
|
// such as *interface{}, **interface{}, etc., then we need to convert
|
|
|
|
|
// the value "v" from *CONCRETE to *interface{} so types match for
|
|
|
|
|
// Set.
|
|
|
|
|
//
|
|
|
|
|
// Example if v is type *Foo where Foo is a struct, v would become
|
|
|
|
|
// *interface{} instead. This only happens if we have an interface expectation
|
|
|
|
|
// at this depth.
|
|
|
|
|
//
|
|
|
|
|
// For more info, see GH-16
|
|
|
|
|
if iType, ok := w.ifaceTypes[ifaceKey(w.ps[w.depth], w.depth)]; ok && iType.Kind() == reflect.Interface {
|
|
|
|
|
y := reflect.New(iType) // Create *interface{}
|
|
|
|
|
y.Elem().Set(reflect.Indirect(v)) // Assign "Foo" to interface{} (dereferenced)
|
|
|
|
|
v = y // v is now typed *interface{} (where *v = Foo)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for i := 1; i < w.ps[w.depth]; i++ {
|
|
|
|
|
if iType, ok := w.ifaceTypes[ifaceKey(w.ps[w.depth]-i, w.depth)]; ok {
|
|
|
|
|
iface := reflect.New(iType).Elem()
|
|
|
|
|
@ -475,3 +535,14 @@ func (w *walker) lock(v reflect.Value) {
|
|
|
|
|
locker.Lock()
|
|
|
|
|
w.locks[w.depth] = locker
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// wrapPtr is a helper that takes v and always make it *v. copystructure
|
|
|
|
|
// stores things internally as pointers until the last moment before unwrapping
|
|
|
|
|
func wrapPtr(v reflect.Value) reflect.Value {
|
|
|
|
|
if !v.IsValid() {
|
|
|
|
|
return v
|
|
|
|
|
}
|
|
|
|
|
vPtr := reflect.New(v.Type())
|
|
|
|
|
vPtr.Elem().Set(v)
|
|
|
|
|
return vPtr
|
|
|
|
|
}
|
|
|
|
|
|