]> git.immae.eu Git - github/fretlink/terraform-provider-statuscake.git/blame - 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
CommitLineData
15c0b25d
AP
1package cty
2
3import (
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.
15func 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.
26func NumberVal(v *big.Float) Value {
27 return Value{
28 ty: Number,
29 v: v,
30 }
31}
32
107c1cdb
ND
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.
49func 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.
63func MustParseNumberVal(s string) Value {
64 ret, err := ParseNumberVal(s)
65 if err != nil {
66 panic(err)
67 }
68 return ret
69}
70
15c0b25d
AP
71// NumberIntVal returns a Value of type Number whose internal value is equal
72// to the given integer.
73func 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.
79func 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.
85func 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.
97func 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.
109func 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.
115func 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.
133func 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.)
155func 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.
182func 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.)
196func 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.
223func 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.)
237func 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.
270func 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.
281func 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.
295func 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}