]> git.immae.eu Git - github/fretlink/terraform-provider-statuscake.git/blob - vendor/github.com/hashicorp/terraform/lang/funcs/collection.go
update vendor and go.mod
[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.IsNull() || 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 if len(list) == 0 {
367 return cty.ListValEmpty(retType.ElementType()), nil
368 }
369 return cty.ListVal(list), nil
370 },
371 })
372
373 // ChunklistFunc constructs a function that splits a single list into fixed-size chunks,
374 // returning a list of lists.
375 var ChunklistFunc = function.New(&function.Spec{
376 Params: []function.Parameter{
377 {
378 Name: "list",
379 Type: cty.List(cty.DynamicPseudoType),
380 },
381 {
382 Name: "size",
383 Type: cty.Number,
384 },
385 },
386 Type: func(args []cty.Value) (cty.Type, error) {
387 return cty.List(args[0].Type()), nil
388 },
389 Impl: func(args []cty.Value, retType cty.Type) (ret cty.Value, err error) {
390 listVal := args[0]
391 if !listVal.IsKnown() {
392 return cty.UnknownVal(retType), nil
393 }
394
395 if listVal.LengthInt() == 0 {
396 return cty.ListValEmpty(listVal.Type()), nil
397 }
398
399 var size int
400 err = gocty.FromCtyValue(args[1], &size)
401 if err != nil {
402 return cty.NilVal, fmt.Errorf("invalid index: %s", err)
403 }
404
405 if size < 0 {
406 return cty.NilVal, errors.New("the size argument must be positive")
407 }
408
409 output := make([]cty.Value, 0)
410
411 // if size is 0, returns a list made of the initial list
412 if size == 0 {
413 output = append(output, listVal)
414 return cty.ListVal(output), nil
415 }
416
417 chunk := make([]cty.Value, 0)
418
419 l := args[0].LengthInt()
420 i := 0
421
422 for it := listVal.ElementIterator(); it.Next(); {
423 _, v := it.Element()
424 chunk = append(chunk, v)
425
426 // Chunk when index isn't 0, or when reaching the values's length
427 if (i+1)%size == 0 || (i+1) == l {
428 output = append(output, cty.ListVal(chunk))
429 chunk = make([]cty.Value, 0)
430 }
431 i++
432 }
433
434 return cty.ListVal(output), nil
435 },
436 })
437
438 // FlattenFunc constructs a function that takes a list and replaces any elements
439 // that are lists with a flattened sequence of the list contents.
440 var FlattenFunc = function.New(&function.Spec{
441 Params: []function.Parameter{
442 {
443 Name: "list",
444 Type: cty.DynamicPseudoType,
445 },
446 },
447 Type: func(args []cty.Value) (cty.Type, error) {
448 if !args[0].IsWhollyKnown() {
449 return cty.DynamicPseudoType, nil
450 }
451
452 argTy := args[0].Type()
453 if !argTy.IsListType() && !argTy.IsSetType() && !argTy.IsTupleType() {
454 return cty.NilType, errors.New("can only flatten lists, sets and tuples")
455 }
456
457 retVal, known := flattener(args[0])
458 if !known {
459 return cty.DynamicPseudoType, nil
460 }
461
462 tys := make([]cty.Type, len(retVal))
463 for i, ty := range retVal {
464 tys[i] = ty.Type()
465 }
466 return cty.Tuple(tys), nil
467 },
468 Impl: func(args []cty.Value, retType cty.Type) (ret cty.Value, err error) {
469 inputList := args[0]
470 if inputList.LengthInt() == 0 {
471 return cty.EmptyTupleVal, nil
472 }
473
474 out, known := flattener(inputList)
475 if !known {
476 return cty.UnknownVal(retType), nil
477 }
478
479 return cty.TupleVal(out), nil
480 },
481 })
482
483 // Flatten until it's not a cty.List, and return whether the value is known.
484 // We can flatten lists with unknown values, as long as they are not
485 // lists themselves.
486 func flattener(flattenList cty.Value) ([]cty.Value, bool) {
487 out := make([]cty.Value, 0)
488 for it := flattenList.ElementIterator(); it.Next(); {
489 _, val := it.Element()
490 if val.Type().IsListType() || val.Type().IsSetType() || val.Type().IsTupleType() {
491 if !val.IsKnown() {
492 return out, false
493 }
494
495 res, known := flattener(val)
496 if !known {
497 return res, known
498 }
499 out = append(out, res...)
500 } else {
501 out = append(out, val)
502 }
503 }
504 return out, true
505 }
506
507 // KeysFunc constructs a function that takes a map and returns a sorted list of the map keys.
508 var KeysFunc = function.New(&function.Spec{
509 Params: []function.Parameter{
510 {
511 Name: "inputMap",
512 Type: cty.DynamicPseudoType,
513 AllowUnknown: true,
514 },
515 },
516 Type: func(args []cty.Value) (cty.Type, error) {
517 ty := args[0].Type()
518 switch {
519 case ty.IsMapType():
520 return cty.List(cty.String), nil
521 case ty.IsObjectType():
522 atys := ty.AttributeTypes()
523 if len(atys) == 0 {
524 return cty.EmptyTuple, nil
525 }
526 // All of our result elements will be strings, and atys just
527 // decides how many there are.
528 etys := make([]cty.Type, len(atys))
529 for i := range etys {
530 etys[i] = cty.String
531 }
532 return cty.Tuple(etys), nil
533 default:
534 return cty.DynamicPseudoType, function.NewArgErrorf(0, "must have map or object type")
535 }
536 },
537 Impl: func(args []cty.Value, retType cty.Type) (cty.Value, error) {
538 m := args[0]
539 var keys []cty.Value
540
541 switch {
542 case m.Type().IsObjectType():
543 // In this case we allow unknown values so we must work only with
544 // the attribute _types_, not with the value itself.
545 var names []string
546 for name := range m.Type().AttributeTypes() {
547 names = append(names, name)
548 }
549 sort.Strings(names) // same ordering guaranteed by cty's ElementIterator
550 if len(names) == 0 {
551 return cty.EmptyTupleVal, nil
552 }
553 keys = make([]cty.Value, len(names))
554 for i, name := range names {
555 keys[i] = cty.StringVal(name)
556 }
557 return cty.TupleVal(keys), nil
558 default:
559 if !m.IsKnown() {
560 return cty.UnknownVal(retType), nil
561 }
562
563 // cty guarantees that ElementIterator will iterate in lexicographical
564 // order by key.
565 for it := args[0].ElementIterator(); it.Next(); {
566 k, _ := it.Element()
567 keys = append(keys, k)
568 }
569 if len(keys) == 0 {
570 return cty.ListValEmpty(cty.String), nil
571 }
572 return cty.ListVal(keys), nil
573 }
574 },
575 })
576
577 // ListFunc constructs a function that takes an arbitrary number of arguments
578 // and returns a list containing those values in the same order.
579 //
580 // This function is deprecated in Terraform v0.12
581 var ListFunc = function.New(&function.Spec{
582 Params: []function.Parameter{},
583 VarParam: &function.Parameter{
584 Name: "vals",
585 Type: cty.DynamicPseudoType,
586 AllowUnknown: true,
587 AllowDynamicType: true,
588 AllowNull: true,
589 },
590 Type: func(args []cty.Value) (ret cty.Type, err error) {
591 if len(args) == 0 {
592 return cty.NilType, errors.New("at least one argument is required")
593 }
594
595 argTypes := make([]cty.Type, len(args))
596
597 for i, arg := range args {
598 argTypes[i] = arg.Type()
599 }
600
601 retType, _ := convert.UnifyUnsafe(argTypes)
602 if retType == cty.NilType {
603 return cty.NilType, errors.New("all arguments must have the same type")
604 }
605
606 return cty.List(retType), nil
607 },
608 Impl: func(args []cty.Value, retType cty.Type) (ret cty.Value, err error) {
609 newList := make([]cty.Value, 0, len(args))
610
611 for _, arg := range args {
612 // We already know this will succeed because of the checks in our Type func above
613 arg, _ = convert.Convert(arg, retType.ElementType())
614 newList = append(newList, arg)
615 }
616
617 return cty.ListVal(newList), nil
618 },
619 })
620
621 // LookupFunc constructs a function that performs dynamic lookups of map types.
622 var LookupFunc = function.New(&function.Spec{
623 Params: []function.Parameter{
624 {
625 Name: "inputMap",
626 Type: cty.DynamicPseudoType,
627 },
628 {
629 Name: "key",
630 Type: cty.String,
631 },
632 },
633 VarParam: &function.Parameter{
634 Name: "default",
635 Type: cty.DynamicPseudoType,
636 AllowUnknown: true,
637 AllowDynamicType: true,
638 AllowNull: true,
639 },
640 Type: func(args []cty.Value) (ret cty.Type, err error) {
641 if len(args) < 1 || len(args) > 3 {
642 return cty.NilType, fmt.Errorf("lookup() takes two or three arguments, got %d", len(args))
643 }
644
645 ty := args[0].Type()
646
647 switch {
648 case ty.IsObjectType():
649 if !args[1].IsKnown() {
650 return cty.DynamicPseudoType, nil
651 }
652
653 key := args[1].AsString()
654 if ty.HasAttribute(key) {
655 return args[0].GetAttr(key).Type(), nil
656 } else if len(args) == 3 {
657 // if the key isn't found but a default is provided,
658 // return the default type
659 return args[2].Type(), nil
660 }
661 return cty.DynamicPseudoType, function.NewArgErrorf(0, "the given object has no attribute %q", key)
662 case ty.IsMapType():
663 return ty.ElementType(), nil
664 default:
665 return cty.NilType, function.NewArgErrorf(0, "lookup() requires a map as the first argument")
666 }
667 },
668 Impl: func(args []cty.Value, retType cty.Type) (ret cty.Value, err error) {
669 var defaultVal cty.Value
670 defaultValueSet := false
671
672 if len(args) == 3 {
673 defaultVal = args[2]
674 defaultValueSet = true
675 }
676
677 mapVar := args[0]
678 lookupKey := args[1].AsString()
679
680 if !mapVar.IsWhollyKnown() {
681 return cty.UnknownVal(retType), nil
682 }
683
684 if mapVar.Type().IsObjectType() {
685 if mapVar.Type().HasAttribute(lookupKey) {
686 return mapVar.GetAttr(lookupKey), nil
687 }
688 } else if mapVar.HasIndex(cty.StringVal(lookupKey)) == cty.True {
689 v := mapVar.Index(cty.StringVal(lookupKey))
690 if ty := v.Type(); !ty.Equals(cty.NilType) {
691 switch {
692 case ty.Equals(cty.String):
693 return cty.StringVal(v.AsString()), nil
694 case ty.Equals(cty.Number):
695 return cty.NumberVal(v.AsBigFloat()), nil
696 case ty.Equals(cty.Bool):
697 return cty.BoolVal(v.True()), nil
698 default:
699 return cty.NilVal, errors.New("lookup() can only be used with maps of primitive types")
700 }
701 }
702 }
703
704 if defaultValueSet {
705 defaultVal, err = convert.Convert(defaultVal, retType)
706 if err != nil {
707 return cty.NilVal, err
708 }
709 return defaultVal, nil
710 }
711
712 return cty.UnknownVal(cty.DynamicPseudoType), fmt.Errorf(
713 "lookup failed to find '%s'", lookupKey)
714 },
715 })
716
717 // MapFunc constructs a function that takes an even number of arguments and
718 // returns a map whose elements are constructed from consecutive pairs of arguments.
719 //
720 // This function is deprecated in Terraform v0.12
721 var MapFunc = function.New(&function.Spec{
722 Params: []function.Parameter{},
723 VarParam: &function.Parameter{
724 Name: "vals",
725 Type: cty.DynamicPseudoType,
726 AllowUnknown: true,
727 AllowDynamicType: true,
728 AllowNull: true,
729 },
730 Type: func(args []cty.Value) (ret cty.Type, err error) {
731 if len(args) < 2 || len(args)%2 != 0 {
732 return cty.NilType, fmt.Errorf("map requires an even number of two or more arguments, got %d", len(args))
733 }
734
735 argTypes := make([]cty.Type, len(args)/2)
736 index := 0
737
738 for i := 0; i < len(args); i += 2 {
739 argTypes[index] = args[i+1].Type()
740 index++
741 }
742
743 valType, _ := convert.UnifyUnsafe(argTypes)
744 if valType == cty.NilType {
745 return cty.NilType, errors.New("all arguments must have the same type")
746 }
747
748 return cty.Map(valType), nil
749 },
750 Impl: func(args []cty.Value, retType cty.Type) (ret cty.Value, err error) {
751 for _, arg := range args {
752 if !arg.IsWhollyKnown() {
753 return cty.UnknownVal(retType), nil
754 }
755 }
756
757 outputMap := make(map[string]cty.Value)
758
759 for i := 0; i < len(args); i += 2 {
760
761 key := args[i].AsString()
762
763 err := gocty.FromCtyValue(args[i], &key)
764 if err != nil {
765 return cty.NilVal, err
766 }
767
768 val := args[i+1]
769
770 var variable cty.Value
771 err = gocty.FromCtyValue(val, &variable)
772 if err != nil {
773 return cty.NilVal, err
774 }
775
776 // We already know this will succeed because of the checks in our Type func above
777 variable, _ = convert.Convert(variable, retType.ElementType())
778
779 // Check for duplicate keys
780 if _, ok := outputMap[key]; ok {
781 return cty.NilVal, fmt.Errorf("argument %d is a duplicate key: %q", i+1, key)
782 }
783 outputMap[key] = variable
784 }
785
786 return cty.MapVal(outputMap), nil
787 },
788 })
789
790 // MatchkeysFunc constructs a function that constructs a new list by taking a
791 // subset of elements from one list whose indexes match the corresponding
792 // indexes of values in another list.
793 var MatchkeysFunc = function.New(&function.Spec{
794 Params: []function.Parameter{
795 {
796 Name: "values",
797 Type: cty.List(cty.DynamicPseudoType),
798 },
799 {
800 Name: "keys",
801 Type: cty.List(cty.DynamicPseudoType),
802 },
803 {
804 Name: "searchset",
805 Type: cty.List(cty.DynamicPseudoType),
806 },
807 },
808 Type: func(args []cty.Value) (cty.Type, error) {
809 ty, _ := convert.UnifyUnsafe([]cty.Type{args[1].Type(), args[2].Type()})
810 if ty == cty.NilType {
811 return cty.NilType, errors.New("keys and searchset must be of the same type")
812 }
813
814 // the return type is based on args[0] (values)
815 return args[0].Type(), nil
816 },
817 Impl: func(args []cty.Value, retType cty.Type) (ret cty.Value, err error) {
818 if !args[0].IsKnown() {
819 return cty.UnknownVal(cty.List(retType.ElementType())), nil
820 }
821
822 if args[0].LengthInt() != args[1].LengthInt() {
823 return cty.ListValEmpty(retType.ElementType()), errors.New("length of keys and values should be equal")
824 }
825
826 output := make([]cty.Value, 0)
827 values := args[0]
828
829 // Keys and searchset must be the same type.
830 // We can skip error checking here because we've already verified that
831 // they can be unified in the Type function
832 ty, _ := convert.UnifyUnsafe([]cty.Type{args[1].Type(), args[2].Type()})
833 keys, _ := convert.Convert(args[1], ty)
834 searchset, _ := convert.Convert(args[2], ty)
835
836 // if searchset is empty, return an empty list.
837 if searchset.LengthInt() == 0 {
838 return cty.ListValEmpty(retType.ElementType()), nil
839 }
840
841 if !values.IsWhollyKnown() || !keys.IsWhollyKnown() {
842 return cty.UnknownVal(retType), nil
843 }
844
845 i := 0
846 for it := keys.ElementIterator(); it.Next(); {
847 _, key := it.Element()
848 for iter := searchset.ElementIterator(); iter.Next(); {
849 _, search := iter.Element()
850 eq, err := stdlib.Equal(key, search)
851 if err != nil {
852 return cty.NilVal, err
853 }
854 if !eq.IsKnown() {
855 return cty.ListValEmpty(retType.ElementType()), nil
856 }
857 if eq.True() {
858 v := values.Index(cty.NumberIntVal(int64(i)))
859 output = append(output, v)
860 break
861 }
862 }
863 i++
864 }
865
866 // if we haven't matched any key, then output is an empty list.
867 if len(output) == 0 {
868 return cty.ListValEmpty(retType.ElementType()), nil
869 }
870 return cty.ListVal(output), nil
871 },
872 })
873
874 // MergeFunc constructs a function that takes an arbitrary number of maps and
875 // returns a single map that contains a merged set of elements from all of the maps.
876 //
877 // If more than one given map defines the same key then the one that is later in
878 // the argument sequence takes precedence.
879 var MergeFunc = function.New(&function.Spec{
880 Params: []function.Parameter{},
881 VarParam: &function.Parameter{
882 Name: "maps",
883 Type: cty.DynamicPseudoType,
884 AllowDynamicType: true,
885 },
886 Type: function.StaticReturnType(cty.DynamicPseudoType),
887 Impl: func(args []cty.Value, retType cty.Type) (ret cty.Value, err error) {
888 outputMap := make(map[string]cty.Value)
889
890 for _, arg := range args {
891 if !arg.IsWhollyKnown() {
892 return cty.UnknownVal(retType), nil
893 }
894 if !arg.Type().IsObjectType() && !arg.Type().IsMapType() {
895 return cty.NilVal, fmt.Errorf("arguments must be maps or objects, got %#v", arg.Type().FriendlyName())
896 }
897 for it := arg.ElementIterator(); it.Next(); {
898 k, v := it.Element()
899 outputMap[k.AsString()] = v
900 }
901 }
902 return cty.ObjectVal(outputMap), nil
903 },
904 })
905
906 // ReverseFunc takes a sequence and produces a new sequence of the same length
907 // with all of the same elements as the given sequence but in reverse order.
908 var ReverseFunc = function.New(&function.Spec{
909 Params: []function.Parameter{
910 {
911 Name: "list",
912 Type: cty.DynamicPseudoType,
913 },
914 },
915 Type: func(args []cty.Value) (cty.Type, error) {
916 argTy := args[0].Type()
917 switch {
918 case argTy.IsTupleType():
919 argTys := argTy.TupleElementTypes()
920 retTys := make([]cty.Type, len(argTys))
921 for i, ty := range argTys {
922 retTys[len(retTys)-i-1] = ty
923 }
924 return cty.Tuple(retTys), nil
925 case argTy.IsListType(), argTy.IsSetType(): // We accept sets here to mimic the usual behavior of auto-converting to list
926 return cty.List(argTy.ElementType()), nil
927 default:
928 return cty.NilType, function.NewArgErrorf(0, "can only reverse list or tuple values, not %s", argTy.FriendlyName())
929 }
930 },
931 Impl: func(args []cty.Value, retType cty.Type) (ret cty.Value, err error) {
932 in := args[0].AsValueSlice()
933 outVals := make([]cty.Value, len(in))
934 for i, v := range in {
935 outVals[len(outVals)-i-1] = v
936 }
937 switch {
938 case retType.IsTupleType():
939 return cty.TupleVal(outVals), nil
940 default:
941 if len(outVals) == 0 {
942 return cty.ListValEmpty(retType.ElementType()), nil
943 }
944 return cty.ListVal(outVals), nil
945 }
946 },
947 })
948
949 // SetProductFunc calculates the cartesian product of two or more sets or
950 // sequences. If the arguments are all lists then the result is a list of tuples,
951 // preserving the ordering of all of the input lists. Otherwise the result is a
952 // set of tuples.
953 var SetProductFunc = function.New(&function.Spec{
954 Params: []function.Parameter{},
955 VarParam: &function.Parameter{
956 Name: "sets",
957 Type: cty.DynamicPseudoType,
958 },
959 Type: func(args []cty.Value) (retType cty.Type, err error) {
960 if len(args) < 2 {
961 return cty.NilType, errors.New("at least two arguments are required")
962 }
963
964 listCount := 0
965 elemTys := make([]cty.Type, len(args))
966 for i, arg := range args {
967 aty := arg.Type()
968 switch {
969 case aty.IsSetType():
970 elemTys[i] = aty.ElementType()
971 case aty.IsListType():
972 elemTys[i] = aty.ElementType()
973 listCount++
974 case aty.IsTupleType():
975 // We can accept a tuple type only if there's some common type
976 // that all of its elements can be converted to.
977 allEtys := aty.TupleElementTypes()
978 if len(allEtys) == 0 {
979 elemTys[i] = cty.DynamicPseudoType
980 listCount++
981 break
982 }
983 ety, _ := convert.UnifyUnsafe(allEtys)
984 if ety == cty.NilType {
985 return cty.NilType, function.NewArgErrorf(i, "all elements must be of the same type")
986 }
987 elemTys[i] = ety
988 listCount++
989 default:
990 return cty.NilType, function.NewArgErrorf(i, "a set or a list is required")
991 }
992 }
993
994 if listCount == len(args) {
995 return cty.List(cty.Tuple(elemTys)), nil
996 }
997 return cty.Set(cty.Tuple(elemTys)), nil
998 },
999 Impl: func(args []cty.Value, retType cty.Type) (ret cty.Value, err error) {
1000 ety := retType.ElementType()
1001
1002 total := 1
1003 for _, arg := range args {
1004 // Because of our type checking function, we are guaranteed that
1005 // all of the arguments are known, non-null values of types that
1006 // support LengthInt.
1007 total *= arg.LengthInt()
1008 }
1009
1010 if total == 0 {
1011 // If any of the arguments was an empty collection then our result
1012 // is also an empty collection, which we'll short-circuit here.
1013 if retType.IsListType() {
1014 return cty.ListValEmpty(ety), nil
1015 }
1016 return cty.SetValEmpty(ety), nil
1017 }
1018
1019 subEtys := ety.TupleElementTypes()
1020 product := make([][]cty.Value, total)
1021
1022 b := make([]cty.Value, total*len(args))
1023 n := make([]int, len(args))
1024 s := 0
1025 argVals := make([][]cty.Value, len(args))
1026 for i, arg := range args {
1027 argVals[i] = arg.AsValueSlice()
1028 }
1029
1030 for i := range product {
1031 e := s + len(args)
1032 pi := b[s:e]
1033 product[i] = pi
1034 s = e
1035
1036 for j, n := range n {
1037 val := argVals[j][n]
1038 ty := subEtys[j]
1039 if !val.Type().Equals(ty) {
1040 var err error
1041 val, err = convert.Convert(val, ty)
1042 if err != nil {
1043 // Should never happen since we checked this in our
1044 // type-checking function.
1045 return cty.NilVal, fmt.Errorf("failed to convert argVals[%d][%d] to %s; this is a bug in Terraform", j, n, ty.FriendlyName())
1046 }
1047 }
1048 pi[j] = val
1049 }
1050
1051 for j := len(n) - 1; j >= 0; j-- {
1052 n[j]++
1053 if n[j] < len(argVals[j]) {
1054 break
1055 }
1056 n[j] = 0
1057 }
1058 }
1059
1060 productVals := make([]cty.Value, total)
1061 for i, vals := range product {
1062 productVals[i] = cty.TupleVal(vals)
1063 }
1064
1065 if retType.IsListType() {
1066 return cty.ListVal(productVals), nil
1067 }
1068 return cty.SetVal(productVals), nil
1069 },
1070 })
1071
1072 // SliceFunc constructs a function that extracts some consecutive elements
1073 // from within a list.
1074 var SliceFunc = function.New(&function.Spec{
1075 Params: []function.Parameter{
1076 {
1077 Name: "list",
1078 Type: cty.DynamicPseudoType,
1079 },
1080 {
1081 Name: "start_index",
1082 Type: cty.Number,
1083 },
1084 {
1085 Name: "end_index",
1086 Type: cty.Number,
1087 },
1088 },
1089 Type: func(args []cty.Value) (cty.Type, error) {
1090 arg := args[0]
1091 argTy := arg.Type()
1092
1093 if argTy.IsSetType() {
1094 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")
1095 }
1096 if !argTy.IsListType() && !argTy.IsTupleType() {
1097 return cty.NilType, function.NewArgErrorf(0, "must be a list or tuple value")
1098 }
1099
1100 startIndex, endIndex, idxsKnown, err := sliceIndexes(args)
1101 if err != nil {
1102 return cty.NilType, err
1103 }
1104
1105 if argTy.IsListType() {
1106 return argTy, nil
1107 }
1108
1109 if !idxsKnown {
1110 // If we don't know our start/end indices then we can't predict
1111 // the result type if we're planning to return a tuple.
1112 return cty.DynamicPseudoType, nil
1113 }
1114 return cty.Tuple(argTy.TupleElementTypes()[startIndex:endIndex]), nil
1115 },
1116 Impl: func(args []cty.Value, retType cty.Type) (ret cty.Value, err error) {
1117 inputList := args[0]
1118
1119 if retType == cty.DynamicPseudoType {
1120 return cty.DynamicVal, nil
1121 }
1122
1123 // we ignore idxsKnown return value here because the indices are always
1124 // known here, or else the call would've short-circuited.
1125 startIndex, endIndex, _, err := sliceIndexes(args)
1126 if err != nil {
1127 return cty.NilVal, err
1128 }
1129
1130 if endIndex-startIndex == 0 {
1131 if retType.IsTupleType() {
1132 return cty.EmptyTupleVal, nil
1133 }
1134 return cty.ListValEmpty(retType.ElementType()), nil
1135 }
1136
1137 outputList := inputList.AsValueSlice()[startIndex:endIndex]
1138
1139 if retType.IsTupleType() {
1140 return cty.TupleVal(outputList), nil
1141 }
1142
1143 return cty.ListVal(outputList), nil
1144 },
1145 })
1146
1147 func sliceIndexes(args []cty.Value) (int, int, bool, error) {
1148 var startIndex, endIndex, length int
1149 var startKnown, endKnown, lengthKnown bool
1150
1151 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
1152 length = args[0].LengthInt()
1153 lengthKnown = true
1154 }
1155
1156 if args[1].IsKnown() {
1157 if err := gocty.FromCtyValue(args[1], &startIndex); err != nil {
1158 return 0, 0, false, function.NewArgErrorf(1, "invalid start index: %s", err)
1159 }
1160 if startIndex < 0 {
1161 return 0, 0, false, function.NewArgErrorf(1, "start index must not be less than zero")
1162 }
1163 if lengthKnown && startIndex > length {
1164 return 0, 0, false, function.NewArgErrorf(1, "start index must not be greater than the length of the list")
1165 }
1166 startKnown = true
1167 }
1168 if args[2].IsKnown() {
1169 if err := gocty.FromCtyValue(args[2], &endIndex); err != nil {
1170 return 0, 0, false, function.NewArgErrorf(2, "invalid end index: %s", err)
1171 }
1172 if endIndex < 0 {
1173 return 0, 0, false, function.NewArgErrorf(2, "end index must not be less than zero")
1174 }
1175 if lengthKnown && endIndex > length {
1176 return 0, 0, false, function.NewArgErrorf(2, "end index must not be greater than the length of the list")
1177 }
1178 endKnown = true
1179 }
1180 if startKnown && endKnown {
1181 if startIndex > endIndex {
1182 return 0, 0, false, function.NewArgErrorf(1, "start index must not be greater than end index")
1183 }
1184 }
1185 return startIndex, endIndex, startKnown && endKnown, nil
1186 }
1187
1188 // TransposeFunc contructs a function that takes a map of lists of strings and
1189 // TransposeFunc constructs a function that takes a map of lists of strings and
1190 // swaps the keys and values to produce a new map of lists of strings.
1191 var TransposeFunc = function.New(&function.Spec{
1192 Params: []function.Parameter{
1193 {
1194 Name: "values",
1195 Type: cty.Map(cty.List(cty.String)),
1196 },
1197 },
1198 Type: function.StaticReturnType(cty.Map(cty.List(cty.String))),
1199 Impl: func(args []cty.Value, retType cty.Type) (ret cty.Value, err error) {
1200 inputMap := args[0]
1201 if !inputMap.IsWhollyKnown() {
1202 return cty.UnknownVal(retType), nil
1203 }
1204
1205 outputMap := make(map[string]cty.Value)
1206 tmpMap := make(map[string][]string)
1207
1208 for it := inputMap.ElementIterator(); it.Next(); {
1209 inKey, inVal := it.Element()
1210 for iter := inVal.ElementIterator(); iter.Next(); {
1211 _, val := iter.Element()
1212 if !val.Type().Equals(cty.String) {
1213 return cty.MapValEmpty(cty.List(cty.String)), errors.New("input must be a map of lists of strings")
1214 }
1215
1216 outKey := val.AsString()
1217 if _, ok := tmpMap[outKey]; !ok {
1218 tmpMap[outKey] = make([]string, 0)
1219 }
1220 outVal := tmpMap[outKey]
1221 outVal = append(outVal, inKey.AsString())
1222 sort.Strings(outVal)
1223 tmpMap[outKey] = outVal
1224 }
1225 }
1226
1227 for outKey, outVal := range tmpMap {
1228 values := make([]cty.Value, 0)
1229 for _, v := range outVal {
1230 values = append(values, cty.StringVal(v))
1231 }
1232 outputMap[outKey] = cty.ListVal(values)
1233 }
1234
1235 return cty.MapVal(outputMap), nil
1236 },
1237 })
1238
1239 // ValuesFunc constructs a function that returns a list of the map values,
1240 // in the order of the sorted keys.
1241 var ValuesFunc = function.New(&function.Spec{
1242 Params: []function.Parameter{
1243 {
1244 Name: "values",
1245 Type: cty.DynamicPseudoType,
1246 },
1247 },
1248 Type: func(args []cty.Value) (ret cty.Type, err error) {
1249 ty := args[0].Type()
1250 if ty.IsMapType() {
1251 return cty.List(ty.ElementType()), nil
1252 } else if ty.IsObjectType() {
1253 // The result is a tuple type with all of the same types as our
1254 // object type's attributes, sorted in lexicographical order by the
1255 // keys. (This matches the sort order guaranteed by ElementIterator
1256 // on a cty object value.)
1257 atys := ty.AttributeTypes()
1258 if len(atys) == 0 {
1259 return cty.EmptyTuple, nil
1260 }
1261 attrNames := make([]string, 0, len(atys))
1262 for name := range atys {
1263 attrNames = append(attrNames, name)
1264 }
1265 sort.Strings(attrNames)
1266
1267 tys := make([]cty.Type, len(attrNames))
1268 for i, name := range attrNames {
1269 tys[i] = atys[name]
1270 }
1271 return cty.Tuple(tys), nil
1272 }
1273 return cty.NilType, errors.New("values() requires a map as the first argument")
1274 },
1275 Impl: func(args []cty.Value, retType cty.Type) (ret cty.Value, err error) {
1276 mapVar := args[0]
1277
1278 // We can just iterate the map/object value here because cty guarantees
1279 // that these types always iterate in key lexicographical order.
1280 var values []cty.Value
1281 for it := mapVar.ElementIterator(); it.Next(); {
1282 _, val := it.Element()
1283 values = append(values, val)
1284 }
1285
1286 if retType.IsTupleType() {
1287 return cty.TupleVal(values), nil
1288 }
1289 if len(values) == 0 {
1290 return cty.ListValEmpty(retType.ElementType()), nil
1291 }
1292 return cty.ListVal(values), nil
1293 },
1294 })
1295
1296 // ZipmapFunc constructs a function that constructs a map from a list of keys
1297 // and a corresponding list of values.
1298 var ZipmapFunc = function.New(&function.Spec{
1299 Params: []function.Parameter{
1300 {
1301 Name: "keys",
1302 Type: cty.List(cty.String),
1303 },
1304 {
1305 Name: "values",
1306 Type: cty.DynamicPseudoType,
1307 },
1308 },
1309 Type: func(args []cty.Value) (ret cty.Type, err error) {
1310 keys := args[0]
1311 values := args[1]
1312 valuesTy := values.Type()
1313
1314 switch {
1315 case valuesTy.IsListType():
1316 return cty.Map(values.Type().ElementType()), nil
1317 case valuesTy.IsTupleType():
1318 if !keys.IsWhollyKnown() {
1319 // Since zipmap with a tuple produces an object, we need to know
1320 // all of the key names before we can predict our result type.
1321 return cty.DynamicPseudoType, nil
1322 }
1323
1324 keysRaw := keys.AsValueSlice()
1325 valueTypesRaw := valuesTy.TupleElementTypes()
1326 if len(keysRaw) != len(valueTypesRaw) {
1327 return cty.NilType, fmt.Errorf("number of keys (%d) does not match number of values (%d)", len(keysRaw), len(valueTypesRaw))
1328 }
1329 atys := make(map[string]cty.Type, len(valueTypesRaw))
1330 for i, keyVal := range keysRaw {
1331 if keyVal.IsNull() {
1332 return cty.NilType, fmt.Errorf("keys list has null value at index %d", i)
1333 }
1334 key := keyVal.AsString()
1335 atys[key] = valueTypesRaw[i]
1336 }
1337 return cty.Object(atys), nil
1338
1339 default:
1340 return cty.NilType, errors.New("values argument must be a list or tuple value")
1341 }
1342 },
1343 Impl: func(args []cty.Value, retType cty.Type) (ret cty.Value, err error) {
1344 keys := args[0]
1345 values := args[1]
1346
1347 if !keys.IsWhollyKnown() {
1348 // Unknown map keys and object attributes are not supported, so
1349 // our entire result must be unknown in this case.
1350 return cty.UnknownVal(retType), nil
1351 }
1352
1353 // both keys and values are guaranteed to be shallowly-known here,
1354 // because our declared params above don't allow unknown or null values.
1355 if keys.LengthInt() != values.LengthInt() {
1356 return cty.NilVal, fmt.Errorf("number of keys (%d) does not match number of values (%d)", keys.LengthInt(), values.LengthInt())
1357 }
1358
1359 output := make(map[string]cty.Value)
1360
1361 i := 0
1362 for it := keys.ElementIterator(); it.Next(); {
1363 _, v := it.Element()
1364 val := values.Index(cty.NumberIntVal(int64(i)))
1365 output[v.AsString()] = val
1366 i++
1367 }
1368
1369 switch {
1370 case retType.IsMapType():
1371 if len(output) == 0 {
1372 return cty.MapValEmpty(retType.ElementType()), nil
1373 }
1374 return cty.MapVal(output), nil
1375 case retType.IsObjectType():
1376 return cty.ObjectVal(output), nil
1377 default:
1378 // Should never happen because the type-check function should've
1379 // caught any other case.
1380 return cty.NilVal, fmt.Errorf("internally selected incorrect result type %s (this is a bug)", retType.FriendlyName())
1381 }
1382 },
1383 })
1384
1385 // helper function to add an element to a list, if it does not already exist
1386 func appendIfMissing(slice []cty.Value, element cty.Value) ([]cty.Value, error) {
1387 for _, ele := range slice {
1388 eq, err := stdlib.Equal(ele, element)
1389 if err != nil {
1390 return slice, err
1391 }
1392 if eq.True() {
1393 return slice, nil
1394 }
1395 }
1396 return append(slice, element), nil
1397 }
1398
1399 // Element returns a single element from a given list at the given index. If
1400 // index is greater than the length of the list then it is wrapped modulo
1401 // the list length.
1402 func Element(list, index cty.Value) (cty.Value, error) {
1403 return ElementFunc.Call([]cty.Value{list, index})
1404 }
1405
1406 // Length returns the number of elements in the given collection or number of
1407 // Unicode characters in the given string.
1408 func Length(collection cty.Value) (cty.Value, error) {
1409 return LengthFunc.Call([]cty.Value{collection})
1410 }
1411
1412 // Coalesce takes any number of arguments and returns the first one that isn't empty.
1413 func Coalesce(args ...cty.Value) (cty.Value, error) {
1414 return CoalesceFunc.Call(args)
1415 }
1416
1417 // CoalesceList takes any number of list arguments and returns the first one that isn't empty.
1418 func CoalesceList(args ...cty.Value) (cty.Value, error) {
1419 return CoalesceListFunc.Call(args)
1420 }
1421
1422 // Compact takes a list of strings and returns a new list
1423 // with any empty string elements removed.
1424 func Compact(list cty.Value) (cty.Value, error) {
1425 return CompactFunc.Call([]cty.Value{list})
1426 }
1427
1428 // Contains determines whether a given list contains a given single value
1429 // as one of its elements.
1430 func Contains(list, value cty.Value) (cty.Value, error) {
1431 return ContainsFunc.Call([]cty.Value{list, value})
1432 }
1433
1434 // Index finds the element index for a given value in a list.
1435 func Index(list, value cty.Value) (cty.Value, error) {
1436 return IndexFunc.Call([]cty.Value{list, value})
1437 }
1438
1439 // Distinct takes a list and returns a new list with any duplicate elements removed.
1440 func Distinct(list cty.Value) (cty.Value, error) {
1441 return DistinctFunc.Call([]cty.Value{list})
1442 }
1443
1444 // Chunklist splits a single list into fixed-size chunks, returning a list of lists.
1445 func Chunklist(list, size cty.Value) (cty.Value, error) {
1446 return ChunklistFunc.Call([]cty.Value{list, size})
1447 }
1448
1449 // Flatten takes a list and replaces any elements that are lists with a flattened
1450 // sequence of the list contents.
1451 func Flatten(list cty.Value) (cty.Value, error) {
1452 return FlattenFunc.Call([]cty.Value{list})
1453 }
1454
1455 // Keys takes a map and returns a sorted list of the map keys.
1456 func Keys(inputMap cty.Value) (cty.Value, error) {
1457 return KeysFunc.Call([]cty.Value{inputMap})
1458 }
1459
1460 // List takes any number of list arguments and returns a list containing those
1461 // values in the same order.
1462 func List(args ...cty.Value) (cty.Value, error) {
1463 return ListFunc.Call(args)
1464 }
1465
1466 // Lookup performs a dynamic lookup into a map.
1467 // There are two required arguments, map and key, plus an optional default,
1468 // which is a value to return if no key is found in map.
1469 func Lookup(args ...cty.Value) (cty.Value, error) {
1470 return LookupFunc.Call(args)
1471 }
1472
1473 // Map takes an even number of arguments and returns a map whose elements are constructed
1474 // from consecutive pairs of arguments.
1475 func Map(args ...cty.Value) (cty.Value, error) {
1476 return MapFunc.Call(args)
1477 }
1478
1479 // Matchkeys constructs a new list by taking a subset of elements from one list
1480 // whose indexes match the corresponding indexes of values in another list.
1481 func Matchkeys(values, keys, searchset cty.Value) (cty.Value, error) {
1482 return MatchkeysFunc.Call([]cty.Value{values, keys, searchset})
1483 }
1484
1485 // Merge takes an arbitrary number of maps and returns a single map that contains
1486 // a merged set of elements from all of the maps.
1487 //
1488 // If more than one given map defines the same key then the one that is later in
1489 // the argument sequence takes precedence.
1490 func Merge(maps ...cty.Value) (cty.Value, error) {
1491 return MergeFunc.Call(maps)
1492 }
1493
1494 // Reverse takes a sequence and produces a new sequence of the same length
1495 // with all of the same elements as the given sequence but in reverse order.
1496 func Reverse(list cty.Value) (cty.Value, error) {
1497 return ReverseFunc.Call([]cty.Value{list})
1498 }
1499
1500 // SetProduct computes the cartesian product of sets or sequences.
1501 func SetProduct(sets ...cty.Value) (cty.Value, error) {
1502 return SetProductFunc.Call(sets)
1503 }
1504
1505 // Slice extracts some consecutive elements from within a list.
1506 func Slice(list, start, end cty.Value) (cty.Value, error) {
1507 return SliceFunc.Call([]cty.Value{list, start, end})
1508 }
1509
1510 // Transpose takes a map of lists of strings and swaps the keys and values to
1511 // produce a new map of lists of strings.
1512 func Transpose(values cty.Value) (cty.Value, error) {
1513 return TransposeFunc.Call([]cty.Value{values})
1514 }
1515
1516 // Values returns a list of the map values, in the order of the sorted keys.
1517 // This function only works on flat maps.
1518 func Values(values cty.Value) (cty.Value, error) {
1519 return ValuesFunc.Call([]cty.Value{values})
1520 }
1521
1522 // Zipmap constructs a map from a list of keys and a corresponding list of values.
1523 func Zipmap(keys, values cty.Value) (cty.Value, error) {
1524 return ZipmapFunc.Call([]cty.Value{keys, values})
1525 }