1package copystructure 2 3import ( 4 "reflect" 5 6 "github.com/mitchellh/reflectwalk" 7) 8 9// Copy returns a deep copy of v. 10func Copy(v interface{}) (interface{}, error) { 11 w := new(walker) 12 err := reflectwalk.Walk(v, w) 13 if err != nil { 14 return nil, err 15 } 16 17 // Get the result. If the result is nil, then we want to turn it 18 // into a typed nil if we can. 19 result := w.Result 20 if result == nil { 21 val := reflect.ValueOf(v) 22 result = reflect.Indirect(reflect.New(val.Type())).Interface() 23 } 24 25 return result, nil 26} 27 28// CopierFunc is a function that knows how to deep copy a specific type. 29// Register these globally with the Copiers variable. 30type CopierFunc func(interface{}) (interface{}, error) 31 32// Copiers is a map of types that behave specially when they are copied. 33// If a type is found in this map while deep copying, this function 34// will be called to copy it instead of attempting to copy all fields. 35// 36// The key should be the type, obtained using: reflect.TypeOf(value with type). 37// 38// It is unsafe to write to this map after Copies have started. If you 39// are writing to this map while also copying, wrap all modifications to 40// this map as well as to Copy in a mutex. 41var Copiers map[reflect.Type]CopierFunc = make(map[reflect.Type]CopierFunc) 42 43type walker struct { 44 Result interface{} 45 46 depth int 47 ignoreDepth int 48 vals []reflect.Value 49 cs []reflect.Value 50 ps []bool 51} 52 53func (w *walker) Enter(l reflectwalk.Location) error { 54 w.depth++ 55 return nil 56} 57 58func (w *walker) Exit(l reflectwalk.Location) error { 59 w.depth-- 60 if w.ignoreDepth > w.depth { 61 w.ignoreDepth = 0 62 } 63 64 if w.ignoring() { 65 return nil 66 } 67 68 switch l { 69 case reflectwalk.Map: 70 fallthrough 71 case reflectwalk.Slice: 72 // Pop map off our container 73 w.cs = w.cs[:len(w.cs)-1] 74 case reflectwalk.MapValue: 75 // Pop off the key and value 76 mv := w.valPop() 77 mk := w.valPop() 78 m := w.cs[len(w.cs)-1] 79 m.SetMapIndex(mk, mv) 80 case reflectwalk.SliceElem: 81 // Pop off the value and the index and set it on the slice 82 v := w.valPop() 83 i := w.valPop().Interface().(int) 84 s := w.cs[len(w.cs)-1] 85 s.Index(i).Set(v) 86 case reflectwalk.Struct: 87 w.replacePointerMaybe() 88 89 // Remove the struct from the container stack 90 w.cs = w.cs[:len(w.cs)-1] 91 case reflectwalk.StructField: 92 // Pop off the value and the field 93 v := w.valPop() 94 f := w.valPop().Interface().(reflect.StructField) 95 if v.IsValid() { 96 s := w.cs[len(w.cs)-1] 97 sf := reflect.Indirect(s).FieldByName(f.Name) 98 if sf.CanSet() { 99 sf.Set(v) 100 } 101 } 102 case reflectwalk.WalkLoc: 103 // Clear out the slices for GC 104 w.cs = nil 105 w.vals = nil 106 } 107 108 return nil 109} 110 111func (w *walker) Map(m reflect.Value) error { 112 if w.ignoring() { 113 return nil 114 } 115 116 // Create the map. If the map itself is nil, then just make a nil map 117 var newMap reflect.Value 118 if m.IsNil() { 119 newMap = reflect.Indirect(reflect.New(m.Type())) 120 } else { 121 newMap = reflect.MakeMap(m.Type()) 122 } 123 124 w.cs = append(w.cs, newMap) 125 w.valPush(newMap) 126 return nil 127} 128 129func (w *walker) MapElem(m, k, v reflect.Value) error { 130 return nil 131} 132 133func (w *walker) PointerEnter(v bool) error { 134 if w.ignoring() { 135 return nil 136 } 137 138 w.ps = append(w.ps, v) 139 return nil 140} 141 142func (w *walker) PointerExit(bool) error { 143 if w.ignoring() { 144 return nil 145 } 146 147 w.ps = w.ps[:len(w.ps)-1] 148 return nil 149} 150 151func (w *walker) Primitive(v reflect.Value) error { 152 if w.ignoring() { 153 return nil 154 } 155 156 // IsValid verifies the v is non-zero and CanInterface verifies 157 // that we're allowed to read this value (unexported fields). 158 var newV reflect.Value 159 if v.IsValid() && v.CanInterface() { 160 newV = reflect.New(v.Type()) 161 reflect.Indirect(newV).Set(v) 162 } 163 164 w.valPush(newV) 165 w.replacePointerMaybe() 166 return nil 167} 168 169func (w *walker) Slice(s reflect.Value) error { 170 if w.ignoring() { 171 return nil 172 } 173 174 var newS reflect.Value 175 if s.IsNil() { 176 newS = reflect.Indirect(reflect.New(s.Type())) 177 } else { 178 newS = reflect.MakeSlice(s.Type(), s.Len(), s.Cap()) 179 } 180 181 w.cs = append(w.cs, newS) 182 w.valPush(newS) 183 return nil 184} 185 186func (w *walker) SliceElem(i int, elem reflect.Value) error { 187 if w.ignoring() { 188 return nil 189 } 190 191 // We don't write the slice here because elem might still be 192 // arbitrarily complex. Just record the index and continue on. 193 w.valPush(reflect.ValueOf(i)) 194 195 return nil 196} 197 198func (w *walker) Struct(s reflect.Value) error { 199 if w.ignoring() { 200 return nil 201 } 202 203 var v reflect.Value 204 if c, ok := Copiers[s.Type()]; ok { 205 // We have a Copier for this struct, so we use that copier to 206 // get the copy, and we ignore anything deeper than this. 207 w.ignoreDepth = w.depth 208 209 dup, err := c(s.Interface()) 210 if err != nil { 211 return err 212 } 213 214 v = reflect.ValueOf(dup) 215 } else { 216 // No copier, we copy ourselves and allow reflectwalk to guide 217 // us deeper into the structure for copying. 218 v = reflect.New(s.Type()) 219 } 220 221 // Push the value onto the value stack for setting the struct field, 222 // and add the struct itself to the containers stack in case we walk 223 // deeper so that its own fields can be modified. 224 w.valPush(v) 225 w.cs = append(w.cs, v) 226 227 return nil 228} 229 230func (w *walker) StructField(f reflect.StructField, v reflect.Value) error { 231 if w.ignoring() { 232 return nil 233 } 234 235 // Push the field onto the stack, we'll handle it when we exit 236 // the struct field in Exit... 237 w.valPush(reflect.ValueOf(f)) 238 return nil 239} 240 241func (w *walker) ignoring() bool { 242 return w.ignoreDepth > 0 && w.depth >= w.ignoreDepth 243} 244 245func (w *walker) pointerPeek() bool { 246 return w.ps[len(w.ps)-1] 247} 248 249func (w *walker) valPop() reflect.Value { 250 result := w.vals[len(w.vals)-1] 251 w.vals = w.vals[:len(w.vals)-1] 252 253 // If we're out of values, that means we popped everything off. In 254 // this case, we reset the result so the next pushed value becomes 255 // the result. 256 if len(w.vals) == 0 { 257 w.Result = nil 258 } 259 260 return result 261} 262 263func (w *walker) valPush(v reflect.Value) { 264 w.vals = append(w.vals, v) 265 266 // If we haven't set the result yet, then this is the result since 267 // it is the first (outermost) value we're seeing. 268 if w.Result == nil && v.IsValid() { 269 w.Result = v.Interface() 270 } 271} 272 273func (w *walker) replacePointerMaybe() { 274 // Determine the last pointer value. If it is NOT a pointer, then 275 // we need to push that onto the stack. 276 if !w.pointerPeek() { 277 w.valPush(reflect.Indirect(w.valPop())) 278 } 279} 280