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