github.com/hashicorp/terraform-plugin-sdk@v1.17.2/internal/addrs/instance_key.go (about) 1 package addrs 2 3 import ( 4 "fmt" 5 6 "github.com/zclconf/go-cty/cty" 7 "github.com/zclconf/go-cty/cty/gocty" 8 ) 9 10 // InstanceKey represents the key of an instance within an object that 11 // contains multiple instances due to using "count" or "for_each" arguments 12 // in configuration. 13 // 14 // IntKey and StringKey are the two implementations of this type. No other 15 // implementations are allowed. The single instance of an object that _isn't_ 16 // using "count" or "for_each" is represented by NoKey, which is a nil 17 // InstanceKey. 18 type InstanceKey interface { 19 instanceKeySigil() 20 String() string 21 } 22 23 // ParseInstanceKey returns the instance key corresponding to the given value, 24 // which must be known and non-null. 25 // 26 // If an unknown or null value is provided then this function will panic. This 27 // function is intended to deal with the values that would naturally be found 28 // in a hcl.TraverseIndex, which (when parsed from source, at least) can never 29 // contain unknown or null values. 30 func ParseInstanceKey(key cty.Value) (InstanceKey, error) { 31 switch key.Type() { 32 case cty.String: 33 return StringKey(key.AsString()), nil 34 case cty.Number: 35 var idx int 36 err := gocty.FromCtyValue(key, &idx) 37 return IntKey(idx), err 38 default: 39 return NoKey, fmt.Errorf("either a string or an integer is required") 40 } 41 } 42 43 // NoKey represents the absense of an InstanceKey, for the single instance 44 // of a configuration object that does not use "count" or "for_each" at all. 45 var NoKey InstanceKey 46 47 // IntKey is the InstanceKey representation representing integer indices, as 48 // used when the "count" argument is specified or if for_each is used with 49 // a sequence type. 50 type IntKey int 51 52 func (k IntKey) instanceKeySigil() { 53 } 54 55 func (k IntKey) String() string { 56 return fmt.Sprintf("[%d]", int(k)) 57 } 58 59 // StringKey is the InstanceKey representation representing string indices, as 60 // used when the "for_each" argument is specified with a map or object type. 61 type StringKey string 62 63 func (k StringKey) instanceKeySigil() { 64 } 65 66 func (k StringKey) String() string { 67 // FIXME: This isn't _quite_ right because Go's quoted string syntax is 68 // slightly different than HCL's, but we'll accept it for now. 69 return fmt.Sprintf("[%q]", string(k)) 70 } 71 72 // InstanceKeyLess returns true if the first given instance key i should sort 73 // before the second key j, and false otherwise. 74 func InstanceKeyLess(i, j InstanceKey) bool { 75 iTy := instanceKeyType(i) 76 jTy := instanceKeyType(j) 77 78 switch { 79 case i == j: 80 return false 81 case i == NoKey: 82 return true 83 case j == NoKey: 84 return false 85 case iTy != jTy: 86 // The ordering here is arbitrary except that we want NoKeyType 87 // to sort before the others, so we'll just use the enum values 88 // of InstanceKeyType here (where NoKey is zero, sorting before 89 // any other). 90 return uint32(iTy) < uint32(jTy) 91 case iTy == IntKeyType: 92 return int(i.(IntKey)) < int(j.(IntKey)) 93 case iTy == StringKeyType: 94 return string(i.(StringKey)) < string(j.(StringKey)) 95 default: 96 // Shouldn't be possible to get down here in practice, since the 97 // above is exhaustive. 98 return false 99 } 100 } 101 102 func instanceKeyType(k InstanceKey) InstanceKeyType { 103 if _, ok := k.(StringKey); ok { 104 return StringKeyType 105 } 106 if _, ok := k.(IntKey); ok { 107 return IntKeyType 108 } 109 return NoKeyType 110 } 111 112 // InstanceKeyType represents the different types of instance key that are 113 // supported. Usually it is sufficient to simply type-assert an InstanceKey 114 // value to either IntKey or StringKey, but this type and its values can be 115 // used to represent the types themselves, rather than specific values 116 // of those types. 117 type InstanceKeyType rune 118 119 const ( 120 NoKeyType InstanceKeyType = 0 121 IntKeyType InstanceKeyType = 'I' 122 StringKeyType InstanceKeyType = 'S' 123 )