]> git.immae.eu Git - github/fretlink/terraform-provider-statuscake.git/blob - vendor/github.com/hashicorp/terraform/lang/funcs/collection.go
Upgrade to 0.12
[github/fretlink/terraform-provider-statuscake.git] / vendor / github.com / hashicorp / terraform / lang / funcs / collection.go
1 package funcs
2
3 import (
4 "errors"
5 "fmt"
6 "sort"
7
8 "github.com/zclconf/go-cty/cty"
9 "github.com/zclconf/go-cty/cty/convert"
10 "github.com/zclconf/go-cty/cty/function"
11 "github.com/zclconf/go-cty/cty/function/stdlib"
12 "github.com/zclconf/go-cty/cty/gocty"
13 )
14
15 var ElementFunc = function.New(&function.Spec{
16 Params: []function.Parameter{
17 {
18 Name: "list",
19 Type: cty.DynamicPseudoType,
20 },
21 {
22 Name: "index",
23 Type: cty.Number,
24 },
25 },
26 Type: func(args []cty.Value) (cty.Type, error) {
27 list := args[0]
28 listTy := list.Type()
29 switch {
30 case listTy.IsListType():
31 return listTy.ElementType(), nil
32 case listTy.IsTupleType():
33 if !args[1].IsKnown() {
34 // If the index isn't known yet then we can't predict the
35 // result type since each tuple element can have its own type.
36 return cty.DynamicPseudoType, nil
37 }
38
39 etys := listTy.TupleElementTypes()
40 var index int
41 err := gocty.FromCtyValue(args[1], &index)
42 if err != nil {
43 // e.g. fractional number where whole number is required
44 return cty.DynamicPseudoType, fmt.Errorf("invalid index: %s", err)
45 }
46 if len(etys) == 0 {
47 return cty.DynamicPseudoType, errors.New("cannot use element function with an empty list")
48 }
49 index = index % len(etys)
50 return etys[index], nil
51 default:
52 return cty.DynamicPseudoType, fmt.Errorf("cannot read elements from %s", listTy.FriendlyName())
53 }
54 },
55 Impl: func(args []cty.Value, retType cty.Type) (cty.Value, error) {
56 var index int
57 err := gocty.FromCtyValue(args[1], &index)
58 if err != nil {
59 // can't happen because we checked this in the Type function above
60 return cty.DynamicVal, fmt.Errorf("invalid index: %s", err)
61 }
62
63 if !args[0].IsKnown() {
64 return cty.UnknownVal(retType), nil
65 }
66
67 l := args[0].LengthInt()
68 if l == 0 {
69 return cty.DynamicVal, errors.New("cannot use element function with an empty list")
70 }
71 index = index % l
72
73 // We did all the necessary type checks in the type function above,
74 // so this is guaranteed not to fail.
75 return args[0].Index(cty.NumberIntVal(int64(index))), nil
76 },
77 })
78
79 var LengthFunc = function.New(&function.Spec{
80 Params: []function.Parameter{
81 {
82 Name: "value",
83 Type: cty.DynamicPseudoType,
84 AllowDynamicType: true,
85 AllowUnknown: true,
86 },
87 },
88 Type: func(args []cty.Value) (cty.Type, error) {
89 collTy := args[0].Type()
90 switch {
91 case collTy == cty.String || collTy.IsTupleType() || collTy.IsObjectType() || collTy.IsListType() || collTy.IsMapType() || collTy.IsSetType() || collTy == cty.DynamicPseudoType:
92 return cty.Number, nil
93 default:
94 return cty.Number, errors.New("argument must be a string, a collection type, or a structural type")
95 }
96 },
97 Impl: func(args []cty.Value, retType cty.Type) (cty.Value, error) {
98 coll := args[0]
99 collTy := args[0].Type()
100 switch {
101 case collTy == cty.DynamicPseudoType:
102 return cty.UnknownVal(cty.Number), nil
103 case collTy.IsTupleType():
104 l := len(collTy.TupleElementTypes())
105 return cty.NumberIntVal(int64(l)), nil
106 case collTy.IsObjectType():
107 l := len(collTy.AttributeTypes())
108 return cty.NumberIntVal(int64(l)), nil
109 case collTy == cty.String:
110 // We'll delegate to the cty stdlib strlen function here, because
111 // it deals with all of the complexities of tokenizing unicode
112 // grapheme clusters.
113 return stdlib.Strlen(coll)
114 case collTy.IsListType() || collTy.IsSetType() || collTy.IsMapType():
115 return coll.Length(), nil
116 default:
117 // Should never happen, because of the checks in our Type func above
118 return cty.UnknownVal(cty.Number), errors.New("impossible value type for length(...)")
119 }
120 },
121 })
122
123 // CoalesceFunc constructs a function that takes any number of arguments and
124 // returns the first one that isn't empty. This function was copied from go-cty
125 // stdlib and modified so that it returns the first *non-empty* non-null element
126 // from a sequence, instead of merely the first non-null.
127 var CoalesceFunc = function.New(&function.Spec{
128 Params: []function.Parameter{},
129 VarParam: &function.Parameter{
130 Name: "vals",
131 Type: cty.DynamicPseudoType,
132 AllowUnknown: true,
133 AllowDynamicType: true,
134 AllowNull: true,
135 },
136 Type: func(args []cty.Value) (ret cty.Type, err error) {
137 argTypes := make([]cty.Type, len(args))
138 for i, val := range args {
139 argTypes[i] = val.Type()
140 }
141 retType, _ := convert.UnifyUnsafe(argTypes)
142 if retType == cty.NilType {
143 return cty.NilType, errors.New("all arguments must have the same type")
144 }
145 return retType, nil
146 },
147 Impl: func(args []cty.Value, retType cty.Type) (ret cty.Value, err error) {
148 for _, argVal := range args {
149 // We already know this will succeed because of the checks in our Type func above
150 argVal, _ = convert.Convert(argVal, retType)
151 if !argVal.IsKnown() {
152 return cty.UnknownVal(retType), nil
153 }
154 if argVal.IsNull() {
155 continue
156 }
157 if retType == cty.String && argVal.RawEquals(cty.StringVal("")) {
158 continue
159 }
160
161 return argVal, nil
162 }
163 return cty.NilVal, errors.New("no non-null, non-empty-string arguments")
164 },
165 })
166
167 // CoalesceListFunc constructs a function that takes any number of list arguments
168 // and returns the first one that isn't empty.
169 var CoalesceListFunc = function.New(&function.Spec{
170 Params: []function.Parameter{},
171 VarParam: &function.Parameter{
172 Name: "vals",
173 Type: cty.DynamicPseudoType,
174 AllowUnknown: true,
175 AllowDynamicType: true,
176 AllowNull: true,
177 },
178 Type: func(args []cty.Value) (ret cty.Type, err error) {
179 if len(args) == 0 {
180 return cty.NilType, errors.New("at least one argument is required")
181 }
182
183 argTypes := make([]cty.Type, len(args))
184
185 for i, arg := range args {
186 // if any argument is unknown, we can't be certain know which type we will return
187 if !arg.IsKnown() {
188 return cty.DynamicPseudoType, nil
189 }
190 ty := arg.Type()
191
192 if !ty.IsListType() && !ty.IsTupleType() {
193 return cty.NilType, errors.New("coalescelist arguments must be lists or tuples")
194 }
195
196 argTypes[i] = arg.Type()
197 }
198
199 last := argTypes[0]
200 // If there are mixed types, we have to return a dynamic type.
201 for _, next := range argTypes[1:] {
202 if !next.Equals(last) {
203 return cty.DynamicPseudoType, nil
204 }
205 }
206
207 return last, nil
208 },
209 Impl: func(args []cty.Value, retType cty.Type) (ret cty.Value, err error) {
210 for _, arg := range args {
211 if !arg.IsKnown() {
212 // If we run into an unknown list at some point, we can't
213 // predict the final result yet. (If there's a known, non-empty
214 // arg before this then we won't get here.)
215 return cty.UnknownVal(retType), nil
216 }
217
218 if arg.LengthInt() > 0 {
219 return arg, nil
220 }
221 }
222
223 return cty.NilVal, errors.New("no non-null arguments")
224 },
225 })
226
227 // CompactFunc constructs a function that takes a list of strings and returns a new list
228 // with any empty string elements removed.
229 var CompactFunc = function.New(&function.Spec{
230 Params: []function.Parameter{
231 {
232 Name: "list",
233 Type: cty.List(cty.String),
234 },
235 },
236 Type: function.StaticReturnType(cty.List(cty.String)),
237 Impl: func(args []cty.Value, retType cty.Type) (ret cty.Value, err error) {
238 listVal := args[0]
239 if !listVal.IsWhollyKnown() {
240 // If some of the element values aren't known yet then we
241 // can't yet return a compacted list
242 return cty.UnknownVal(retType), nil
243 }
244
245 var outputList []cty.Value
246
247 for it := listVal.ElementIterator(); it.Next(); {
248 _, v := it.Element()
249 if v.AsString() == "" {
250 continue
251 }
252 outputList = append(outputList, v)
253 }
254
255 if len(outputList) == 0 {
256 return cty.ListValEmpty(cty.String), nil
257 }
258
259 return cty.ListVal(outputList), nil
260 },
261 })
262
263 // ContainsFunc constructs a function that determines whether a given list or
264 // set contains a given single value as one of its elements.
265 var ContainsFunc = function.New(&function.Spec{
266 Params: []function.Parameter{
267 {
268 Name: "list",
269 Type: cty.DynamicPseudoType,
270 },
271 {
272 Name: "value",
273 Type: cty.DynamicPseudoType,
274 },
275 },
276 Type: function.StaticReturnType(cty.Bool),
277 Impl: func(args []cty.Value, retType cty.Type) (ret cty.Value, err error) {
278 arg := args[0]
279 ty := arg.Type()
280
281 if !ty.IsListType() && !ty.IsTupleType() && !ty.IsSetType() {
282 return cty.NilVal, errors.New("argument must be list, tuple, or set")
283 }
284
285 _, err = Index(cty.TupleVal(arg.AsValueSlice()), args[1])
286 if err != nil {
287 return cty.False, nil
288 }
289
290 return cty.True, nil
291 },
292 })
293
294 // IndexFunc constructs a function that finds the element index for a given value in a list.
295 var IndexFunc = function.New(&function.Spec{
296 Params: []function.Parameter{
297 {
298 Name: "list",
299 Type: cty.DynamicPseudoType,
300 },
301 {
302 Name: "value",
303 Type: cty.DynamicPseudoType,
304 },
305 },
306 Type: function.StaticReturnType(cty.Number),
307 Impl: func(args []cty.Value, retType cty.Type) (ret cty.Value, err error) {
308 if !(args[0].Type().IsListType() || args[0].Type().IsTupleType()) {
309 return cty.NilVal, errors.New("argument must be a list or tuple")
310 }
311
312 if !args[0].IsKnown() {
313 return cty.UnknownVal(cty.Number), nil
314 }
315
316 if args[0].LengthInt() == 0 { // Easy path
317 return cty.NilVal, errors.New("cannot search an empty list")
318 }
319
320 for it := args[0].ElementIterator(); it.Next(); {
321 i, v := it.Element()
322 eq, err := stdlib.Equal(v, args[1])
323 if err != nil {
324 return cty.NilVal, err
325 }
326 if !eq.IsKnown() {
327 return cty.UnknownVal(cty.Number), nil
328 }
329 if eq.True() {
330 return i, nil
331 }
332 }
333 return cty.NilVal, errors.New("item not found")
334
335 },
336 })
337
338 // DistinctFunc constructs a function that takes a list and returns a new list
339 // with any duplicate elements removed.
340 var DistinctFunc = function.New(&function.Spec{
341 Params: []function.Parameter{
342 {
343 Name: "list",
344 Type: cty.List(cty.DynamicPseudoType),
345 },
346 },
347 Type: func(args []cty.Value) (cty.Type, error) {
348 return args[0].Type(), nil
349 },
350 Impl: func(args []cty.Value, retType cty.Type) (ret cty.Value, err error) {
351 listVal := args[0]
352
353 if !listVal.IsWhollyKnown() {
354 return cty.UnknownVal(retType), nil
355 }
356 var list []cty.Value
357
358 for it := listVal.ElementIterator(); it.Next(); {
359 _, v := it.Element()
360 list, err = appendIfMissing(list, v)
361 if err != nil {
362 return cty.NilVal, err
363 }
364 }
365
366 return cty.ListVal(list), nil
367 },
368 })
369
370 // ChunklistFunc constructs a function that splits a single list into fixed-size chunks,
371 // returning a list of lists.
372 var ChunklistFunc = function.New(&function.Spec{
373 Params: []function.Parameter{
374 {
375 Name: "list",
376 Type: cty.List(cty.DynamicPseudoType),
377 },
378 {
379 Name: "size",
380 Type: cty.Number,
381 },
382 },
383 Type: func(args []cty.Value) (cty.Type, error) {
384 return cty.List(args[0].Type()), nil
385 },
386 Impl: func(args []cty.Value, retType cty.Type) (ret cty.Value, err error) {
387 listVal := args[0]
388 if !listVal.IsKnown() {
389 return cty.UnknownVal(retType), nil
390 }
391
392 var size int
393 err = gocty.FromCtyValue(args[1], &size)
394 if err != nil {
395 return cty.NilVal, fmt.Errorf("invalid index: %s", err)
396 }
397
398 if size < 0 {
399 return cty.NilVal, errors.New("the size argument must be positive")
400 }
401
402 output := make([]cty.Value, 0)
403
404 // if size is 0, returns a list made of the initial list
405 if size == 0 {
406 output = append(output, listVal)
407 return cty.ListVal(output), nil
408 }
409
410 chunk := make([]cty.Value, 0)
411
412 l := args[0].LengthInt()
413 i := 0
414
415 for it := listVal.ElementIterator(); it.Next(); {
416 _, v := it.Element()
417 chunk = append(chunk, v)
418
419 // Chunk when index isn't 0, or when reaching the values's length
420 if (i+1)%size == 0 || (i+1) == l {
421 output = append(output, cty.ListVal(chunk))
422 chunk = make([]cty.Value, 0)
423 }
424 i++
425 }
426
427 return cty.ListVal(output), nil
428 },
429 })
430
431 // FlattenFunc constructs a function that takes a list and replaces any elements
432 // that are lists with a flattened sequence of the list contents.
433 var FlattenFunc = function.New(&function.Spec{
434 Params: []function.Parameter{
435 {
436 Name: "list",
437 Type: cty.DynamicPseudoType,
438 },
439 },
440 Type: func(args []cty.Value) (cty.Type, error) {
441 if !args[0].IsWhollyKnown() {
442 return cty.DynamicPseudoType, nil
443 }
444
445 argTy := args[0].Type()
446 if !argTy.IsListType() && !argTy.IsSetType() && !argTy.IsTupleType() {
447 return cty.NilType, errors.New("can only flatten lists, sets and tuples")
448 }
449
450 retVal, known := flattener(args[0])
451 if !known {
452 return cty.DynamicPseudoType, nil
453 }
454
455 tys := make([]cty.Type, len(retVal))
456 for i, ty := range retVal {
457 tys[i] = ty.Type()
458 }
459 return cty.Tuple(tys), nil
460 },
461 Impl: func(args []cty.Value, retType cty.Type) (ret cty.Value, err error) {
462 inputList := args[0]
463 if inputList.LengthInt() == 0 {
464 return cty.EmptyTupleVal, nil
465 }
466
467 out, known := flattener(inputList)
468 if !known {
469 return cty.UnknownVal(retType), nil
470 }
471
472 return cty.TupleVal(out), nil
473 },
474 })
475
476 // Flatten until it's not a cty.List, and return whether the value is known.
477 // We can flatten lists with unknown values, as long as they are not
478 // lists themselves.
479 func flattener(flattenList cty.Value) ([]cty.Value, bool) {
480 out := make([]cty.Value, 0)
481 for it := flattenList.ElementIterator(); it.Next(); {
482 _, val := it.Element()
483 if val.Type().IsListType() || val.Type().IsSetType() || val.Type().IsTupleType() {
484 if !val.IsKnown() {
485 return out, false
486 }
487
488 res, known := flattener(val)
489 if !known {
490 return res, known
491 }
492 out = append(out, res...)
493 } else {
494 out = append(out, val)
495 }
496 }
497 return out, true
498 }
499
500 // KeysFunc constructs a function that takes a map and returns a sorted list of the map keys.
501 var KeysFunc = function.New(&function.Spec{
502 Params: []function.Parameter{
503 {
504 Name: "inputMap",
505 Type: cty.DynamicPseudoType,
506 AllowUnknown: true,
507 },
508 },
509 Type: func(args []cty.Value) (cty.Type, error) {
510 ty := args[0].Type()
511 switch {
512 case ty.IsMapType():
513 return cty.List(cty.String), nil
514 case ty.IsObjectType():
515 atys := ty.AttributeTypes()
516 if len(atys) == 0 {
517 return cty.EmptyTuple, nil
518 }
519 // All of our result elements will be strings, and atys just
520 // decides how many there are.
521 etys := make([]cty.Type, len(atys))
522 for i := range etys {
523 etys[i] = cty.String
524 }
525 return cty.Tuple(etys), nil
526 default:
527 return cty.DynamicPseudoType, function.NewArgErrorf(0, "must have map or object type")
528 }
529 },
530 Impl: func(args []cty.Value, retType cty.Type) (cty.Value, error) {
531 m := args[0]
532 var keys []cty.Value
533
534 switch {
535 case m.Type().IsObjectType():
536 // In this case we allow unknown values so we must work only with
537 // the attribute _types_, not with the value itself.
538 var names []string
539 for name := range m.Type().AttributeTypes() {
540 names = append(names, name)
541 }
542 sort.Strings(names) // same ordering guaranteed by cty's ElementIterator
543 if len(names) == 0 {
544 return cty.EmptyTupleVal, nil
545 }
546 keys = make([]cty.Value, len(names))
547 for i, name := range names {
548 keys[i] = cty.StringVal(name)
549 }
550 return cty.TupleVal(keys), nil
551 default:
552 if !m.IsKnown() {
553 return cty.UnknownVal(retType), nil
554 }
555
556 // cty guarantees that ElementIterator will iterate in lexicographical
557 // order by key.
558 for it := args[0].ElementIterator(); it.Next(); {
559 k, _ := it.Element()
560 keys = append(keys, k)
561 }
562 if len(keys) == 0 {
563 return cty.ListValEmpty(cty.String), nil
564 }
565 return cty.ListVal(keys), nil
566 }
567 },
568 })
569
570 // ListFunc constructs a function that takes an arbitrary number of arguments
571 // and returns a list containing those values in the same order.
572 //
573 // This function is deprecated in Terraform v0.12
574 var ListFunc = function.New(&function.Spec{
575 Params: []function.Parameter{},
576 VarParam: &function.Parameter{
577 Name: "vals",
578 Type: cty.DynamicPseudoType,
579 AllowUnknown: true,
580 AllowDynamicType: true,
581 AllowNull: true,
582 },
583 Type: func(args []cty.Value) (ret cty.Type, err error) {
584 if len(args) == 0 {
585 return cty.NilType, errors.New("at least one argument is required")
586 }
587
588 argTypes := make([]cty.Type, len(args))
589
590 for i, arg := range args {
591 argTypes[i] = arg.Type()
592 }
593
594 retType, _ := convert.UnifyUnsafe(argTypes)
595 if retType == cty.NilType {
596 return cty.NilType, errors.New("all arguments must have the same type")
597 }
598
599 return cty.List(retType), nil
600 },
601 Impl: func(args []cty.Value, retType cty.Type) (ret cty.Value, err error) {
602 newList := make([]cty.Value, 0, len(args))
603
604 for _, arg := range args {
605 // We already know this will succeed because of the checks in our Type func above
606 arg, _ = convert.Convert(arg, retType.ElementType())
607 newList = append(newList, arg)
608 }
609
610 return cty.ListVal(newList), nil
611 },
612 })
613
614 // LookupFunc constructs a function that performs dynamic lookups of map types.
615 var LookupFunc = function.New(&function.Spec{
616 Params: []function.Parameter{
617 {
618 Name: "inputMap",
619 Type: cty.DynamicPseudoType,
620 },
621 {
622 Name: "key",
623 Type: cty.String,
624 },
625 },
626 VarParam: &function.Parameter{
627 Name: "default",
628 Type: cty.DynamicPseudoType,
629 AllowUnknown: true,
630 AllowDynamicType: true,
631 AllowNull: true,
632 },
633 Type: func(args []cty.Value) (ret cty.Type, err error) {
634 if len(args) < 1 || len(args) > 3 {
635 return cty.NilType, fmt.Errorf("lookup() takes two or three arguments, got %d", len(args))
636 }
637
638 ty := args[0].Type()
639
640 switch {
641 case ty.IsObjectType():
642 if !args[1].IsKnown() {
643 return cty.DynamicPseudoType, nil
644 }
645
646 key := args[1].AsString()
647 if ty.HasAttribute(key) {
648 return args[0].GetAttr(key).Type(), nil
649 } else if len(args) == 3 {
650 // if the key isn't found but a default is provided,
651 // return the default type
652 return args[2].Type(), nil
653 }
654 return cty.DynamicPseudoType, function.NewArgErrorf(0, "the given object has no attribute %q", key)
655 case ty.IsMapType():
656 return ty.ElementType(), nil
657 default:
658 return cty.NilType, function.NewArgErrorf(0, "lookup() requires a map as the first argument")
659 }
660 },
661 Impl: func(args []cty.Value, retType cty.Type) (ret cty.Value, err error) {
662 var defaultVal cty.Value
663 defaultValueSet := false
664
665 if len(args) == 3 {
666 defaultVal = args[2]
667 defaultValueSet = true
668 }
669
670 mapVar := args[0]
671 lookupKey := args[1].AsString()
672
673 if !mapVar.IsWhollyKnown() {
674 return cty.UnknownVal(retType), nil
675 }
676
677 if mapVar.Type().IsObjectType() {
678 if mapVar.Type().HasAttribute(lookupKey) {
679 return mapVar.GetAttr(lookupKey), nil
680 }
681 } else if mapVar.HasIndex(cty.StringVal(lookupKey)) == cty.True {
682 v := mapVar.Index(cty.StringVal(lookupKey))
683 if ty := v.Type(); !ty.Equals(cty.NilType) {
684 switch {
685 case ty.Equals(cty.String):
686 return cty.StringVal(v.AsString()), nil
687 case ty.Equals(cty.Number):
688 return cty.NumberVal(v.AsBigFloat()), nil
689 default:
690 return cty.NilVal, errors.New("lookup() can only be used with flat lists")
691 }
692 }
693 }
694
695 if defaultValueSet {
696 defaultVal, err = convert.Convert(defaultVal, retType)
697 if err != nil {
698 return cty.NilVal, err
699 }
700 return defaultVal, nil
701 }
702
703 return cty.UnknownVal(cty.DynamicPseudoType), fmt.Errorf(
704 "lookup failed to find '%s'", lookupKey)
705 },
706 })
707
708 // MapFunc constructs a function that takes an even number of arguments and
709 // returns a map whose elements are constructed from consecutive pairs of arguments.
710 //
711 // This function is deprecated in Terraform v0.12
712 var MapFunc = function.New(&function.Spec{
713 Params: []function.Parameter{},
714 VarParam: &function.Parameter{
715 Name: "vals",
716 Type: cty.DynamicPseudoType,
717 AllowUnknown: true,
718 AllowDynamicType: true,
719 AllowNull: true,
720 },
721 Type: func(args []cty.Value) (ret cty.Type, err error) {
722 if len(args) < 2 || len(args)%2 != 0 {
723 return cty.NilType, fmt.Errorf("map requires an even number of two or more arguments, got %d", len(args))
724 }
725
726 argTypes := make([]cty.Type, len(args)/2)
727 index := 0
728
729 for i := 0; i < len(args); i += 2 {
730 argTypes[index] = args[i+1].Type()
731 index++
732 }
733
734 valType, _ := convert.UnifyUnsafe(argTypes)
735 if valType == cty.NilType {
736 return cty.NilType, errors.New("all arguments must have the same type")
737 }
738
739 return cty.Map(valType), nil
740 },
741 Impl: func(args []cty.Value, retType cty.Type) (ret cty.Value, err error) {
742 for _, arg := range args {
743 if !arg.IsWhollyKnown() {
744 return cty.UnknownVal(retType), nil
745 }
746 }
747
748 outputMap := make(map[string]cty.Value)
749
750 for i := 0; i < len(args); i += 2 {
751
752 key := args[i].AsString()
753
754 err := gocty.FromCtyValue(args[i], &key)
755 if err != nil {
756 return cty.NilVal, err
757 }
758
759 val := args[i+1]
760
761 var variable cty.Value
762 err = gocty.FromCtyValue(val, &variable)
763 if err != nil {
764 return cty.NilVal, err
765 }
766
767 // We already know this will succeed because of the checks in our Type func above
768 variable, _ = convert.Convert(variable, retType.ElementType())
769
770 // Check for duplicate keys
771 if _, ok := outputMap[key]; ok {
772 return cty.NilVal, fmt.Errorf("argument %d is a duplicate key: %q", i+1, key)
773 }
774 outputMap[key] = variable
775 }
776
777 return cty.MapVal(outputMap), nil
778 },
779 })
780
781 // MatchkeysFunc constructs a function that constructs a new list by taking a
782 // subset of elements from one list whose indexes match the corresponding
783 // indexes of values in another list.
784 var MatchkeysFunc = function.New(&function.Spec{
785 Params: []function.Parameter{
786 {
787 Name: "values",
788 Type: cty.List(cty.DynamicPseudoType),
789 },
790 {
791 Name: "keys",
792 Type: cty.List(cty.DynamicPseudoType),
793 },
794 {
795 Name: "searchset",
796 Type: cty.List(cty.DynamicPseudoType),
797 },
798 },
799 Type: func(args []cty.Value) (cty.Type, error) {
800 if !args[1].Type().Equals(args[2].Type()) {
801 return cty.NilType, errors.New("lists must be of the same type")
802 }
803
804 return args[0].Type(), nil
805 },
806 Impl: func(args []cty.Value, retType cty.Type) (ret cty.Value, err error) {
807 if !args[0].IsKnown() {
808 return cty.UnknownVal(cty.List(retType.ElementType())), nil
809 }
810
811 if args[0].LengthInt() != args[1].LengthInt() {
812 return cty.ListValEmpty(retType.ElementType()), errors.New("length of keys and values should be equal")
813 }
814
815 output := make([]cty.Value, 0)
816
817 values := args[0]
818 keys := args[1]
819 searchset := args[2]
820
821 // if searchset is empty, return an empty list.
822 if searchset.LengthInt() == 0 {
823 return cty.ListValEmpty(retType.ElementType()), nil
824 }
825
826 if !values.IsWhollyKnown() || !keys.IsWhollyKnown() {
827 return cty.UnknownVal(retType), nil
828 }
829
830 i := 0
831 for it := keys.ElementIterator(); it.Next(); {
832 _, key := it.Element()
833 for iter := searchset.ElementIterator(); iter.Next(); {
834 _, search := iter.Element()
835 eq, err := stdlib.Equal(key, search)
836 if err != nil {
837 return cty.NilVal, err
838 }
839 if !eq.IsKnown() {
840 return cty.ListValEmpty(retType.ElementType()), nil
841 }
842 if eq.True() {
843 v := values.Index(cty.NumberIntVal(int64(i)))
844 output = append(output, v)
845 break
846 }
847 }
848 i++
849 }
850
851 // if we haven't matched any key, then output is an empty list.
852 if len(output) == 0 {
853 return cty.ListValEmpty(retType.ElementType()), nil
854 }
855 return cty.ListVal(output), nil
856 },
857 })
858
859 // MergeFunc constructs a function that takes an arbitrary number of maps and
860 // returns a single map that contains a merged set of elements from all of the maps.
861 //
862 // If more than one given map defines the same key then the one that is later in
863 // the argument sequence takes precedence.
864 var MergeFunc = function.New(&function.Spec{
865 Params: []function.Parameter{},
866 VarParam: &function.Parameter{
867 Name: "maps",
868 Type: cty.DynamicPseudoType,
869 AllowDynamicType: true,
870 AllowNull: true,
871 },
872 Type: function.StaticReturnType(cty.DynamicPseudoType),
873 Impl: func(args []cty.Value, retType cty.Type) (ret cty.Value, err error) {
874 outputMap := make(map[string]cty.Value)
875
876 for _, arg := range args {
877 if !arg.IsWhollyKnown() {
878 return cty.UnknownVal(retType), nil
879 }
880 if !arg.Type().IsObjectType() && !arg.Type().IsMapType() {
881 return cty.NilVal, fmt.Errorf("arguments must be maps or objects, got %#v", arg.Type().FriendlyName())
882 }
883 for it := arg.ElementIterator(); it.Next(); {
884 k, v := it.Element()
885 outputMap[k.AsString()] = v
886 }
887 }
888 return cty.ObjectVal(outputMap), nil
889 },
890 })
891
892 // ReverseFunc takes a sequence and produces a new sequence of the same length
893 // with all of the same elements as the given sequence but in reverse order.
894 var ReverseFunc = function.New(&function.Spec{
895 Params: []function.Parameter{
896 {
897 Name: "list",
898 Type: cty.DynamicPseudoType,
899 },
900 },
901 Type: func(args []cty.Value) (cty.Type, error) {
902 argTy := args[0].Type()
903 switch {
904 case argTy.IsTupleType():
905 argTys := argTy.TupleElementTypes()
906 retTys := make([]cty.Type, len(argTys))
907 for i, ty := range argTys {
908 retTys[len(retTys)-i-1] = ty
909 }
910 return cty.Tuple(retTys), nil
911 case argTy.IsListType(), argTy.IsSetType(): // We accept sets here to mimic the usual behavior of auto-converting to list
912 return cty.List(argTy.ElementType()), nil
913 default:
914 return cty.NilType, function.NewArgErrorf(0, "can only reverse list or tuple values, not %s", argTy.FriendlyName())
915 }
916 },
917 Impl: func(args []cty.Value, retType cty.Type) (ret cty.Value, err error) {
918 in := args[0].AsValueSlice()
919 outVals := make([]cty.Value, len(in))
920 for i, v := range in {
921 outVals[len(outVals)-i-1] = v
922 }
923 switch {
924 case retType.IsTupleType():
925 return cty.TupleVal(outVals), nil
926 default:
927 if len(outVals) == 0 {
928 return cty.ListValEmpty(retType.ElementType()), nil
929 }
930 return cty.ListVal(outVals), nil
931 }
932 },
933 })
934
935 // SetProductFunc calculates the cartesian product of two or more sets or
936 // sequences. If the arguments are all lists then the result is a list of tuples,
937 // preserving the ordering of all of the input lists. Otherwise the result is a
938 // set of tuples.
939 var SetProductFunc = function.New(&function.Spec{
940 Params: []function.Parameter{},
941 VarParam: &function.Parameter{
942 Name: "sets",
943 Type: cty.DynamicPseudoType,
944 },
945 Type: func(args []cty.Value) (retType cty.Type, err error) {
946 if len(args) < 2 {
947 return cty.NilType, errors.New("at least two arguments are required")
948 }
949
950 listCount := 0
951 elemTys := make([]cty.Type, len(args))
952 for i, arg := range args {
953 aty := arg.Type()
954 switch {
955 case aty.IsSetType():
956 elemTys[i] = aty.ElementType()
957 case aty.IsListType():
958 elemTys[i] = aty.ElementType()
959 listCount++
960 case aty.IsTupleType():
961 // We can accept a tuple type only if there's some common type
962 // that all of its elements can be converted to.
963 allEtys := aty.TupleElementTypes()
964 if len(allEtys) == 0 {
965 elemTys[i] = cty.DynamicPseudoType
966 listCount++
967 break
968 }
969 ety, _ := convert.UnifyUnsafe(allEtys)
970 if ety == cty.NilType {
971 return cty.NilType, function.NewArgErrorf(i, "all elements must be of the same type")
972 }
973 elemTys[i] = ety
974 listCount++
975 default:
976 return cty.NilType, function.NewArgErrorf(i, "a set or a list is required")
977 }
978 }
979
980 if listCount == len(args) {
981 return cty.List(cty.Tuple(elemTys)), nil
982 }
983 return cty.Set(cty.Tuple(elemTys)), nil
984 },
985 Impl: func(args []cty.Value, retType cty.Type) (ret cty.Value, err error) {
986 ety := retType.ElementType()
987
988 total := 1
989 for _, arg := range args {
990 // Because of our type checking function, we are guaranteed that
991 // all of the arguments are known, non-null values of types that
992 // support LengthInt.
993 total *= arg.LengthInt()
994 }
995
996 if total == 0 {
997 // If any of the arguments was an empty collection then our result
998 // is also an empty collection, which we'll short-circuit here.
999 if retType.IsListType() {
1000 return cty.ListValEmpty(ety), nil
1001 }
1002 return cty.SetValEmpty(ety), nil
1003 }
1004
1005 subEtys := ety.TupleElementTypes()
1006 product := make([][]cty.Value, total)
1007
1008 b := make([]cty.Value, total*len(args))
1009 n := make([]int, len(args))
1010 s := 0
1011 argVals := make([][]cty.Value, len(args))
1012 for i, arg := range args {
1013 argVals[i] = arg.AsValueSlice()
1014 }
1015
1016 for i := range product {
1017 e := s + len(args)
1018 pi := b[s:e]
1019 product[i] = pi
1020 s = e
1021
1022 for j, n := range n {
1023 val := argVals[j][n]
1024 ty := subEtys[j]
1025 if !val.Type().Equals(ty) {
1026 var err error
1027 val, err = convert.Convert(val, ty)
1028 if err != nil {
1029 // Should never happen since we checked this in our
1030 // type-checking function.
1031 return cty.NilVal, fmt.Errorf("failed to convert argVals[%d][%d] to %s; this is a bug in Terraform", j, n, ty.FriendlyName())
1032 }
1033 }
1034 pi[j] = val
1035 }
1036
1037 for j := len(n) - 1; j >= 0; j-- {
1038 n[j]++
1039 if n[j] < len(argVals[j]) {
1040 break
1041 }
1042 n[j] = 0
1043 }
1044 }
1045
1046 productVals := make([]cty.Value, total)
1047 for i, vals := range product {
1048 productVals[i] = cty.TupleVal(vals)
1049 }
1050
1051 if retType.IsListType() {
1052 return cty.ListVal(productVals), nil
1053 }
1054 return cty.SetVal(productVals), nil
1055 },
1056 })
1057
1058 // SliceFunc constructs a function that extracts some consecutive elements
1059 // from within a list.
1060 var SliceFunc = function.New(&function.Spec{
1061 Params: []function.Parameter{
1062 {
1063 Name: "list",
1064 Type: cty.DynamicPseudoType,
1065 },
1066 {
1067 Name: "start_index",
1068 Type: cty.Number,
1069 },
1070 {
1071 Name: "end_index",
1072 Type: cty.Number,
1073 },
1074 },
1075 Type: func(args []cty.Value) (cty.Type, error) {
1076 arg := args[0]
1077 argTy := arg.Type()
1078
1079 if argTy.IsSetType() {
1080 return cty.NilType, function.NewArgErrorf(0, "cannot slice a set, because its elements do not have indices; use the tolist function to force conversion to list if the ordering of the result is not important")
1081 }
1082 if !argTy.IsListType() && !argTy.IsTupleType() {
1083 return cty.NilType, function.NewArgErrorf(0, "must be a list or tuple value")
1084 }
1085
1086 startIndex, endIndex, idxsKnown, err := sliceIndexes(args)
1087 if err != nil {
1088 return cty.NilType, err
1089 }
1090
1091 if argTy.IsListType() {
1092 return argTy, nil
1093 }
1094
1095 if !idxsKnown {
1096 // If we don't know our start/end indices then we can't predict
1097 // the result type if we're planning to return a tuple.
1098 return cty.DynamicPseudoType, nil
1099 }
1100 return cty.Tuple(argTy.TupleElementTypes()[startIndex:endIndex]), nil
1101 },
1102 Impl: func(args []cty.Value, retType cty.Type) (ret cty.Value, err error) {
1103 inputList := args[0]
1104
1105 if retType == cty.DynamicPseudoType {
1106 return cty.DynamicVal, nil
1107 }
1108
1109 // we ignore idxsKnown return value here because the indices are always
1110 // known here, or else the call would've short-circuited.
1111 startIndex, endIndex, _, err := sliceIndexes(args)
1112 if err != nil {
1113 return cty.NilVal, err
1114 }
1115
1116 if endIndex-startIndex == 0 {
1117 if retType.IsTupleType() {
1118 return cty.EmptyTupleVal, nil
1119 }
1120 return cty.ListValEmpty(retType.ElementType()), nil
1121 }
1122
1123 outputList := inputList.AsValueSlice()[startIndex:endIndex]
1124
1125 if retType.IsTupleType() {
1126 return cty.TupleVal(outputList), nil
1127 }
1128
1129 return cty.ListVal(outputList), nil
1130 },
1131 })
1132
1133 func sliceIndexes(args []cty.Value) (int, int, bool, error) {
1134 var startIndex, endIndex, length int
1135 var startKnown, endKnown, lengthKnown bool
1136
1137 if args[0].Type().IsTupleType() || args[0].IsKnown() { // if it's a tuple then we always know the length by the type, but lists must be known
1138 length = args[0].LengthInt()
1139 lengthKnown = true
1140 }
1141
1142 if args[1].IsKnown() {
1143 if err := gocty.FromCtyValue(args[1], &startIndex); err != nil {
1144 return 0, 0, false, function.NewArgErrorf(1, "invalid start index: %s", err)
1145 }
1146 if startIndex < 0 {
1147 return 0, 0, false, function.NewArgErrorf(1, "start index must not be less than zero")
1148 }
1149 if lengthKnown && startIndex > length {
1150 return 0, 0, false, function.NewArgErrorf(1, "start index must not be greater than the length of the list")
1151 }
1152 startKnown = true
1153 }
1154 if args[2].IsKnown() {
1155 if err := gocty.FromCtyValue(args[2], &endIndex); err != nil {
1156 return 0, 0, false, function.NewArgErrorf(2, "invalid end index: %s", err)
1157 }
1158 if endIndex < 0 {
1159 return 0, 0, false, function.NewArgErrorf(2, "end index must not be less than zero")
1160 }
1161 if lengthKnown && endIndex > length {
1162 return 0, 0, false, function.NewArgErrorf(2, "end index must not be greater than the length of the list")
1163 }
1164 endKnown = true
1165 }
1166 if startKnown && endKnown {
1167 if startIndex > endIndex {
1168 return 0, 0, false, function.NewArgErrorf(1, "start index must not be greater than end index")
1169 }
1170 }
1171 return startIndex, endIndex, startKnown && endKnown, nil
1172 }
1173
1174 // TransposeFunc contructs a function that takes a map of lists of strings and
1175 // TransposeFunc constructs a function that takes a map of lists of strings and
1176 // swaps the keys and values to produce a new map of lists of strings.
1177 var TransposeFunc = function.New(&function.Spec{
1178 Params: []function.Parameter{
1179 {
1180 Name: "values",
1181 Type: cty.Map(cty.List(cty.String)),
1182 },
1183 },
1184 Type: function.StaticReturnType(cty.Map(cty.List(cty.String))),
1185 Impl: func(args []cty.Value, retType cty.Type) (ret cty.Value, err error) {
1186 inputMap := args[0]
1187 if !inputMap.IsWhollyKnown() {
1188 return cty.UnknownVal(retType), nil
1189 }
1190
1191 outputMap := make(map[string]cty.Value)
1192 tmpMap := make(map[string][]string)
1193
1194 for it := inputMap.ElementIterator(); it.Next(); {
1195 inKey, inVal := it.Element()
1196 for iter := inVal.ElementIterator(); iter.Next(); {
1197 _, val := iter.Element()
1198 if !val.Type().Equals(cty.String) {
1199 return cty.MapValEmpty(cty.List(cty.String)), errors.New("input must be a map of lists of strings")
1200 }
1201
1202 outKey := val.AsString()
1203 if _, ok := tmpMap[outKey]; !ok {
1204 tmpMap[outKey] = make([]string, 0)
1205 }
1206 outVal := tmpMap[outKey]
1207 outVal = append(outVal, inKey.AsString())
1208 sort.Strings(outVal)
1209 tmpMap[outKey] = outVal
1210 }
1211 }
1212
1213 for outKey, outVal := range tmpMap {
1214 values := make([]cty.Value, 0)
1215 for _, v := range outVal {
1216 values = append(values, cty.StringVal(v))
1217 }
1218 outputMap[outKey] = cty.ListVal(values)
1219 }
1220
1221 return cty.MapVal(outputMap), nil
1222 },
1223 })
1224
1225 // ValuesFunc constructs a function that returns a list of the map values,
1226 // in the order of the sorted keys.
1227 var ValuesFunc = function.New(&function.Spec{
1228 Params: []function.Parameter{
1229 {
1230 Name: "values",
1231 Type: cty.DynamicPseudoType,
1232 },
1233 },
1234 Type: func(args []cty.Value) (ret cty.Type, err error) {
1235 ty := args[0].Type()
1236 if ty.IsMapType() {
1237 return cty.List(ty.ElementType()), nil
1238 } else if ty.IsObjectType() {
1239 // The result is a tuple type with all of the same types as our
1240 // object type's attributes, sorted in lexicographical order by the
1241 // keys. (This matches the sort order guaranteed by ElementIterator
1242 // on a cty object value.)
1243 atys := ty.AttributeTypes()
1244 if len(atys) == 0 {
1245 return cty.EmptyTuple, nil
1246 }
1247 attrNames := make([]string, 0, len(atys))
1248 for name := range atys {
1249 attrNames = append(attrNames, name)
1250 }
1251 sort.Strings(attrNames)
1252
1253 tys := make([]cty.Type, len(attrNames))
1254 for i, name := range attrNames {
1255 tys[i] = atys[name]
1256 }
1257 return cty.Tuple(tys), nil
1258 }
1259 return cty.NilType, errors.New("values() requires a map as the first argument")
1260 },
1261 Impl: func(args []cty.Value, retType cty.Type) (ret cty.Value, err error) {
1262 mapVar := args[0]
1263
1264 // We can just iterate the map/object value here because cty guarantees
1265 // that these types always iterate in key lexicographical order.
1266 var values []cty.Value
1267 for it := mapVar.ElementIterator(); it.Next(); {
1268 _, val := it.Element()
1269 values = append(values, val)
1270 }
1271
1272 if retType.IsTupleType() {
1273 return cty.TupleVal(values), nil
1274 }
1275 if len(values) == 0 {
1276 return cty.ListValEmpty(retType.ElementType()), nil
1277 }
1278 return cty.ListVal(values), nil
1279 },
1280 })
1281
1282 // ZipmapFunc constructs a function that constructs a map from a list of keys
1283 // and a corresponding list of values.
1284 var ZipmapFunc = function.New(&function.Spec{
1285 Params: []function.Parameter{
1286 {
1287 Name: "keys",
1288 Type: cty.List(cty.String),
1289 },
1290 {
1291 Name: "values",
1292 Type: cty.DynamicPseudoType,
1293 },
1294 },
1295 Type: func(args []cty.Value) (ret cty.Type, err error) {
1296 keys := args[0]
1297 values := args[1]
1298 valuesTy := values.Type()
1299
1300 switch {
1301 case valuesTy.IsListType():
1302 return cty.Map(values.Type().ElementType()), nil
1303 case valuesTy.IsTupleType():
1304 if !keys.IsWhollyKnown() {
1305 // Since zipmap with a tuple produces an object, we need to know
1306 // all of the key names before we can predict our result type.
1307 return cty.DynamicPseudoType, nil
1308 }
1309
1310 keysRaw := keys.AsValueSlice()
1311 valueTypesRaw := valuesTy.TupleElementTypes()
1312 if len(keysRaw) != len(valueTypesRaw) {
1313 return cty.NilType, fmt.Errorf("number of keys (%d) does not match number of values (%d)", len(keysRaw), len(valueTypesRaw))
1314 }
1315 atys := make(map[string]cty.Type, len(valueTypesRaw))
1316 for i, keyVal := range keysRaw {
1317 if keyVal.IsNull() {
1318 return cty.NilType, fmt.Errorf("keys list has null value at index %d", i)
1319 }
1320 key := keyVal.AsString()
1321 atys[key] = valueTypesRaw[i]
1322 }
1323 return cty.Object(atys), nil
1324
1325 default:
1326 return cty.NilType, errors.New("values argument must be a list or tuple value")
1327 }
1328 },
1329 Impl: func(args []cty.Value, retType cty.Type) (ret cty.Value, err error) {
1330 keys := args[0]
1331 values := args[1]
1332
1333 if !keys.IsWhollyKnown() {
1334 // Unknown map keys and object attributes are not supported, so
1335 // our entire result must be unknown in this case.
1336 return cty.UnknownVal(retType), nil
1337 }
1338
1339 // both keys and values are guaranteed to be shallowly-known here,
1340 // because our declared params above don't allow unknown or null values.
1341 if keys.LengthInt() != values.LengthInt() {
1342 return cty.NilVal, fmt.Errorf("number of keys (%d) does not match number of values (%d)", keys.LengthInt(), values.LengthInt())
1343 }
1344
1345 output := make(map[string]cty.Value)
1346
1347 i := 0
1348 for it := keys.ElementIterator(); it.Next(); {
1349 _, v := it.Element()
1350 val := values.Index(cty.NumberIntVal(int64(i)))
1351 output[v.AsString()] = val
1352 i++
1353 }
1354
1355 switch {
1356 case retType.IsMapType():
1357 if len(output) == 0 {
1358 return cty.MapValEmpty(retType.ElementType()), nil
1359 }
1360 return cty.MapVal(output), nil
1361 case retType.IsObjectType():
1362 return cty.ObjectVal(output), nil
1363 default:
1364 // Should never happen because the type-check function should've
1365 // caught any other case.
1366 return cty.NilVal, fmt.Errorf("internally selected incorrect result type %s (this is a bug)", retType.FriendlyName())
1367 }
1368 },
1369 })
1370
1371 // helper function to add an element to a list, if it does not already exist
1372 func appendIfMissing(slice []cty.Value, element cty.Value) ([]cty.Value, error) {
1373 for _, ele := range slice {
1374 eq, err := stdlib.Equal(ele, element)
1375 if err != nil {
1376 return slice, err
1377 }
1378 if eq.True() {
1379 return slice, nil
1380 }
1381 }
1382 return append(slice, element), nil
1383 }
1384
1385 // Element returns a single element from a given list at the given index. If
1386 // index is greater than the length of the list then it is wrapped modulo
1387 // the list length.
1388 func Element(list, index cty.Value) (cty.Value, error) {
1389 return ElementFunc.Call([]cty.Value{list, index})
1390 }
1391
1392 // Length returns the number of elements in the given collection or number of
1393 // Unicode characters in the given string.
1394 func Length(collection cty.Value) (cty.Value, error) {
1395 return LengthFunc.Call([]cty.Value{collection})
1396 }
1397
1398 // Coalesce takes any number of arguments and returns the first one that isn't empty.
1399 func Coalesce(args ...cty.Value) (cty.Value, error) {
1400 return CoalesceFunc.Call(args)
1401 }
1402
1403 // CoalesceList takes any number of list arguments and returns the first one that isn't empty.
1404 func CoalesceList(args ...cty.Value) (cty.Value, error) {
1405 return CoalesceListFunc.Call(args)
1406 }
1407
1408 // Compact takes a list of strings and returns a new list
1409 // with any empty string elements removed.
1410 func Compact(list cty.Value) (cty.Value, error) {
1411 return CompactFunc.Call([]cty.Value{list})
1412 }
1413
1414 // Contains determines whether a given list contains a given single value
1415 // as one of its elements.
1416 func Contains(list, value cty.Value) (cty.Value, error) {
1417 return ContainsFunc.Call([]cty.Value{list, value})
1418 }
1419
1420 // Index finds the element index for a given value in a list.
1421 func Index(list, value cty.Value) (cty.Value, error) {
1422 return IndexFunc.Call([]cty.Value{list, value})
1423 }
1424
1425 // Distinct takes a list and returns a new list with any duplicate elements removed.
1426 func Distinct(list cty.Value) (cty.Value, error) {
1427 return DistinctFunc.Call([]cty.Value{list})
1428 }
1429
1430 // Chunklist splits a single list into fixed-size chunks, returning a list of lists.
1431 func Chunklist(list, size cty.Value) (cty.Value, error) {
1432 return ChunklistFunc.Call([]cty.Value{list, size})
1433 }
1434
1435 // Flatten takes a list and replaces any elements that are lists with a flattened
1436 // sequence of the list contents.
1437 func Flatten(list cty.Value) (cty.Value, error) {
1438 return FlattenFunc.Call([]cty.Value{list})
1439 }
1440
1441 // Keys takes a map and returns a sorted list of the map keys.
1442 func Keys(inputMap cty.Value) (cty.Value, error) {
1443 return KeysFunc.Call([]cty.Value{inputMap})
1444 }
1445
1446 // List takes any number of list arguments and returns a list containing those
1447 // values in the same order.
1448 func List(args ...cty.Value) (cty.Value, error) {
1449 return ListFunc.Call(args)
1450 }
1451
1452 // Lookup performs a dynamic lookup into a map.
1453 // There are two required arguments, map and key, plus an optional default,
1454 // which is a value to return if no key is found in map.
1455 func Lookup(args ...cty.Value) (cty.Value, error) {
1456 return LookupFunc.Call(args)
1457 }
1458
1459 // Map takes an even number of arguments and returns a map whose elements are constructed
1460 // from consecutive pairs of arguments.
1461 func Map(args ...cty.Value) (cty.Value, error) {
1462 return MapFunc.Call(args)
1463 }
1464
1465 // Matchkeys constructs a new list by taking a subset of elements from one list
1466 // whose indexes match the corresponding indexes of values in another list.
1467 func Matchkeys(values, keys, searchset cty.Value) (cty.Value, error) {
1468 return MatchkeysFunc.Call([]cty.Value{values, keys, searchset})
1469 }
1470
1471 // Merge takes an arbitrary number of maps and returns a single map that contains
1472 // a merged set of elements from all of the maps.
1473 //
1474 // If more than one given map defines the same key then the one that is later in
1475 // the argument sequence takes precedence.
1476 func Merge(maps ...cty.Value) (cty.Value, error) {
1477 return MergeFunc.Call(maps)
1478 }
1479
1480 // Reverse takes a sequence and produces a new sequence of the same length
1481 // with all of the same elements as the given sequence but in reverse order.
1482 func Reverse(list cty.Value) (cty.Value, error) {
1483 return ReverseFunc.Call([]cty.Value{list})
1484 }
1485
1486 // SetProduct computes the cartesian product of sets or sequences.
1487 func SetProduct(sets ...cty.Value) (cty.Value, error) {
1488 return SetProductFunc.Call(sets)
1489 }
1490
1491 // Slice extracts some consecutive elements from within a list.
1492 func Slice(list, start, end cty.Value) (cty.Value, error) {
1493 return SliceFunc.Call([]cty.Value{list, start, end})
1494 }
1495
1496 // Transpose takes a map of lists of strings and swaps the keys and values to
1497 // produce a new map of lists of strings.
1498 func Transpose(values cty.Value) (cty.Value, error) {
1499 return TransposeFunc.Call([]cty.Value{values})
1500 }
1501
1502 // Values returns a list of the map values, in the order of the sorted keys.
1503 // This function only works on flat maps.
1504 func Values(values cty.Value) (cty.Value, error) {
1505 return ValuesFunc.Call([]cty.Value{values})
1506 }
1507
1508 // Zipmap constructs a map from a list of keys and a corresponding list of values.
1509 func Zipmap(keys, values cty.Value) (cty.Value, error) {
1510 return ZipmapFunc.Call([]cty.Value{keys, values})
1511 }