diff options
Diffstat (limited to 'vendor/github.com/hashicorp/terraform/addrs/instance_key.go')
-rw-r--r-- | vendor/github.com/hashicorp/terraform/addrs/instance_key.go | 123 |
1 files changed, 123 insertions, 0 deletions
diff --git a/vendor/github.com/hashicorp/terraform/addrs/instance_key.go b/vendor/github.com/hashicorp/terraform/addrs/instance_key.go new file mode 100644 index 0000000..cef8b27 --- /dev/null +++ b/vendor/github.com/hashicorp/terraform/addrs/instance_key.go | |||
@@ -0,0 +1,123 @@ | |||
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 | ) | ||