Update reflectwalk and copystructure
Bug fix and improvements
This commit is contained in:
parent
36fd208fa9
commit
a86aa0f22d
|
@ -82,6 +82,14 @@ func (c Config) Copy(v interface{}) (interface{}, error) {
|
|||
return result, nil
|
||||
}
|
||||
|
||||
// Return the key used to index interfaces types we've seen. Store the number
|
||||
// of pointers in the upper 32bits, and the depth in the lower 32bits. This is
|
||||
// easy to calculate, easy to match a key with our current depth, and we don't
|
||||
// need to deal with initializing and cleaning up nested maps or slices.
|
||||
func ifaceKey(pointers, depth int) uint64 {
|
||||
return uint64(pointers)<<32 | uint64(depth)
|
||||
}
|
||||
|
||||
type walker struct {
|
||||
Result interface{}
|
||||
|
||||
|
@ -89,7 +97,16 @@ type walker struct {
|
|||
ignoreDepth int
|
||||
vals []reflect.Value
|
||||
cs []reflect.Value
|
||||
ps []int
|
||||
|
||||
// This stores the number of pointers we've walked over, indexed by depth.
|
||||
ps []int
|
||||
|
||||
// If an interface is indirected by a pointer, we need to know the type of
|
||||
// interface to create when creating the new value. Store the interface
|
||||
// types here, indexed by both the walk depth and the number of pointers
|
||||
// already seen at that depth. Use ifaceKey to calculate the proper uint64
|
||||
// value.
|
||||
ifaceTypes map[uint64]reflect.Type
|
||||
|
||||
// any locks we've taken, indexed by depth
|
||||
locks []sync.Locker
|
||||
|
@ -119,7 +136,16 @@ func (w *walker) Exit(l reflectwalk.Location) error {
|
|||
defer locker.Unlock()
|
||||
}
|
||||
|
||||
// clear out pointers and interfaces as we exit the stack
|
||||
w.ps[w.depth] = 0
|
||||
|
||||
for k := range w.ifaceTypes {
|
||||
mask := uint64(^uint32(0))
|
||||
if k&mask == uint64(w.depth) {
|
||||
delete(w.ifaceTypes, k)
|
||||
}
|
||||
}
|
||||
|
||||
w.depth--
|
||||
if w.ignoreDepth > w.depth {
|
||||
w.ignoreDepth = 0
|
||||
|
@ -222,6 +248,18 @@ func (w *walker) PointerExit(v bool) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func (w *walker) Interface(v reflect.Value) error {
|
||||
if !v.IsValid() {
|
||||
return nil
|
||||
}
|
||||
if w.ifaceTypes == nil {
|
||||
w.ifaceTypes = make(map[uint64]reflect.Type)
|
||||
}
|
||||
|
||||
w.ifaceTypes[ifaceKey(w.ps[w.depth], w.depth)] = v.Type()
|
||||
return nil
|
||||
}
|
||||
|
||||
func (w *walker) Primitive(v reflect.Value) error {
|
||||
if w.ignoring() {
|
||||
return nil
|
||||
|
@ -312,8 +350,7 @@ func (w *walker) StructField(f reflect.StructField, v reflect.Value) error {
|
|||
// If PkgPath is non-empty, this is a private (unexported) field.
|
||||
// We do not set this unexported since the Go runtime doesn't allow us.
|
||||
if f.PkgPath != "" {
|
||||
w.ignore()
|
||||
return nil
|
||||
return reflectwalk.SkipEntry
|
||||
}
|
||||
|
||||
// Push the field onto the stack, we'll handle it when we exit
|
||||
|
@ -369,6 +406,12 @@ func (w *walker) replacePointerMaybe() {
|
|||
|
||||
v := w.valPop()
|
||||
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()
|
||||
iface.Set(v)
|
||||
v = iface
|
||||
}
|
||||
|
||||
p := reflect.New(v.Type())
|
||||
p.Elem().Set(v)
|
||||
v = p
|
||||
|
|
|
@ -4,7 +4,10 @@
|
|||
// those elements.
|
||||
package reflectwalk
|
||||
|
||||
import "reflect"
|
||||
import (
|
||||
"errors"
|
||||
"reflect"
|
||||
)
|
||||
|
||||
// PrimitiveWalker implementations are able to handle primitive values
|
||||
// within complex structures. Primitive values are numbers, strings,
|
||||
|
@ -16,6 +19,12 @@ type PrimitiveWalker interface {
|
|||
Primitive(reflect.Value) error
|
||||
}
|
||||
|
||||
// InterfaceWalker implementations are able to handle interface values as they
|
||||
// are encountered during the walk.
|
||||
type InterfaceWalker interface {
|
||||
Interface(reflect.Value) error
|
||||
}
|
||||
|
||||
// MapWalker implementations are able to handle individual elements
|
||||
// found within a map structure.
|
||||
type MapWalker interface {
|
||||
|
@ -53,6 +62,13 @@ type PointerWalker interface {
|
|||
PointerExit(bool) error
|
||||
}
|
||||
|
||||
// SkipEntry can be returned from walk functions to skip walking
|
||||
// the value of this field. This is only valid in the following functions:
|
||||
//
|
||||
// - StructField: skips walking the struct value
|
||||
//
|
||||
var SkipEntry = errors.New("skip this entry")
|
||||
|
||||
// Walk takes an arbitrary value and an interface and traverses the
|
||||
// value, calling callbacks on the interface if they are supported.
|
||||
// The interface should implement one or more of the walker interfaces
|
||||
|
@ -96,8 +112,15 @@ func walk(v reflect.Value, w interface{}) (err error) {
|
|||
|
||||
for {
|
||||
if pointerV.Kind() == reflect.Interface {
|
||||
if iw, ok := w.(InterfaceWalker); ok {
|
||||
if err = iw.Interface(pointerV); err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
pointerV = pointerV.Elem()
|
||||
}
|
||||
|
||||
if pointerV.Kind() == reflect.Ptr {
|
||||
pointer = true
|
||||
v = reflect.Indirect(pointerV)
|
||||
|
@ -282,6 +305,12 @@ func walkStruct(v reflect.Value, w interface{}) (err error) {
|
|||
|
||||
if sw, ok := w.(StructWalker); ok {
|
||||
err = sw.StructField(sf, f)
|
||||
|
||||
// SkipEntry just pretends this field doesn't even exist
|
||||
if err == SkipEntry {
|
||||
continue
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
|
|
@ -1464,10 +1464,10 @@
|
|||
"revision": "8631ce90f28644f54aeedcb3e389a85174e067d1"
|
||||
},
|
||||
{
|
||||
"checksumSHA1": "gsIaLhXE/YZahSg33edGHvzVQ1o=",
|
||||
"checksumSHA1": "BsIMq23KDyxdhQC7g2dDz/9oHbA=",
|
||||
"path": "github.com/mitchellh/copystructure",
|
||||
"revision": "c740739b7b69de009385f52933769c1c037705df",
|
||||
"revisionTime": "2016-10-03T06:35:14Z"
|
||||
"revision": "c4815f984fb5c5486f6db1c9a5660e7605fd4c20",
|
||||
"revisionTime": "2016-10-03T18:23:19Z"
|
||||
},
|
||||
{
|
||||
"path": "github.com/mitchellh/go-homedir",
|
||||
|
@ -1499,10 +1499,10 @@
|
|||
"revision": "6e6954073784f7ee67b28f2d22749d6479151ed7"
|
||||
},
|
||||
{
|
||||
"checksumSHA1": "u+sHUhd/XXvjiVPAJ/h8yvLbSj4=",
|
||||
"checksumSHA1": "vBpuqNfSTZcAR/0tP8tNYacySGs=",
|
||||
"path": "github.com/mitchellh/reflectwalk",
|
||||
"revision": "4a18c295388e8482403483c88469392f9e6556d7",
|
||||
"revisionTime": "2016-10-02T04:32:56Z"
|
||||
"revision": "92573fe8d000a145bfebc03a16bc22b34945867f",
|
||||
"revisionTime": "2016-10-03T17:45:16Z"
|
||||
},
|
||||
{
|
||||
"checksumSHA1": "/iig5lYSPCL3C8J7e4nTAevYNDE=",
|
||||
|
|
Loading…
Reference in New Issue