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  }