github.com/hashicorp/terraform-plugin-sdk@v1.17.2/internal/states/state_deepcopy.go (about) 1 package states 2 3 import ( 4 "github.com/hashicorp/terraform-plugin-sdk/internal/addrs" 5 "github.com/zclconf/go-cty/cty" 6 ) 7 8 // Taking deep copies of states is an important operation because state is 9 // otherwise a mutable data structure that is challenging to share across 10 // many separate callers. It is important that the DeepCopy implementations 11 // in this file comprehensively copy all parts of the state data structure 12 // that could be mutated via pointers. 13 14 // DeepCopy returns a new state that contains equivalent data to the reciever 15 // but shares no backing memory in common. 16 // 17 // As with all methods on State, this method is not safe to use concurrently 18 // with writing to any portion of the recieving data structure. It is the 19 // caller's responsibility to ensure mutual exclusion for the duration of the 20 // operation, but may then freely modify the receiver and the returned copy 21 // independently once this method returns. 22 func (s *State) DeepCopy() *State { 23 if s == nil { 24 return nil 25 } 26 27 modules := make(map[string]*Module, len(s.Modules)) 28 for k, m := range s.Modules { 29 modules[k] = m.DeepCopy() 30 } 31 return &State{ 32 Modules: modules, 33 } 34 } 35 36 // DeepCopy returns a new module state that contains equivalent data to the 37 // receiver but shares no backing memory in common. 38 // 39 // As with all methods on Module, this method is not safe to use concurrently 40 // with writing to any portion of the recieving data structure. It is the 41 // caller's responsibility to ensure mutual exclusion for the duration of the 42 // operation, but may then freely modify the receiver and the returned copy 43 // independently once this method returns. 44 func (ms *Module) DeepCopy() *Module { 45 if ms == nil { 46 return nil 47 } 48 49 resources := make(map[string]*Resource, len(ms.Resources)) 50 for k, r := range ms.Resources { 51 resources[k] = r.DeepCopy() 52 } 53 outputValues := make(map[string]*OutputValue, len(ms.OutputValues)) 54 for k, v := range ms.OutputValues { 55 outputValues[k] = v.DeepCopy() 56 } 57 localValues := make(map[string]cty.Value, len(ms.LocalValues)) 58 for k, v := range ms.LocalValues { 59 // cty.Value is immutable, so we don't need to copy these. 60 localValues[k] = v 61 } 62 63 return &Module{ 64 Addr: ms.Addr, // technically mutable, but immutable by convention 65 Resources: resources, 66 OutputValues: outputValues, 67 LocalValues: localValues, 68 } 69 } 70 71 // DeepCopy returns a new resource state that contains equivalent data to the 72 // receiver but shares no backing memory in common. 73 // 74 // As with all methods on Resource, this method is not safe to use concurrently 75 // with writing to any portion of the recieving data structure. It is the 76 // caller's responsibility to ensure mutual exclusion for the duration of the 77 // operation, but may then freely modify the receiver and the returned copy 78 // independently once this method returns. 79 func (rs *Resource) DeepCopy() *Resource { 80 if rs == nil { 81 return nil 82 } 83 84 instances := make(map[addrs.InstanceKey]*ResourceInstance, len(rs.Instances)) 85 for k, i := range rs.Instances { 86 instances[k] = i.DeepCopy() 87 } 88 89 return &Resource{ 90 Addr: rs.Addr, 91 EachMode: rs.EachMode, 92 Instances: instances, 93 ProviderConfig: rs.ProviderConfig, // technically mutable, but immutable by convention 94 } 95 } 96 97 // DeepCopy returns a new resource instance state that contains equivalent data 98 // to the receiver but shares no backing memory in common. 99 // 100 // As with all methods on ResourceInstance, this method is not safe to use 101 // concurrently with writing to any portion of the recieving data structure. It 102 // is the caller's responsibility to ensure mutual exclusion for the duration 103 // of the operation, but may then freely modify the receiver and the returned 104 // copy independently once this method returns. 105 func (is *ResourceInstance) DeepCopy() *ResourceInstance { 106 if is == nil { 107 return nil 108 } 109 110 deposed := make(map[DeposedKey]*ResourceInstanceObjectSrc, len(is.Deposed)) 111 for k, obj := range is.Deposed { 112 deposed[k] = obj.DeepCopy() 113 } 114 115 return &ResourceInstance{ 116 Current: is.Current.DeepCopy(), 117 Deposed: deposed, 118 } 119 } 120 121 // DeepCopy returns a new resource instance object that contains equivalent data 122 // to the receiver but shares no backing memory in common. 123 // 124 // As with all methods on ResourceInstanceObjectSrc, this method is not safe to 125 // use concurrently with writing to any portion of the recieving data structure. 126 // It is the caller's responsibility to ensure mutual exclusion for the duration 127 // of the operation, but may then freely modify the receiver and the returned 128 // copy independently once this method returns. 129 func (obj *ResourceInstanceObjectSrc) DeepCopy() *ResourceInstanceObjectSrc { 130 if obj == nil { 131 return nil 132 } 133 134 var attrsFlat map[string]string 135 if obj.AttrsFlat != nil { 136 attrsFlat = make(map[string]string, len(obj.AttrsFlat)) 137 for k, v := range obj.AttrsFlat { 138 attrsFlat[k] = v 139 } 140 } 141 142 var attrsJSON []byte 143 if obj.AttrsJSON != nil { 144 attrsJSON = make([]byte, len(obj.AttrsJSON)) 145 copy(attrsJSON, obj.AttrsJSON) 146 } 147 148 var private []byte 149 if obj.Private != nil { 150 private = make([]byte, len(obj.Private)) 151 copy(private, obj.Private) 152 } 153 154 // Some addrs.Referencable implementations are technically mutable, but 155 // we treat them as immutable by convention and so we don't deep-copy here. 156 dependencies := make([]addrs.Referenceable, len(obj.Dependencies)) 157 copy(dependencies, obj.Dependencies) 158 159 return &ResourceInstanceObjectSrc{ 160 Status: obj.Status, 161 SchemaVersion: obj.SchemaVersion, 162 Private: private, 163 AttrsFlat: attrsFlat, 164 AttrsJSON: attrsJSON, 165 Dependencies: dependencies, 166 } 167 } 168 169 // DeepCopy returns a new resource instance object that contains equivalent data 170 // to the receiver but shares no backing memory in common. 171 // 172 // As with all methods on ResourceInstanceObject, this method is not safe to use 173 // concurrently with writing to any portion of the recieving data structure. It 174 // is the caller's responsibility to ensure mutual exclusion for the duration 175 // of the operation, but may then freely modify the receiver and the returned 176 // copy independently once this method returns. 177 func (obj *ResourceInstanceObject) DeepCopy() *ResourceInstanceObject { 178 if obj == nil { 179 return nil 180 } 181 182 var private []byte 183 if obj.Private != nil { 184 private = make([]byte, len(obj.Private)) 185 copy(private, obj.Private) 186 } 187 188 // Some addrs.Referenceable implementations are technically mutable, but 189 // we treat them as immutable by convention and so we don't deep-copy here. 190 var dependencies []addrs.Referenceable 191 if obj.Dependencies != nil { 192 dependencies = make([]addrs.Referenceable, len(obj.Dependencies)) 193 copy(dependencies, obj.Dependencies) 194 } 195 196 return &ResourceInstanceObject{ 197 Value: obj.Value, 198 Status: obj.Status, 199 Private: private, 200 Dependencies: dependencies, 201 } 202 } 203 204 // DeepCopy returns a new output value state that contains equivalent data 205 // to the receiver but shares no backing memory in common. 206 // 207 // As with all methods on OutputValue, this method is not safe to use 208 // concurrently with writing to any portion of the recieving data structure. It 209 // is the caller's responsibility to ensure mutual exclusion for the duration 210 // of the operation, but may then freely modify the receiver and the returned 211 // copy independently once this method returns. 212 func (os *OutputValue) DeepCopy() *OutputValue { 213 if os == nil { 214 return nil 215 } 216 217 return &OutputValue{ 218 Value: os.Value, 219 Sensitive: os.Sensitive, 220 } 221 }