]> git.immae.eu Git - github/fretlink/terraform-provider-statuscake.git/blame - vendor/github.com/zclconf/go-cty/cty/convert/conversion_collection.go
Upgrade to 0.12
[github/fretlink/terraform-provider-statuscake.git] / vendor / github.com / zclconf / go-cty / cty / convert / conversion_collection.go
CommitLineData
15c0b25d
AP
1package convert
2
3import (
4 "github.com/zclconf/go-cty/cty"
5)
6
7// conversionCollectionToList returns a conversion that will apply the given
8// conversion to all of the elements of a collection (something that supports
9// ForEachElement and LengthInt) and then returns the result as a list.
10//
11// "conv" can be nil if the elements are expected to already be of the
12// correct type and just need to be re-wrapped into a list. (For example,
13// if we're converting from a set into a list of the same element type.)
14func conversionCollectionToList(ety cty.Type, conv conversion) conversion {
15 return func(val cty.Value, path cty.Path) (cty.Value, error) {
16 elems := make([]cty.Value, 0, val.LengthInt())
17 i := int64(0)
18 path = append(path, nil)
19 it := val.ElementIterator()
20 for it.Next() {
21 _, val := it.Element()
22 var err error
23
24 path[len(path)-1] = cty.IndexStep{
25 Key: cty.NumberIntVal(i),
26 }
27
28 if conv != nil {
29 val, err = conv(val, path)
30 if err != nil {
31 return cty.NilVal, err
32 }
33 }
34 elems = append(elems, val)
35
36 i++
37 }
38
39 if len(elems) == 0 {
40 return cty.ListValEmpty(ety), nil
41 }
42
43 return cty.ListVal(elems), nil
44 }
45}
46
47// conversionCollectionToSet returns a conversion that will apply the given
48// conversion to all of the elements of a collection (something that supports
49// ForEachElement and LengthInt) and then returns the result as a set.
50//
51// "conv" can be nil if the elements are expected to already be of the
52// correct type and just need to be re-wrapped into a set. (For example,
53// if we're converting from a list into a set of the same element type.)
54func conversionCollectionToSet(ety cty.Type, conv conversion) conversion {
55 return func(val cty.Value, path cty.Path) (cty.Value, error) {
56 elems := make([]cty.Value, 0, val.LengthInt())
57 i := int64(0)
58 path = append(path, nil)
59 it := val.ElementIterator()
60 for it.Next() {
61 _, val := it.Element()
62 var err error
63
64 path[len(path)-1] = cty.IndexStep{
65 Key: cty.NumberIntVal(i),
66 }
67
68 if conv != nil {
69 val, err = conv(val, path)
70 if err != nil {
71 return cty.NilVal, err
72 }
73 }
74 elems = append(elems, val)
75
76 i++
77 }
78
79 if len(elems) == 0 {
80 return cty.SetValEmpty(ety), nil
81 }
82
83 return cty.SetVal(elems), nil
84 }
85}
86
107c1cdb
ND
87// conversionCollectionToMap returns a conversion that will apply the given
88// conversion to all of the elements of a collection (something that supports
89// ForEachElement and LengthInt) and then returns the result as a map.
90//
91// "conv" can be nil if the elements are expected to already be of the
92// correct type and just need to be re-wrapped into a map.
93func conversionCollectionToMap(ety cty.Type, conv conversion) conversion {
94 return func(val cty.Value, path cty.Path) (cty.Value, error) {
95 elems := make(map[string]cty.Value, 0)
96 path = append(path, nil)
97 it := val.ElementIterator()
98 for it.Next() {
99 key, val := it.Element()
100 var err error
101
102 path[len(path)-1] = cty.IndexStep{
103 Key: key,
104 }
105
106 keyStr, err := Convert(key, cty.String)
107 if err != nil {
108 // Should never happen, because keys can only be numbers or
109 // strings and both can convert to string.
110 return cty.DynamicVal, path.NewErrorf("cannot convert key type %s to string for map", key.Type().FriendlyName())
111 }
112
113 if conv != nil {
114 val, err = conv(val, path)
115 if err != nil {
116 return cty.NilVal, err
117 }
118 }
119
120 elems[keyStr.AsString()] = val
121 }
122
123 if len(elems) == 0 {
124 return cty.MapValEmpty(ety), nil
125 }
126
127 return cty.MapVal(elems), nil
128 }
129}
130
131// conversionTupleToSet returns a conversion that will take a value of the
132// given tuple type and return a set of the given element type.
133//
134// Will panic if the given tupleType isn't actually a tuple type.
135func conversionTupleToSet(tupleType cty.Type, listEty cty.Type, unsafe bool) conversion {
136 tupleEtys := tupleType.TupleElementTypes()
137
138 if len(tupleEtys) == 0 {
139 // Empty tuple short-circuit
140 return func(val cty.Value, path cty.Path) (cty.Value, error) {
141 return cty.SetValEmpty(listEty), nil
142 }
143 }
144
145 if listEty == cty.DynamicPseudoType {
146 // This is a special case where the caller wants us to find
147 // a suitable single type that all elements can convert to, if
148 // possible.
149 listEty, _ = unify(tupleEtys, unsafe)
150 if listEty == cty.NilType {
151 return nil
152 }
153 }
154
155 elemConvs := make([]conversion, len(tupleEtys))
156 for i, tupleEty := range tupleEtys {
157 if tupleEty.Equals(listEty) {
158 // no conversion required
159 continue
160 }
161
162 elemConvs[i] = getConversion(tupleEty, listEty, unsafe)
163 if elemConvs[i] == nil {
164 // If any of our element conversions are impossible, then the our
165 // whole conversion is impossible.
166 return nil
167 }
168 }
169
170 // If we fall out here then a conversion is possible, using the
171 // element conversions in elemConvs
172 return func(val cty.Value, path cty.Path) (cty.Value, error) {
173 elems := make([]cty.Value, 0, len(elemConvs))
174 path = append(path, nil)
175 i := int64(0)
176 it := val.ElementIterator()
177 for it.Next() {
178 _, val := it.Element()
179 var err error
180
181 path[len(path)-1] = cty.IndexStep{
182 Key: cty.NumberIntVal(i),
183 }
184
185 conv := elemConvs[i]
186 if conv != nil {
187 val, err = conv(val, path)
188 if err != nil {
189 return cty.NilVal, err
190 }
191 }
192 elems = append(elems, val)
193
194 i++
195 }
196
197 return cty.SetVal(elems), nil
198 }
199}
200
15c0b25d
AP
201// conversionTupleToList returns a conversion that will take a value of the
202// given tuple type and return a list of the given element type.
203//
204// Will panic if the given tupleType isn't actually a tuple type.
205func conversionTupleToList(tupleType cty.Type, listEty cty.Type, unsafe bool) conversion {
206 tupleEtys := tupleType.TupleElementTypes()
207
208 if len(tupleEtys) == 0 {
209 // Empty tuple short-circuit
210 return func(val cty.Value, path cty.Path) (cty.Value, error) {
211 return cty.ListValEmpty(listEty), nil
212 }
213 }
214
215 if listEty == cty.DynamicPseudoType {
216 // This is a special case where the caller wants us to find
217 // a suitable single type that all elements can convert to, if
218 // possible.
219 listEty, _ = unify(tupleEtys, unsafe)
220 if listEty == cty.NilType {
221 return nil
222 }
223 }
224
225 elemConvs := make([]conversion, len(tupleEtys))
226 for i, tupleEty := range tupleEtys {
227 if tupleEty.Equals(listEty) {
228 // no conversion required
229 continue
230 }
231
232 elemConvs[i] = getConversion(tupleEty, listEty, unsafe)
233 if elemConvs[i] == nil {
234 // If any of our element conversions are impossible, then the our
235 // whole conversion is impossible.
236 return nil
237 }
238 }
239
240 // If we fall out here then a conversion is possible, using the
241 // element conversions in elemConvs
242 return func(val cty.Value, path cty.Path) (cty.Value, error) {
243 elems := make([]cty.Value, 0, len(elemConvs))
244 path = append(path, nil)
245 i := int64(0)
246 it := val.ElementIterator()
247 for it.Next() {
248 _, val := it.Element()
249 var err error
250
251 path[len(path)-1] = cty.IndexStep{
252 Key: cty.NumberIntVal(i),
253 }
254
255 conv := elemConvs[i]
256 if conv != nil {
257 val, err = conv(val, path)
258 if err != nil {
259 return cty.NilVal, err
260 }
261 }
262 elems = append(elems, val)
263
264 i++
265 }
266
267 return cty.ListVal(elems), nil
268 }
269}
270
271// conversionObjectToMap returns a conversion that will take a value of the
272// given object type and return a map of the given element type.
273//
274// Will panic if the given objectType isn't actually an object type.
275func conversionObjectToMap(objectType cty.Type, mapEty cty.Type, unsafe bool) conversion {
276 objectAtys := objectType.AttributeTypes()
277
278 if len(objectAtys) == 0 {
279 // Empty object short-circuit
280 return func(val cty.Value, path cty.Path) (cty.Value, error) {
281 return cty.MapValEmpty(mapEty), nil
282 }
283 }
284
285 if mapEty == cty.DynamicPseudoType {
286 // This is a special case where the caller wants us to find
287 // a suitable single type that all elements can convert to, if
288 // possible.
289 objectAtysList := make([]cty.Type, 0, len(objectAtys))
290 for _, aty := range objectAtys {
291 objectAtysList = append(objectAtysList, aty)
292 }
293 mapEty, _ = unify(objectAtysList, unsafe)
294 if mapEty == cty.NilType {
295 return nil
296 }
297 }
298
299 elemConvs := make(map[string]conversion, len(objectAtys))
300 for name, objectAty := range objectAtys {
301 if objectAty.Equals(mapEty) {
302 // no conversion required
303 continue
304 }
305
306 elemConvs[name] = getConversion(objectAty, mapEty, unsafe)
307 if elemConvs[name] == nil {
308 // If any of our element conversions are impossible, then the our
309 // whole conversion is impossible.
310 return nil
311 }
312 }
313
314 // If we fall out here then a conversion is possible, using the
315 // element conversions in elemConvs
316 return func(val cty.Value, path cty.Path) (cty.Value, error) {
317 elems := make(map[string]cty.Value, len(elemConvs))
318 path = append(path, nil)
319 it := val.ElementIterator()
320 for it.Next() {
321 name, val := it.Element()
322 var err error
323
324 path[len(path)-1] = cty.IndexStep{
325 Key: name,
326 }
327
328 conv := elemConvs[name.AsString()]
329 if conv != nil {
330 val, err = conv(val, path)
331 if err != nil {
332 return cty.NilVal, err
333 }
334 }
335 elems[name.AsString()] = val
336 }
337
338 return cty.MapVal(elems), nil
339 }
340}