github.com/opentofu/opentofu@v1.7.1/internal/instances/expansion_mode.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 instances
     7  
     8  import (
     9  	"fmt"
    10  	"sort"
    11  
    12  	"github.com/zclconf/go-cty/cty"
    13  
    14  	"github.com/opentofu/opentofu/internal/addrs"
    15  )
    16  
    17  // expansion is an internal interface used to represent the different
    18  // ways expansion can operate depending on how repetition is configured for
    19  // an object.
    20  type expansion interface {
    21  	instanceKeys() []addrs.InstanceKey
    22  	repetitionData(addrs.InstanceKey) RepetitionData
    23  }
    24  
    25  // expansionSingle is the expansion corresponding to no repetition arguments
    26  // at all, producing a single object with no key.
    27  //
    28  // expansionSingleVal is the only valid value of this type.
    29  type expansionSingle uintptr
    30  
    31  var singleKeys = []addrs.InstanceKey{addrs.NoKey}
    32  var expansionSingleVal expansionSingle
    33  
    34  func (e expansionSingle) instanceKeys() []addrs.InstanceKey {
    35  	return singleKeys
    36  }
    37  
    38  func (e expansionSingle) repetitionData(key addrs.InstanceKey) RepetitionData {
    39  	if key != addrs.NoKey {
    40  		panic("cannot use instance key with non-repeating object")
    41  	}
    42  	return RepetitionData{}
    43  }
    44  
    45  // expansionCount is the expansion corresponding to the "count" argument.
    46  type expansionCount int
    47  
    48  func (e expansionCount) instanceKeys() []addrs.InstanceKey {
    49  	ret := make([]addrs.InstanceKey, int(e))
    50  	for i := range ret {
    51  		ret[i] = addrs.IntKey(i)
    52  	}
    53  	return ret
    54  }
    55  
    56  func (e expansionCount) repetitionData(key addrs.InstanceKey) RepetitionData {
    57  	i := int(key.(addrs.IntKey))
    58  	if i < 0 || i >= int(e) {
    59  		panic(fmt.Sprintf("instance key %d out of range for count %d", i, e))
    60  	}
    61  	return RepetitionData{
    62  		CountIndex: cty.NumberIntVal(int64(i)),
    63  	}
    64  }
    65  
    66  // expansionForEach is the expansion corresponding to the "for_each" argument.
    67  type expansionForEach map[string]cty.Value
    68  
    69  func (e expansionForEach) instanceKeys() []addrs.InstanceKey {
    70  	ret := make([]addrs.InstanceKey, 0, len(e))
    71  	for k := range e {
    72  		ret = append(ret, addrs.StringKey(k))
    73  	}
    74  	sort.Slice(ret, func(i, j int) bool {
    75  		return ret[i].(addrs.StringKey) < ret[j].(addrs.StringKey)
    76  	})
    77  	return ret
    78  }
    79  
    80  func (e expansionForEach) repetitionData(key addrs.InstanceKey) RepetitionData {
    81  	k := string(key.(addrs.StringKey))
    82  	v, ok := e[k]
    83  	if !ok {
    84  		panic(fmt.Sprintf("instance key %q does not match any instance", k))
    85  	}
    86  	return RepetitionData{
    87  		EachKey:   cty.StringVal(k),
    88  		EachValue: v,
    89  	}
    90  }