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  }