]> git.immae.eu Git - github/fretlink/terraform-provider-statuscake.git/blob - vendor/github.com/zclconf/go-cty/cty/value_init.go
Upgrade to 0.12
[github/fretlink/terraform-provider-statuscake.git] / vendor / github.com / zclconf / go-cty / cty / value_init.go
1 package cty
2
3 import (
4 "fmt"
5 "math/big"
6 "reflect"
7
8 "golang.org/x/text/unicode/norm"
9
10 "github.com/zclconf/go-cty/cty/set"
11 )
12
13 // BoolVal returns a Value of type Number whose internal value is the given
14 // bool.
15 func BoolVal(v bool) Value {
16 return Value{
17 ty: Bool,
18 v: v,
19 }
20 }
21
22 // NumberVal returns a Value of type Number whose internal value is the given
23 // big.Float. The returned value becomes the owner of the big.Float object,
24 // and so it's forbidden for the caller to mutate the object after it's
25 // wrapped in this way.
26 func NumberVal(v *big.Float) Value {
27 return Value{
28 ty: Number,
29 v: v,
30 }
31 }
32
33 // ParseNumberVal returns a Value of type number produced by parsing the given
34 // string as a decimal real number. To ensure that two identical strings will
35 // always produce an equal number, always use this function to derive a number
36 // from a string; it will ensure that the precision and rounding mode for the
37 // internal big decimal is configured in a consistent way.
38 //
39 // If the given string cannot be parsed as a number, the returned error has
40 // the message "a number is required", making it suitable to return to an
41 // end-user to signal a type conversion error.
42 //
43 // If the given string contains a number that becomes a recurring fraction
44 // when expressed in binary then it will be truncated to have a 512-bit
45 // mantissa. Note that this is a higher precision than that of a float64,
46 // so coverting the same decimal number first to float64 and then calling
47 // NumberFloatVal will not produce an equal result; the conversion first
48 // to float64 will round the mantissa to fewer than 512 bits.
49 func ParseNumberVal(s string) (Value, error) {
50 // Base 10, precision 512, and rounding to nearest even is the standard
51 // way to handle numbers arriving as strings.
52 f, _, err := big.ParseFloat(s, 10, 512, big.ToNearestEven)
53 if err != nil {
54 return NilVal, fmt.Errorf("a number is required")
55 }
56 return NumberVal(f), nil
57 }
58
59 // MustParseNumberVal is like ParseNumberVal but it will panic in case of any
60 // error. It can be used during initialization or any other situation where
61 // the given string is a constant or otherwise known to be correct by the
62 // caller.
63 func MustParseNumberVal(s string) Value {
64 ret, err := ParseNumberVal(s)
65 if err != nil {
66 panic(err)
67 }
68 return ret
69 }
70
71 // NumberIntVal returns a Value of type Number whose internal value is equal
72 // to the given integer.
73 func NumberIntVal(v int64) Value {
74 return NumberVal(new(big.Float).SetInt64(v))
75 }
76
77 // NumberUIntVal returns a Value of type Number whose internal value is equal
78 // to the given unsigned integer.
79 func NumberUIntVal(v uint64) Value {
80 return NumberVal(new(big.Float).SetUint64(v))
81 }
82
83 // NumberFloatVal returns a Value of type Number whose internal value is
84 // equal to the given float.
85 func NumberFloatVal(v float64) Value {
86 return NumberVal(new(big.Float).SetFloat64(v))
87 }
88
89 // StringVal returns a Value of type String whose internal value is the
90 // given string.
91 //
92 // Strings must be UTF-8 encoded sequences of valid unicode codepoints, and
93 // they are NFC-normalized on entry into the world of cty values.
94 //
95 // If the given string is not valid UTF-8 then behavior of string operations
96 // is undefined.
97 func StringVal(v string) Value {
98 return Value{
99 ty: String,
100 v: NormalizeString(v),
101 }
102 }
103
104 // NormalizeString applies the same normalization that cty applies when
105 // constructing string values.
106 //
107 // A return value from this function can be meaningfully compared byte-for-byte
108 // with a Value.AsString result.
109 func NormalizeString(s string) string {
110 return norm.NFC.String(s)
111 }
112
113 // ObjectVal returns a Value of an object type whose structure is defined
114 // by the key names and value types in the given map.
115 func ObjectVal(attrs map[string]Value) Value {
116 attrTypes := make(map[string]Type, len(attrs))
117 attrVals := make(map[string]interface{}, len(attrs))
118
119 for attr, val := range attrs {
120 attr = NormalizeString(attr)
121 attrTypes[attr] = val.ty
122 attrVals[attr] = val.v
123 }
124
125 return Value{
126 ty: Object(attrTypes),
127 v: attrVals,
128 }
129 }
130
131 // TupleVal returns a Value of a tuple type whose element types are
132 // defined by the value types in the given slice.
133 func TupleVal(elems []Value) Value {
134 elemTypes := make([]Type, len(elems))
135 elemVals := make([]interface{}, len(elems))
136
137 for i, val := range elems {
138 elemTypes[i] = val.ty
139 elemVals[i] = val.v
140 }
141
142 return Value{
143 ty: Tuple(elemTypes),
144 v: elemVals,
145 }
146 }
147
148 // ListVal returns a Value of list type whose element type is defined by
149 // the types of the given values, which must be homogenous.
150 //
151 // If the types are not all consistent (aside from elements that are of the
152 // dynamic pseudo-type) then this function will panic. It will panic also
153 // if the given list is empty, since then the element type cannot be inferred.
154 // (See also ListValEmpty.)
155 func ListVal(vals []Value) Value {
156 if len(vals) == 0 {
157 panic("must not call ListVal with empty slice")
158 }
159 elementType := DynamicPseudoType
160 rawList := make([]interface{}, len(vals))
161
162 for i, val := range vals {
163 if elementType == DynamicPseudoType {
164 elementType = val.ty
165 } else if val.ty != DynamicPseudoType && !elementType.Equals(val.ty) {
166 panic(fmt.Errorf(
167 "inconsistent list element types (%#v then %#v)",
168 elementType, val.ty,
169 ))
170 }
171
172 rawList[i] = val.v
173 }
174
175 return Value{
176 ty: List(elementType),
177 v: rawList,
178 }
179 }
180
181 // ListValEmpty returns an empty list of the given element type.
182 func ListValEmpty(element Type) Value {
183 return Value{
184 ty: List(element),
185 v: []interface{}{},
186 }
187 }
188
189 // MapVal returns a Value of a map type whose element type is defined by
190 // the types of the given values, which must be homogenous.
191 //
192 // If the types are not all consistent (aside from elements that are of the
193 // dynamic pseudo-type) then this function will panic. It will panic also
194 // if the given map is empty, since then the element type cannot be inferred.
195 // (See also MapValEmpty.)
196 func MapVal(vals map[string]Value) Value {
197 if len(vals) == 0 {
198 panic("must not call MapVal with empty map")
199 }
200 elementType := DynamicPseudoType
201 rawMap := make(map[string]interface{}, len(vals))
202
203 for key, val := range vals {
204 if elementType == DynamicPseudoType {
205 elementType = val.ty
206 } else if val.ty != DynamicPseudoType && !elementType.Equals(val.ty) {
207 panic(fmt.Errorf(
208 "inconsistent map element types (%#v then %#v)",
209 elementType, val.ty,
210 ))
211 }
212
213 rawMap[NormalizeString(key)] = val.v
214 }
215
216 return Value{
217 ty: Map(elementType),
218 v: rawMap,
219 }
220 }
221
222 // MapValEmpty returns an empty map of the given element type.
223 func MapValEmpty(element Type) Value {
224 return Value{
225 ty: Map(element),
226 v: map[string]interface{}{},
227 }
228 }
229
230 // SetVal returns a Value of set type whose element type is defined by
231 // the types of the given values, which must be homogenous.
232 //
233 // If the types are not all consistent (aside from elements that are of the
234 // dynamic pseudo-type) then this function will panic. It will panic also
235 // if the given list is empty, since then the element type cannot be inferred.
236 // (See also SetValEmpty.)
237 func SetVal(vals []Value) Value {
238 if len(vals) == 0 {
239 panic("must not call SetVal with empty slice")
240 }
241 elementType := DynamicPseudoType
242 rawList := make([]interface{}, len(vals))
243
244 for i, val := range vals {
245 if elementType == DynamicPseudoType {
246 elementType = val.ty
247 } else if val.ty != DynamicPseudoType && !elementType.Equals(val.ty) {
248 panic(fmt.Errorf(
249 "inconsistent set element types (%#v then %#v)",
250 elementType, val.ty,
251 ))
252 }
253
254 rawList[i] = val.v
255 }
256
257 rawVal := set.NewSetFromSlice(setRules{elementType}, rawList)
258
259 return Value{
260 ty: Set(elementType),
261 v: rawVal,
262 }
263 }
264
265 // SetValFromValueSet returns a Value of set type based on an already-constructed
266 // ValueSet.
267 //
268 // The element type of the returned value is the element type of the given
269 // set.
270 func SetValFromValueSet(s ValueSet) Value {
271 ety := s.ElementType()
272 rawVal := s.s.Copy() // copy so caller can't mutate what we wrap
273
274 return Value{
275 ty: Set(ety),
276 v: rawVal,
277 }
278 }
279
280 // SetValEmpty returns an empty set of the given element type.
281 func SetValEmpty(element Type) Value {
282 return Value{
283 ty: Set(element),
284 v: set.NewSet(setRules{element}),
285 }
286 }
287
288 // CapsuleVal creates a value of the given capsule type using the given
289 // wrapVal, which must be a pointer to a value of the capsule type's native
290 // type.
291 //
292 // This function will panic if the given type is not a capsule type, if
293 // the given wrapVal is not compatible with the given capsule type, or if
294 // wrapVal is not a pointer.
295 func CapsuleVal(ty Type, wrapVal interface{}) Value {
296 if !ty.IsCapsuleType() {
297 panic("not a capsule type")
298 }
299
300 wv := reflect.ValueOf(wrapVal)
301 if wv.Kind() != reflect.Ptr {
302 panic("wrapVal is not a pointer")
303 }
304
305 it := ty.typeImpl.(*capsuleType).GoType
306 if !wv.Type().Elem().AssignableTo(it) {
307 panic("wrapVal target is not compatible with the given capsule type")
308 }
309
310 return Value{
311 ty: ty,
312 v: wrapVal,
313 }
314 }