diff options
author | Alex Pilon <apilon@hashicorp.com> | 2019-02-22 18:24:37 -0500 |
---|---|---|
committer | Alex Pilon <apilon@hashicorp.com> | 2019-02-22 18:24:37 -0500 |
commit | 15c0b25d011f37e7c20aeca9eaf461f78285b8d9 (patch) | |
tree | 255c250a5c9d4801c74092d33b7337d8c14438ff /vendor/github.com/hashicorp/terraform/config/hcl2shim/values.go | |
parent | 07971ca38143c5faf951d152fba370ddcbe26ad5 (diff) | |
download | terraform-provider-statuscake-15c0b25d011f37e7c20aeca9eaf461f78285b8d9.tar.gz terraform-provider-statuscake-15c0b25d011f37e7c20aeca9eaf461f78285b8d9.tar.zst terraform-provider-statuscake-15c0b25d011f37e7c20aeca9eaf461f78285b8d9.zip |
deps: github.com/hashicorp/terraform@sdk-v0.11-with-go-modules
Updated via: go get github.com/hashicorp/terraform@sdk-v0.11-with-go-modules and go mod tidy
Diffstat (limited to 'vendor/github.com/hashicorp/terraform/config/hcl2shim/values.go')
-rw-r--r-- | vendor/github.com/hashicorp/terraform/config/hcl2shim/values.go | 246 |
1 files changed, 246 insertions, 0 deletions
diff --git a/vendor/github.com/hashicorp/terraform/config/hcl2shim/values.go b/vendor/github.com/hashicorp/terraform/config/hcl2shim/values.go new file mode 100644 index 0000000..0b697a5 --- /dev/null +++ b/vendor/github.com/hashicorp/terraform/config/hcl2shim/values.go | |||
@@ -0,0 +1,246 @@ | |||
1 | package hcl2shim | ||
2 | |||
3 | import ( | ||
4 | "fmt" | ||
5 | "math/big" | ||
6 | |||
7 | "github.com/hashicorp/hil/ast" | ||
8 | "github.com/zclconf/go-cty/cty" | ||
9 | ) | ||
10 | |||
11 | // UnknownVariableValue is a sentinel value that can be used | ||
12 | // to denote that the value of a variable is unknown at this time. | ||
13 | // RawConfig uses this information to build up data about | ||
14 | // unknown keys. | ||
15 | const UnknownVariableValue = "74D93920-ED26-11E3-AC10-0800200C9A66" | ||
16 | |||
17 | // ConfigValueFromHCL2 converts a value from HCL2 (really, from the cty dynamic | ||
18 | // types library that HCL2 uses) to a value type that matches what would've | ||
19 | // been produced from the HCL-based interpolator for an equivalent structure. | ||
20 | // | ||
21 | // This function will transform a cty null value into a Go nil value, which | ||
22 | // isn't a possible outcome of the HCL/HIL-based decoder and so callers may | ||
23 | // need to detect and reject any null values. | ||
24 | func ConfigValueFromHCL2(v cty.Value) interface{} { | ||
25 | if !v.IsKnown() { | ||
26 | return UnknownVariableValue | ||
27 | } | ||
28 | if v.IsNull() { | ||
29 | return nil | ||
30 | } | ||
31 | |||
32 | switch v.Type() { | ||
33 | case cty.Bool: | ||
34 | return v.True() // like HCL.BOOL | ||
35 | case cty.String: | ||
36 | return v.AsString() // like HCL token.STRING or token.HEREDOC | ||
37 | case cty.Number: | ||
38 | // We can't match HCL _exactly_ here because it distinguishes between | ||
39 | // int and float values, but we'll get as close as we can by using | ||
40 | // an int if the number is exactly representable, and a float if not. | ||
41 | // The conversion to float will force precision to that of a float64, | ||
42 | // which is potentially losing information from the specific number | ||
43 | // given, but no worse than what HCL would've done in its own conversion | ||
44 | // to float. | ||
45 | |||
46 | f := v.AsBigFloat() | ||
47 | if i, acc := f.Int64(); acc == big.Exact { | ||
48 | // if we're on a 32-bit system and the number is too big for 32-bit | ||
49 | // int then we'll fall through here and use a float64. | ||
50 | const MaxInt = int(^uint(0) >> 1) | ||
51 | const MinInt = -MaxInt - 1 | ||
52 | if i <= int64(MaxInt) && i >= int64(MinInt) { | ||
53 | return int(i) // Like HCL token.NUMBER | ||
54 | } | ||
55 | } | ||
56 | |||
57 | f64, _ := f.Float64() | ||
58 | return f64 // like HCL token.FLOAT | ||
59 | } | ||
60 | |||
61 | if v.Type().IsListType() || v.Type().IsSetType() || v.Type().IsTupleType() { | ||
62 | l := make([]interface{}, 0, v.LengthInt()) | ||
63 | it := v.ElementIterator() | ||
64 | for it.Next() { | ||
65 | _, ev := it.Element() | ||
66 | l = append(l, ConfigValueFromHCL2(ev)) | ||
67 | } | ||
68 | return l | ||
69 | } | ||
70 | |||
71 | if v.Type().IsMapType() || v.Type().IsObjectType() { | ||
72 | l := make(map[string]interface{}) | ||
73 | it := v.ElementIterator() | ||
74 | for it.Next() { | ||
75 | ek, ev := it.Element() | ||
76 | l[ek.AsString()] = ConfigValueFromHCL2(ev) | ||
77 | } | ||
78 | return l | ||
79 | } | ||
80 | |||
81 | // If we fall out here then we have some weird type that we haven't | ||
82 | // accounted for. This should never happen unless the caller is using | ||
83 | // capsule types, and we don't currently have any such types defined. | ||
84 | panic(fmt.Errorf("can't convert %#v to config value", v)) | ||
85 | } | ||
86 | |||
87 | // HCL2ValueFromConfigValue is the opposite of configValueFromHCL2: it takes | ||
88 | // a value as would be returned from the old interpolator and turns it into | ||
89 | // a cty.Value so it can be used within, for example, an HCL2 EvalContext. | ||
90 | func HCL2ValueFromConfigValue(v interface{}) cty.Value { | ||
91 | if v == nil { | ||
92 | return cty.NullVal(cty.DynamicPseudoType) | ||
93 | } | ||
94 | if v == UnknownVariableValue { | ||
95 | return cty.DynamicVal | ||
96 | } | ||
97 | |||
98 | switch tv := v.(type) { | ||
99 | case bool: | ||
100 | return cty.BoolVal(tv) | ||
101 | case string: | ||
102 | return cty.StringVal(tv) | ||
103 | case int: | ||
104 | return cty.NumberIntVal(int64(tv)) | ||
105 | case float64: | ||
106 | return cty.NumberFloatVal(tv) | ||
107 | case []interface{}: | ||
108 | vals := make([]cty.Value, len(tv)) | ||
109 | for i, ev := range tv { | ||
110 | vals[i] = HCL2ValueFromConfigValue(ev) | ||
111 | } | ||
112 | return cty.TupleVal(vals) | ||
113 | case map[string]interface{}: | ||
114 | vals := map[string]cty.Value{} | ||
115 | for k, ev := range tv { | ||
116 | vals[k] = HCL2ValueFromConfigValue(ev) | ||
117 | } | ||
118 | return cty.ObjectVal(vals) | ||
119 | default: | ||
120 | // HCL/HIL should never generate anything that isn't caught by | ||
121 | // the above, so if we get here something has gone very wrong. | ||
122 | panic(fmt.Errorf("can't convert %#v to cty.Value", v)) | ||
123 | } | ||
124 | } | ||
125 | |||
126 | func HILVariableFromHCL2Value(v cty.Value) ast.Variable { | ||
127 | if v.IsNull() { | ||
128 | // Caller should guarantee/check this before calling | ||
129 | panic("Null values cannot be represented in HIL") | ||
130 | } | ||
131 | if !v.IsKnown() { | ||
132 | return ast.Variable{ | ||
133 | Type: ast.TypeUnknown, | ||
134 | Value: UnknownVariableValue, | ||
135 | } | ||
136 | } | ||
137 | |||
138 | switch v.Type() { | ||
139 | case cty.Bool: | ||
140 | return ast.Variable{ | ||
141 | Type: ast.TypeBool, | ||
142 | Value: v.True(), | ||
143 | } | ||
144 | case cty.Number: | ||
145 | v := ConfigValueFromHCL2(v) | ||
146 | switch tv := v.(type) { | ||
147 | case int: | ||
148 | return ast.Variable{ | ||
149 | Type: ast.TypeInt, | ||
150 | Value: tv, | ||
151 | } | ||
152 | case float64: | ||
153 | return ast.Variable{ | ||
154 | Type: ast.TypeFloat, | ||
155 | Value: tv, | ||
156 | } | ||
157 | default: | ||
158 | // should never happen | ||
159 | panic("invalid return value for configValueFromHCL2") | ||
160 | } | ||
161 | case cty.String: | ||
162 | return ast.Variable{ | ||
163 | Type: ast.TypeString, | ||
164 | Value: v.AsString(), | ||
165 | } | ||
166 | } | ||
167 | |||
168 | if v.Type().IsListType() || v.Type().IsSetType() || v.Type().IsTupleType() { | ||
169 | l := make([]ast.Variable, 0, v.LengthInt()) | ||
170 | it := v.ElementIterator() | ||
171 | for it.Next() { | ||
172 | _, ev := it.Element() | ||
173 | l = append(l, HILVariableFromHCL2Value(ev)) | ||
174 | } | ||
175 | // If we were given a tuple then this could actually produce an invalid | ||
176 | // list with non-homogenous types, which we expect to be caught inside | ||
177 | // HIL just like a user-supplied non-homogenous list would be. | ||
178 | return ast.Variable{ | ||
179 | Type: ast.TypeList, | ||
180 | Value: l, | ||
181 | } | ||
182 | } | ||
183 | |||
184 | if v.Type().IsMapType() || v.Type().IsObjectType() { | ||
185 | l := make(map[string]ast.Variable) | ||
186 | it := v.ElementIterator() | ||
187 | for it.Next() { | ||
188 | ek, ev := it.Element() | ||
189 | l[ek.AsString()] = HILVariableFromHCL2Value(ev) | ||
190 | } | ||
191 | // If we were given an object then this could actually produce an invalid | ||
192 | // map with non-homogenous types, which we expect to be caught inside | ||
193 | // HIL just like a user-supplied non-homogenous map would be. | ||
194 | return ast.Variable{ | ||
195 | Type: ast.TypeMap, | ||
196 | Value: l, | ||
197 | } | ||
198 | } | ||
199 | |||
200 | // If we fall out here then we have some weird type that we haven't | ||
201 | // accounted for. This should never happen unless the caller is using | ||
202 | // capsule types, and we don't currently have any such types defined. | ||
203 | panic(fmt.Errorf("can't convert %#v to HIL variable", v)) | ||
204 | } | ||
205 | |||
206 | func HCL2ValueFromHILVariable(v ast.Variable) cty.Value { | ||
207 | switch v.Type { | ||
208 | case ast.TypeList: | ||
209 | vals := make([]cty.Value, len(v.Value.([]ast.Variable))) | ||
210 | for i, ev := range v.Value.([]ast.Variable) { | ||
211 | vals[i] = HCL2ValueFromHILVariable(ev) | ||
212 | } | ||
213 | return cty.TupleVal(vals) | ||
214 | case ast.TypeMap: | ||
215 | vals := make(map[string]cty.Value, len(v.Value.(map[string]ast.Variable))) | ||
216 | for k, ev := range v.Value.(map[string]ast.Variable) { | ||
217 | vals[k] = HCL2ValueFromHILVariable(ev) | ||
218 | } | ||
219 | return cty.ObjectVal(vals) | ||
220 | default: | ||
221 | return HCL2ValueFromConfigValue(v.Value) | ||
222 | } | ||
223 | } | ||
224 | |||
225 | func HCL2TypeForHILType(hilType ast.Type) cty.Type { | ||
226 | switch hilType { | ||
227 | case ast.TypeAny: | ||
228 | return cty.DynamicPseudoType | ||
229 | case ast.TypeUnknown: | ||
230 | return cty.DynamicPseudoType | ||
231 | case ast.TypeBool: | ||
232 | return cty.Bool | ||
233 | case ast.TypeInt: | ||
234 | return cty.Number | ||
235 | case ast.TypeFloat: | ||
236 | return cty.Number | ||
237 | case ast.TypeString: | ||
238 | return cty.String | ||
239 | case ast.TypeList: | ||
240 | return cty.List(cty.DynamicPseudoType) | ||
241 | case ast.TypeMap: | ||
242 | return cty.Map(cty.DynamicPseudoType) | ||
243 | default: | ||
244 | return cty.NilType // equilvalent to ast.TypeInvalid | ||
245 | } | ||
246 | } | ||