diff --git a/vendor/github.com/mitchellh/copystructure/copystructure.go b/vendor/github.com/mitchellh/copystructure/copystructure.go index 8122bfb77..3f390764e 100644 --- a/vendor/github.com/mitchellh/copystructure/copystructure.go +++ b/vendor/github.com/mitchellh/copystructure/copystructure.go @@ -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 diff --git a/vendor/github.com/mitchellh/reflectwalk/reflectwalk.go b/vendor/github.com/mitchellh/reflectwalk/reflectwalk.go index 3a6da9737..ec0a62337 100644 --- a/vendor/github.com/mitchellh/reflectwalk/reflectwalk.go +++ b/vendor/github.com/mitchellh/reflectwalk/reflectwalk.go @@ -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 } diff --git a/vendor/vendor.json b/vendor/vendor.json index c5871e5c7..c54d87159 100644 --- a/vendor/vendor.json +++ b/vendor/vendor.json @@ -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=",