diff options
Diffstat (limited to 'vendor/github.com/zclconf/go-cty/cty/function/stdlib/sequence.go')
-rw-r--r-- | vendor/github.com/zclconf/go-cty/cty/function/stdlib/sequence.go | 130 |
1 files changed, 130 insertions, 0 deletions
diff --git a/vendor/github.com/zclconf/go-cty/cty/function/stdlib/sequence.go b/vendor/github.com/zclconf/go-cty/cty/function/stdlib/sequence.go new file mode 100644 index 0000000..e2c77c5 --- /dev/null +++ b/vendor/github.com/zclconf/go-cty/cty/function/stdlib/sequence.go | |||
@@ -0,0 +1,130 @@ | |||
1 | package stdlib | ||
2 | |||
3 | import ( | ||
4 | "fmt" | ||
5 | |||
6 | "github.com/zclconf/go-cty/cty" | ||
7 | "github.com/zclconf/go-cty/cty/convert" | ||
8 | "github.com/zclconf/go-cty/cty/function" | ||
9 | ) | ||
10 | |||
11 | var ConcatFunc = function.New(&function.Spec{ | ||
12 | Params: []function.Parameter{}, | ||
13 | VarParam: &function.Parameter{ | ||
14 | Name: "seqs", | ||
15 | Type: cty.DynamicPseudoType, | ||
16 | }, | ||
17 | Type: func(args []cty.Value) (ret cty.Type, err error) { | ||
18 | if len(args) == 0 { | ||
19 | return cty.NilType, fmt.Errorf("at least one argument is required") | ||
20 | } | ||
21 | |||
22 | if args[0].Type().IsListType() { | ||
23 | // Possibly we're going to return a list, if all of our other | ||
24 | // args are also lists and we can find a common element type. | ||
25 | tys := make([]cty.Type, len(args)) | ||
26 | for i, val := range args { | ||
27 | ty := val.Type() | ||
28 | if !ty.IsListType() { | ||
29 | tys = nil | ||
30 | break | ||
31 | } | ||
32 | tys[i] = ty | ||
33 | } | ||
34 | |||
35 | if tys != nil { | ||
36 | commonType, _ := convert.UnifyUnsafe(tys) | ||
37 | if commonType != cty.NilType { | ||
38 | return commonType, nil | ||
39 | } | ||
40 | } | ||
41 | } | ||
42 | |||
43 | etys := make([]cty.Type, 0, len(args)) | ||
44 | for i, val := range args { | ||
45 | ety := val.Type() | ||
46 | switch { | ||
47 | case ety.IsTupleType(): | ||
48 | etys = append(etys, ety.TupleElementTypes()...) | ||
49 | case ety.IsListType(): | ||
50 | if !val.IsKnown() { | ||
51 | // We need to know the list to count its elements to | ||
52 | // build our tuple type, so any concat of an unknown | ||
53 | // list can't be typed yet. | ||
54 | return cty.DynamicPseudoType, nil | ||
55 | } | ||
56 | |||
57 | l := val.LengthInt() | ||
58 | subEty := ety.ElementType() | ||
59 | for j := 0; j < l; j++ { | ||
60 | etys = append(etys, subEty) | ||
61 | } | ||
62 | default: | ||
63 | return cty.NilType, function.NewArgErrorf( | ||
64 | i, "all arguments must be lists or tuples; got %s", | ||
65 | ety.FriendlyName(), | ||
66 | ) | ||
67 | } | ||
68 | } | ||
69 | return cty.Tuple(etys), nil | ||
70 | }, | ||
71 | Impl: func(args []cty.Value, retType cty.Type) (ret cty.Value, err error) { | ||
72 | switch { | ||
73 | case retType.IsListType(): | ||
74 | // If retType is a list type then we know that all of the | ||
75 | // given values will be lists and that they will either be of | ||
76 | // retType or of something we can convert to retType. | ||
77 | vals := make([]cty.Value, 0, len(args)) | ||
78 | for i, list := range args { | ||
79 | list, err = convert.Convert(list, retType) | ||
80 | if err != nil { | ||
81 | // Conversion might fail because we used UnifyUnsafe | ||
82 | // to choose our return type. | ||
83 | return cty.NilVal, function.NewArgError(i, err) | ||
84 | } | ||
85 | |||
86 | it := list.ElementIterator() | ||
87 | for it.Next() { | ||
88 | _, v := it.Element() | ||
89 | vals = append(vals, v) | ||
90 | } | ||
91 | } | ||
92 | if len(vals) == 0 { | ||
93 | return cty.ListValEmpty(retType.ElementType()), nil | ||
94 | } | ||
95 | |||
96 | return cty.ListVal(vals), nil | ||
97 | case retType.IsTupleType(): | ||
98 | // If retType is a tuple type then we could have a mixture of | ||
99 | // lists and tuples but we know they all have known values | ||
100 | // (because our params don't AllowUnknown) and we know that | ||
101 | // concatenating them all together will produce a tuple of | ||
102 | // retType because of the work we did in the Type function above. | ||
103 | vals := make([]cty.Value, 0, len(args)) | ||
104 | |||
105 | for _, seq := range args { | ||
106 | // Both lists and tuples support ElementIterator, so this is easy. | ||
107 | it := seq.ElementIterator() | ||
108 | for it.Next() { | ||
109 | _, v := it.Element() | ||
110 | vals = append(vals, v) | ||
111 | } | ||
112 | } | ||
113 | |||
114 | return cty.TupleVal(vals), nil | ||
115 | default: | ||
116 | // should never happen if Type is working correctly above | ||
117 | panic("unsupported return type") | ||
118 | } | ||
119 | }, | ||
120 | }) | ||
121 | |||
122 | // Concat takes one or more sequences (lists or tuples) and returns the single | ||
123 | // sequence that results from concatenating them together in order. | ||
124 | // | ||
125 | // If all of the given sequences are lists of the same element type then the | ||
126 | // result is a list of that type. Otherwise, the result is a of a tuple type | ||
127 | // constructed from the given sequence types. | ||
128 | func Concat(seqs ...cty.Value) (cty.Value, error) { | ||
129 | return ConcatFunc.Call(seqs) | ||
130 | } | ||