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