diff options
Diffstat (limited to 'vendor/github.com/zclconf/go-cty/cty/convert')
9 files changed, 827 insertions, 0 deletions
diff --git a/vendor/github.com/zclconf/go-cty/cty/convert/compare_types.go b/vendor/github.com/zclconf/go-cty/cty/convert/compare_types.go new file mode 100644 index 0000000..d84f6ac --- /dev/null +++ b/vendor/github.com/zclconf/go-cty/cty/convert/compare_types.go | |||
@@ -0,0 +1,165 @@ | |||
1 | package convert | ||
2 | |||
3 | import ( | ||
4 | "github.com/zclconf/go-cty/cty" | ||
5 | ) | ||
6 | |||
7 | // compareTypes implements a preference order for unification. | ||
8 | // | ||
9 | // The result of this method is not useful for anything other than unification | ||
10 | // preferences, since it assumes that the caller will verify that any suggested | ||
11 | // conversion is actually possible and it is thus able to to make certain | ||
12 | // optimistic assumptions. | ||
13 | func compareTypes(a cty.Type, b cty.Type) int { | ||
14 | |||
15 | // DynamicPseudoType always has lowest preference, because anything can | ||
16 | // convert to it (it acts as a placeholder for "any type") and we want | ||
17 | // to optimistically assume that any dynamics will converge on matching | ||
18 | // their neighbors. | ||
19 | if a == cty.DynamicPseudoType || b == cty.DynamicPseudoType { | ||
20 | if a != cty.DynamicPseudoType { | ||
21 | return -1 | ||
22 | } | ||
23 | if b != cty.DynamicPseudoType { | ||
24 | return 1 | ||
25 | } | ||
26 | return 0 | ||
27 | } | ||
28 | |||
29 | if a.IsPrimitiveType() && b.IsPrimitiveType() { | ||
30 | // String is a supertype of all primitive types, because we can | ||
31 | // represent all primitive values as specially-formatted strings. | ||
32 | if a == cty.String || b == cty.String { | ||
33 | if a != cty.String { | ||
34 | return 1 | ||
35 | } | ||
36 | if b != cty.String { | ||
37 | return -1 | ||
38 | } | ||
39 | return 0 | ||
40 | } | ||
41 | } | ||
42 | |||
43 | if a.IsListType() && b.IsListType() { | ||
44 | return compareTypes(a.ElementType(), b.ElementType()) | ||
45 | } | ||
46 | if a.IsSetType() && b.IsSetType() { | ||
47 | return compareTypes(a.ElementType(), b.ElementType()) | ||
48 | } | ||
49 | if a.IsMapType() && b.IsMapType() { | ||
50 | return compareTypes(a.ElementType(), b.ElementType()) | ||
51 | } | ||
52 | |||
53 | // From this point on we may have swapped the two items in order to | ||
54 | // simplify our cases. Therefore any non-zero return after this point | ||
55 | // must be multiplied by "swap" to potentially invert the return value | ||
56 | // if needed. | ||
57 | swap := 1 | ||
58 | switch { | ||
59 | case a.IsTupleType() && b.IsListType(): | ||
60 | fallthrough | ||
61 | case a.IsObjectType() && b.IsMapType(): | ||
62 | fallthrough | ||
63 | case a.IsSetType() && b.IsTupleType(): | ||
64 | fallthrough | ||
65 | case a.IsSetType() && b.IsListType(): | ||
66 | a, b = b, a | ||
67 | swap = -1 | ||
68 | } | ||
69 | |||
70 | if b.IsSetType() && (a.IsTupleType() || a.IsListType()) { | ||
71 | // We'll just optimistically assume that the element types are | ||
72 | // unifyable/convertible, and let a second recursive pass | ||
73 | // figure out how to make that so. | ||
74 | return -1 * swap | ||
75 | } | ||
76 | |||
77 | if a.IsListType() && b.IsTupleType() { | ||
78 | // We'll just optimistically assume that the tuple's element types | ||
79 | // can be unified into something compatible with the list's element | ||
80 | // type. | ||
81 | return -1 * swap | ||
82 | } | ||
83 | |||
84 | if a.IsMapType() && b.IsObjectType() { | ||
85 | // We'll just optimistically assume that the object's attribute types | ||
86 | // can be unified into something compatible with the map's element | ||
87 | // type. | ||
88 | return -1 * swap | ||
89 | } | ||
90 | |||
91 | // For object and tuple types, comparing two types doesn't really tell | ||
92 | // the whole story because it may be possible to construct a new type C | ||
93 | // that is the supertype of both A and B by unifying each attribute/element | ||
94 | // separately. That possibility is handled by Unify as a follow-up if | ||
95 | // type sorting is insufficient to produce a valid result. | ||
96 | // | ||
97 | // Here we will take care of the simple possibilities where no new type | ||
98 | // is needed. | ||
99 | if a.IsObjectType() && b.IsObjectType() { | ||
100 | atysA := a.AttributeTypes() | ||
101 | atysB := b.AttributeTypes() | ||
102 | |||
103 | if len(atysA) != len(atysB) { | ||
104 | return 0 | ||
105 | } | ||
106 | |||
107 | hasASuper := false | ||
108 | hasBSuper := false | ||
109 | for k := range atysA { | ||
110 | if _, has := atysB[k]; !has { | ||
111 | return 0 | ||
112 | } | ||
113 | |||
114 | cmp := compareTypes(atysA[k], atysB[k]) | ||
115 | if cmp < 0 { | ||
116 | hasASuper = true | ||
117 | } else if cmp > 0 { | ||
118 | hasBSuper = true | ||
119 | } | ||
120 | } | ||
121 | |||
122 | switch { | ||
123 | case hasASuper && hasBSuper: | ||
124 | return 0 | ||
125 | case hasASuper: | ||
126 | return -1 * swap | ||
127 | case hasBSuper: | ||
128 | return 1 * swap | ||
129 | default: | ||
130 | return 0 | ||
131 | } | ||
132 | } | ||
133 | if a.IsTupleType() && b.IsTupleType() { | ||
134 | etysA := a.TupleElementTypes() | ||
135 | etysB := b.TupleElementTypes() | ||
136 | |||
137 | if len(etysA) != len(etysB) { | ||
138 | return 0 | ||
139 | } | ||
140 | |||
141 | hasASuper := false | ||
142 | hasBSuper := false | ||
143 | for i := range etysA { | ||
144 | cmp := compareTypes(etysA[i], etysB[i]) | ||
145 | if cmp < 0 { | ||
146 | hasASuper = true | ||
147 | } else if cmp > 0 { | ||
148 | hasBSuper = true | ||
149 | } | ||
150 | } | ||
151 | |||
152 | switch { | ||
153 | case hasASuper && hasBSuper: | ||
154 | return 0 | ||
155 | case hasASuper: | ||
156 | return -1 * swap | ||
157 | case hasBSuper: | ||
158 | return 1 * swap | ||
159 | default: | ||
160 | return 0 | ||
161 | } | ||
162 | } | ||
163 | |||
164 | return 0 | ||
165 | } | ||
diff --git a/vendor/github.com/zclconf/go-cty/cty/convert/conversion.go b/vendor/github.com/zclconf/go-cty/cty/convert/conversion.go new file mode 100644 index 0000000..7bfcc08 --- /dev/null +++ b/vendor/github.com/zclconf/go-cty/cty/convert/conversion.go | |||
@@ -0,0 +1,120 @@ | |||
1 | package convert | ||
2 | |||
3 | import ( | ||
4 | "github.com/zclconf/go-cty/cty" | ||
5 | ) | ||
6 | |||
7 | // conversion is an internal variant of Conversion that carries around | ||
8 | // a cty.Path to be used in error responses. | ||
9 | type conversion func(cty.Value, cty.Path) (cty.Value, error) | ||
10 | |||
11 | func getConversion(in cty.Type, out cty.Type, unsafe bool) conversion { | ||
12 | conv := getConversionKnown(in, out, unsafe) | ||
13 | if conv == nil { | ||
14 | return nil | ||
15 | } | ||
16 | |||
17 | // Wrap the conversion in some standard checks that we don't want to | ||
18 | // have to repeat in every conversion function. | ||
19 | return func(in cty.Value, path cty.Path) (cty.Value, error) { | ||
20 | if !in.IsKnown() { | ||
21 | return cty.UnknownVal(out), nil | ||
22 | } | ||
23 | if in.IsNull() { | ||
24 | // We'll pass through nulls, albeit type converted, and let | ||
25 | // the caller deal with whatever handling they want to do in | ||
26 | // case null values are considered valid in some applications. | ||
27 | return cty.NullVal(out), nil | ||
28 | } | ||
29 | |||
30 | return conv(in, path) | ||
31 | } | ||
32 | } | ||
33 | |||
34 | func getConversionKnown(in cty.Type, out cty.Type, unsafe bool) conversion { | ||
35 | switch { | ||
36 | |||
37 | case out == cty.DynamicPseudoType: | ||
38 | // Conversion *to* DynamicPseudoType means that the caller wishes | ||
39 | // to allow any type in this position, so we'll produce a do-nothing | ||
40 | // conversion that just passes through the value as-is. | ||
41 | return dynamicPassthrough | ||
42 | |||
43 | case unsafe && in == cty.DynamicPseudoType: | ||
44 | // Conversion *from* DynamicPseudoType means that we have a value | ||
45 | // whose type isn't yet known during type checking. For these we will | ||
46 | // assume that conversion will succeed and deal with any errors that | ||
47 | // result (which is why we can only do this when "unsafe" is set). | ||
48 | return dynamicFixup(out) | ||
49 | |||
50 | case in.IsPrimitiveType() && out.IsPrimitiveType(): | ||
51 | conv := primitiveConversionsSafe[in][out] | ||
52 | if conv != nil { | ||
53 | return conv | ||
54 | } | ||
55 | if unsafe { | ||
56 | return primitiveConversionsUnsafe[in][out] | ||
57 | } | ||
58 | return nil | ||
59 | |||
60 | case out.IsListType() && (in.IsListType() || in.IsSetType()): | ||
61 | inEty := in.ElementType() | ||
62 | outEty := out.ElementType() | ||
63 | if inEty.Equals(outEty) { | ||
64 | // This indicates that we're converting from list to set with | ||
65 | // the same element type, so we don't need an element converter. | ||
66 | return conversionCollectionToList(outEty, nil) | ||
67 | } | ||
68 | |||
69 | convEty := getConversion(inEty, outEty, unsafe) | ||
70 | if convEty == nil { | ||
71 | return nil | ||
72 | } | ||
73 | return conversionCollectionToList(outEty, convEty) | ||
74 | |||
75 | case out.IsSetType() && (in.IsListType() || in.IsSetType()): | ||
76 | if in.IsListType() && !unsafe { | ||
77 | // Conversion from list to map is unsafe because it will lose | ||
78 | // information: the ordering will not be preserved, and any | ||
79 | // duplicate elements will be conflated. | ||
80 | return nil | ||
81 | } | ||
82 | inEty := in.ElementType() | ||
83 | outEty := out.ElementType() | ||
84 | convEty := getConversion(inEty, outEty, unsafe) | ||
85 | if inEty.Equals(outEty) { | ||
86 | // This indicates that we're converting from set to list with | ||
87 | // the same element type, so we don't need an element converter. | ||
88 | return conversionCollectionToSet(outEty, nil) | ||
89 | } | ||
90 | |||
91 | if convEty == nil { | ||
92 | return nil | ||
93 | } | ||
94 | return conversionCollectionToSet(outEty, convEty) | ||
95 | |||
96 | case out.IsListType() && in.IsTupleType(): | ||
97 | outEty := out.ElementType() | ||
98 | return conversionTupleToList(in, outEty, unsafe) | ||
99 | |||
100 | case out.IsMapType() && in.IsObjectType(): | ||
101 | outEty := out.ElementType() | ||
102 | return conversionObjectToMap(in, outEty, unsafe) | ||
103 | |||
104 | default: | ||
105 | return nil | ||
106 | |||
107 | } | ||
108 | } | ||
109 | |||
110 | // retConversion wraps a conversion (internal type) so it can be returned | ||
111 | // as a Conversion (public type). | ||
112 | func retConversion(conv conversion) Conversion { | ||
113 | if conv == nil { | ||
114 | return nil | ||
115 | } | ||
116 | |||
117 | return func(in cty.Value) (cty.Value, error) { | ||
118 | return conv(in, cty.Path(nil)) | ||
119 | } | ||
120 | } | ||
diff --git a/vendor/github.com/zclconf/go-cty/cty/convert/conversion_collection.go b/vendor/github.com/zclconf/go-cty/cty/convert/conversion_collection.go new file mode 100644 index 0000000..eace85d --- /dev/null +++ b/vendor/github.com/zclconf/go-cty/cty/convert/conversion_collection.go | |||
@@ -0,0 +1,226 @@ | |||
1 | package convert | ||
2 | |||
3 | import ( | ||
4 | "github.com/zclconf/go-cty/cty" | ||
5 | ) | ||
6 | |||
7 | // conversionCollectionToList returns a conversion that will apply the given | ||
8 | // conversion to all of the elements of a collection (something that supports | ||
9 | // ForEachElement and LengthInt) and then returns the result as a list. | ||
10 | // | ||
11 | // "conv" can be nil if the elements are expected to already be of the | ||
12 | // correct type and just need to be re-wrapped into a list. (For example, | ||
13 | // if we're converting from a set into a list of the same element type.) | ||
14 | func conversionCollectionToList(ety cty.Type, conv conversion) conversion { | ||
15 | return func(val cty.Value, path cty.Path) (cty.Value, error) { | ||
16 | elems := make([]cty.Value, 0, val.LengthInt()) | ||
17 | i := int64(0) | ||
18 | path = append(path, nil) | ||
19 | it := val.ElementIterator() | ||
20 | for it.Next() { | ||
21 | _, val := it.Element() | ||
22 | var err error | ||
23 | |||
24 | path[len(path)-1] = cty.IndexStep{ | ||
25 | Key: cty.NumberIntVal(i), | ||
26 | } | ||
27 | |||
28 | if conv != nil { | ||
29 | val, err = conv(val, path) | ||
30 | if err != nil { | ||
31 | return cty.NilVal, err | ||
32 | } | ||
33 | } | ||
34 | elems = append(elems, val) | ||
35 | |||
36 | i++ | ||
37 | } | ||
38 | |||
39 | if len(elems) == 0 { | ||
40 | return cty.ListValEmpty(ety), nil | ||
41 | } | ||
42 | |||
43 | return cty.ListVal(elems), nil | ||
44 | } | ||
45 | } | ||
46 | |||
47 | // conversionCollectionToSet returns a conversion that will apply the given | ||
48 | // conversion to all of the elements of a collection (something that supports | ||
49 | // ForEachElement and LengthInt) and then returns the result as a set. | ||
50 | // | ||
51 | // "conv" can be nil if the elements are expected to already be of the | ||
52 | // correct type and just need to be re-wrapped into a set. (For example, | ||
53 | // if we're converting from a list into a set of the same element type.) | ||
54 | func conversionCollectionToSet(ety cty.Type, conv conversion) conversion { | ||
55 | return func(val cty.Value, path cty.Path) (cty.Value, error) { | ||
56 | elems := make([]cty.Value, 0, val.LengthInt()) | ||
57 | i := int64(0) | ||
58 | path = append(path, nil) | ||
59 | it := val.ElementIterator() | ||
60 | for it.Next() { | ||
61 | _, val := it.Element() | ||
62 | var err error | ||
63 | |||
64 | path[len(path)-1] = cty.IndexStep{ | ||
65 | Key: cty.NumberIntVal(i), | ||
66 | } | ||
67 | |||
68 | if conv != nil { | ||
69 | val, err = conv(val, path) | ||
70 | if err != nil { | ||
71 | return cty.NilVal, err | ||
72 | } | ||
73 | } | ||
74 | elems = append(elems, val) | ||
75 | |||
76 | i++ | ||
77 | } | ||
78 | |||
79 | if len(elems) == 0 { | ||
80 | return cty.SetValEmpty(ety), nil | ||
81 | } | ||
82 | |||
83 | return cty.SetVal(elems), nil | ||
84 | } | ||
85 | } | ||
86 | |||
87 | // conversionTupleToList returns a conversion that will take a value of the | ||
88 | // given tuple type and return a list of the given element type. | ||
89 | // | ||
90 | // Will panic if the given tupleType isn't actually a tuple type. | ||
91 | func conversionTupleToList(tupleType cty.Type, listEty cty.Type, unsafe bool) conversion { | ||
92 | tupleEtys := tupleType.TupleElementTypes() | ||
93 | |||
94 | if len(tupleEtys) == 0 { | ||
95 | // Empty tuple short-circuit | ||
96 | return func(val cty.Value, path cty.Path) (cty.Value, error) { | ||
97 | return cty.ListValEmpty(listEty), nil | ||
98 | } | ||
99 | } | ||
100 | |||
101 | if listEty == cty.DynamicPseudoType { | ||
102 | // This is a special case where the caller wants us to find | ||
103 | // a suitable single type that all elements can convert to, if | ||
104 | // possible. | ||
105 | listEty, _ = unify(tupleEtys, unsafe) | ||
106 | if listEty == cty.NilType { | ||
107 | return nil | ||
108 | } | ||
109 | } | ||
110 | |||
111 | elemConvs := make([]conversion, len(tupleEtys)) | ||
112 | for i, tupleEty := range tupleEtys { | ||
113 | if tupleEty.Equals(listEty) { | ||
114 | // no conversion required | ||
115 | continue | ||
116 | } | ||
117 | |||
118 | elemConvs[i] = getConversion(tupleEty, listEty, unsafe) | ||
119 | if elemConvs[i] == nil { | ||
120 | // If any of our element conversions are impossible, then the our | ||
121 | // whole conversion is impossible. | ||
122 | return nil | ||
123 | } | ||
124 | } | ||
125 | |||
126 | // If we fall out here then a conversion is possible, using the | ||
127 | // element conversions in elemConvs | ||
128 | return func(val cty.Value, path cty.Path) (cty.Value, error) { | ||
129 | elems := make([]cty.Value, 0, len(elemConvs)) | ||
130 | path = append(path, nil) | ||
131 | i := int64(0) | ||
132 | it := val.ElementIterator() | ||
133 | for it.Next() { | ||
134 | _, val := it.Element() | ||
135 | var err error | ||
136 | |||
137 | path[len(path)-1] = cty.IndexStep{ | ||
138 | Key: cty.NumberIntVal(i), | ||
139 | } | ||
140 | |||
141 | conv := elemConvs[i] | ||
142 | if conv != nil { | ||
143 | val, err = conv(val, path) | ||
144 | if err != nil { | ||
145 | return cty.NilVal, err | ||
146 | } | ||
147 | } | ||
148 | elems = append(elems, val) | ||
149 | |||
150 | i++ | ||
151 | } | ||
152 | |||
153 | return cty.ListVal(elems), nil | ||
154 | } | ||
155 | } | ||
156 | |||
157 | // conversionObjectToMap returns a conversion that will take a value of the | ||
158 | // given object type and return a map of the given element type. | ||
159 | // | ||
160 | // Will panic if the given objectType isn't actually an object type. | ||
161 | func conversionObjectToMap(objectType cty.Type, mapEty cty.Type, unsafe bool) conversion { | ||
162 | objectAtys := objectType.AttributeTypes() | ||
163 | |||
164 | if len(objectAtys) == 0 { | ||
165 | // Empty object short-circuit | ||
166 | return func(val cty.Value, path cty.Path) (cty.Value, error) { | ||
167 | return cty.MapValEmpty(mapEty), nil | ||
168 | } | ||
169 | } | ||
170 | |||
171 | if mapEty == cty.DynamicPseudoType { | ||
172 | // This is a special case where the caller wants us to find | ||
173 | // a suitable single type that all elements can convert to, if | ||
174 | // possible. | ||
175 | objectAtysList := make([]cty.Type, 0, len(objectAtys)) | ||
176 | for _, aty := range objectAtys { | ||
177 | objectAtysList = append(objectAtysList, aty) | ||
178 | } | ||
179 | mapEty, _ = unify(objectAtysList, unsafe) | ||
180 | if mapEty == cty.NilType { | ||
181 | return nil | ||
182 | } | ||
183 | } | ||
184 | |||
185 | elemConvs := make(map[string]conversion, len(objectAtys)) | ||
186 | for name, objectAty := range objectAtys { | ||
187 | if objectAty.Equals(mapEty) { | ||
188 | // no conversion required | ||
189 | continue | ||
190 | } | ||
191 | |||
192 | elemConvs[name] = getConversion(objectAty, mapEty, unsafe) | ||
193 | if elemConvs[name] == nil { | ||
194 | // If any of our element conversions are impossible, then the our | ||
195 | // whole conversion is impossible. | ||
196 | return nil | ||
197 | } | ||
198 | } | ||
199 | |||
200 | // If we fall out here then a conversion is possible, using the | ||
201 | // element conversions in elemConvs | ||
202 | return func(val cty.Value, path cty.Path) (cty.Value, error) { | ||
203 | elems := make(map[string]cty.Value, len(elemConvs)) | ||
204 | path = append(path, nil) | ||
205 | it := val.ElementIterator() | ||
206 | for it.Next() { | ||
207 | name, val := it.Element() | ||
208 | var err error | ||
209 | |||
210 | path[len(path)-1] = cty.IndexStep{ | ||
211 | Key: name, | ||
212 | } | ||
213 | |||
214 | conv := elemConvs[name.AsString()] | ||
215 | if conv != nil { | ||
216 | val, err = conv(val, path) | ||
217 | if err != nil { | ||
218 | return cty.NilVal, err | ||
219 | } | ||
220 | } | ||
221 | elems[name.AsString()] = val | ||
222 | } | ||
223 | |||
224 | return cty.MapVal(elems), nil | ||
225 | } | ||
226 | } | ||
diff --git a/vendor/github.com/zclconf/go-cty/cty/convert/conversion_dynamic.go b/vendor/github.com/zclconf/go-cty/cty/convert/conversion_dynamic.go new file mode 100644 index 0000000..4d19cf6 --- /dev/null +++ b/vendor/github.com/zclconf/go-cty/cty/convert/conversion_dynamic.go | |||
@@ -0,0 +1,33 @@ | |||
1 | package convert | ||
2 | |||
3 | import ( | ||
4 | "github.com/zclconf/go-cty/cty" | ||
5 | ) | ||
6 | |||
7 | // dynamicFixup deals with just-in-time conversions of values that were | ||
8 | // input-typed as cty.DynamicPseudoType during analysis, ensuring that | ||
9 | // we end up with the desired output type once the value is known, or | ||
10 | // failing with an error if that is not possible. | ||
11 | // | ||
12 | // This is in the spirit of the cty philosophy of optimistically assuming that | ||
13 | // DynamicPseudoType values will become the intended value eventually, and | ||
14 | // dealing with any inconsistencies during final evaluation. | ||
15 | func dynamicFixup(wantType cty.Type) conversion { | ||
16 | return func(in cty.Value, path cty.Path) (cty.Value, error) { | ||
17 | ret, err := Convert(in, wantType) | ||
18 | if err != nil { | ||
19 | // Re-wrap this error so that the returned path is relative | ||
20 | // to the caller's original value, rather than relative to our | ||
21 | // conversion value here. | ||
22 | return cty.NilVal, path.NewError(err) | ||
23 | } | ||
24 | return ret, nil | ||
25 | } | ||
26 | } | ||
27 | |||
28 | // dynamicPassthrough is an identity conversion that is used when the | ||
29 | // target type is DynamicPseudoType, indicating that the caller doesn't care | ||
30 | // which type is returned. | ||
31 | func dynamicPassthrough(in cty.Value, path cty.Path) (cty.Value, error) { | ||
32 | return in, nil | ||
33 | } | ||
diff --git a/vendor/github.com/zclconf/go-cty/cty/convert/conversion_primitive.go b/vendor/github.com/zclconf/go-cty/cty/convert/conversion_primitive.go new file mode 100644 index 0000000..e563ee3 --- /dev/null +++ b/vendor/github.com/zclconf/go-cty/cty/convert/conversion_primitive.go | |||
@@ -0,0 +1,50 @@ | |||
1 | package convert | ||
2 | |||
3 | import ( | ||
4 | "math/big" | ||
5 | |||
6 | "github.com/zclconf/go-cty/cty" | ||
7 | ) | ||
8 | |||
9 | var stringTrue = cty.StringVal("true") | ||
10 | var stringFalse = cty.StringVal("false") | ||
11 | |||
12 | var primitiveConversionsSafe = map[cty.Type]map[cty.Type]conversion{ | ||
13 | cty.Number: { | ||
14 | cty.String: func(val cty.Value, path cty.Path) (cty.Value, error) { | ||
15 | f := val.AsBigFloat() | ||
16 | return cty.StringVal(f.Text('f', -1)), nil | ||
17 | }, | ||
18 | }, | ||
19 | cty.Bool: { | ||
20 | cty.String: func(val cty.Value, path cty.Path) (cty.Value, error) { | ||
21 | if val.True() { | ||
22 | return stringTrue, nil | ||
23 | } else { | ||
24 | return stringFalse, nil | ||
25 | } | ||
26 | }, | ||
27 | }, | ||
28 | } | ||
29 | |||
30 | var primitiveConversionsUnsafe = map[cty.Type]map[cty.Type]conversion{ | ||
31 | cty.String: { | ||
32 | cty.Number: func(val cty.Value, path cty.Path) (cty.Value, error) { | ||
33 | f, _, err := big.ParseFloat(val.AsString(), 10, 512, big.ToNearestEven) | ||
34 | if err != nil { | ||
35 | return cty.NilVal, path.NewErrorf("a number is required") | ||
36 | } | ||
37 | return cty.NumberVal(f), nil | ||
38 | }, | ||
39 | cty.Bool: func(val cty.Value, path cty.Path) (cty.Value, error) { | ||
40 | switch val.AsString() { | ||
41 | case "true", "1": | ||
42 | return cty.True, nil | ||
43 | case "false", "0": | ||
44 | return cty.False, nil | ||
45 | default: | ||
46 | return cty.NilVal, path.NewErrorf("a bool is required") | ||
47 | } | ||
48 | }, | ||
49 | }, | ||
50 | } | ||
diff --git a/vendor/github.com/zclconf/go-cty/cty/convert/doc.go b/vendor/github.com/zclconf/go-cty/cty/convert/doc.go new file mode 100644 index 0000000..2037299 --- /dev/null +++ b/vendor/github.com/zclconf/go-cty/cty/convert/doc.go | |||
@@ -0,0 +1,15 @@ | |||
1 | // Package convert contains some routines for converting between cty types. | ||
2 | // The intent of providing this package is to encourage applications using | ||
3 | // cty to have consistent type conversion behavior for maximal interoperability | ||
4 | // when Values pass from one application to another. | ||
5 | // | ||
6 | // The conversions are categorized into two categories. "Safe" conversions are | ||
7 | // ones that are guaranteed to succeed if given a non-null value of the | ||
8 | // appropriate source type. "Unsafe" conversions, on the other hand, are valid | ||
9 | // for only a subset of input values, and thus may fail with an error when | ||
10 | // called for values outside of that valid subset. | ||
11 | // | ||
12 | // The functions whose names end in Unsafe support all of the conversions that | ||
13 | // are supported by the corresponding functions whose names do not have that | ||
14 | // suffix, and then additional unsafe conversions as well. | ||
15 | package convert | ||
diff --git a/vendor/github.com/zclconf/go-cty/cty/convert/public.go b/vendor/github.com/zclconf/go-cty/cty/convert/public.go new file mode 100644 index 0000000..55f44ae --- /dev/null +++ b/vendor/github.com/zclconf/go-cty/cty/convert/public.go | |||
@@ -0,0 +1,83 @@ | |||
1 | package convert | ||
2 | |||
3 | import ( | ||
4 | "fmt" | ||
5 | |||
6 | "github.com/zclconf/go-cty/cty" | ||
7 | ) | ||
8 | |||
9 | // This file contains the public interface of this package, which is intended | ||
10 | // to be a small, convenient interface designed for easy integration into | ||
11 | // a hypothetical language type checker and interpreter. | ||
12 | |||
13 | // Conversion is a named function type representing a conversion from a | ||
14 | // value of one type to a value of another type. | ||
15 | // | ||
16 | // The source type for a conversion is always the source type given to | ||
17 | // the function that returned the Conversion, but there is no way to recover | ||
18 | // that from a Conversion value itself. If a Conversion is given a value | ||
19 | // that is not of its expected type (with the exception of DynamicPseudoType, | ||
20 | // which is always supported) then the function may panic or produce undefined | ||
21 | // results. | ||
22 | type Conversion func(in cty.Value) (out cty.Value, err error) | ||
23 | |||
24 | // GetConversion returns a Conversion between the given in and out Types if | ||
25 | // a safe one is available, or returns nil otherwise. | ||
26 | func GetConversion(in cty.Type, out cty.Type) Conversion { | ||
27 | return retConversion(getConversion(in, out, false)) | ||
28 | } | ||
29 | |||
30 | // GetConversionUnsafe returns a Conversion between the given in and out Types | ||
31 | // if either a safe or unsafe one is available, or returns nil otherwise. | ||
32 | func GetConversionUnsafe(in cty.Type, out cty.Type) Conversion { | ||
33 | return retConversion(getConversion(in, out, true)) | ||
34 | } | ||
35 | |||
36 | // Convert returns the result of converting the given value to the given type | ||
37 | // if an safe or unsafe conversion is available, or returns an error if such a | ||
38 | // conversion is impossible. | ||
39 | // | ||
40 | // This is a convenience wrapper around calling GetConversionUnsafe and then | ||
41 | // immediately passing the given value to the resulting function. | ||
42 | func Convert(in cty.Value, want cty.Type) (cty.Value, error) { | ||
43 | if in.Type().Equals(want) { | ||
44 | return in, nil | ||
45 | } | ||
46 | |||
47 | conv := GetConversionUnsafe(in.Type(), want) | ||
48 | if conv == nil { | ||
49 | return cty.NilVal, fmt.Errorf("incorrect type; %s required", want.FriendlyName()) | ||
50 | } | ||
51 | return conv(in) | ||
52 | } | ||
53 | |||
54 | // Unify attempts to find the most general type that can be converted from | ||
55 | // all of the given types. If this is possible, that type is returned along | ||
56 | // with a slice of necessary conversions for some of the given types. | ||
57 | // | ||
58 | // If no common supertype can be found, this function returns cty.NilType and | ||
59 | // a nil slice. | ||
60 | // | ||
61 | // If a common supertype *can* be found, the returned slice will always be | ||
62 | // non-nil and will contain a non-nil conversion for each given type that | ||
63 | // needs to be converted, with indices corresponding to the input slice. | ||
64 | // Any given type that does *not* need conversion (because it is already of | ||
65 | // the appropriate type) will have a nil Conversion. | ||
66 | // | ||
67 | // cty.DynamicPseudoType is, as usual, a special case. If the given type list | ||
68 | // contains a mixture of dynamic and non-dynamic types, the dynamic types are | ||
69 | // disregarded for type selection and a conversion is returned for them that | ||
70 | // will attempt a late conversion of the given value to the target type, | ||
71 | // failing with a conversion error if the eventual concrete type is not | ||
72 | // compatible. If *all* given types are DynamicPseudoType, or in the | ||
73 | // degenerate case of an empty slice of types, the returned type is itself | ||
74 | // cty.DynamicPseudoType and no conversions are attempted. | ||
75 | func Unify(types []cty.Type) (cty.Type, []Conversion) { | ||
76 | return unify(types, false) | ||
77 | } | ||
78 | |||
79 | // UnifyUnsafe is the same as Unify except that it may return unsafe | ||
80 | // conversions in situations where a safe conversion isn't also available. | ||
81 | func UnifyUnsafe(types []cty.Type) (cty.Type, []Conversion) { | ||
82 | return unify(types, true) | ||
83 | } | ||
diff --git a/vendor/github.com/zclconf/go-cty/cty/convert/sort_types.go b/vendor/github.com/zclconf/go-cty/cty/convert/sort_types.go new file mode 100644 index 0000000..b776910 --- /dev/null +++ b/vendor/github.com/zclconf/go-cty/cty/convert/sort_types.go | |||
@@ -0,0 +1,69 @@ | |||
1 | package convert | ||
2 | |||
3 | import ( | ||
4 | "github.com/zclconf/go-cty/cty" | ||
5 | ) | ||
6 | |||
7 | // sortTypes produces an ordering of the given types that serves as a | ||
8 | // preference order for the result of unification of the given types. | ||
9 | // The return value is a slice of indices into the given slice, and will | ||
10 | // thus always be the same length as the given slice. | ||
11 | // | ||
12 | // The goal is that the most general of the given types will appear first | ||
13 | // in the ordering. If there are uncomparable pairs of types in the list | ||
14 | // then they will appear in an undefined order, and the unification pass | ||
15 | // will presumably then fail. | ||
16 | func sortTypes(tys []cty.Type) []int { | ||
17 | l := len(tys) | ||
18 | |||
19 | // First we build a graph whose edges represent "more general than", | ||
20 | // which we will then do a topological sort of. | ||
21 | edges := make([][]int, l) | ||
22 | for i := 0; i < (l - 1); i++ { | ||
23 | for j := i + 1; j < l; j++ { | ||
24 | cmp := compareTypes(tys[i], tys[j]) | ||
25 | switch { | ||
26 | case cmp < 0: | ||
27 | edges[i] = append(edges[i], j) | ||
28 | case cmp > 0: | ||
29 | edges[j] = append(edges[j], i) | ||
30 | } | ||
31 | } | ||
32 | } | ||
33 | |||
34 | // Compute the in-degree of each node | ||
35 | inDegree := make([]int, l) | ||
36 | for _, outs := range edges { | ||
37 | for _, j := range outs { | ||
38 | inDegree[j]++ | ||
39 | } | ||
40 | } | ||
41 | |||
42 | // The array backing our result will double as our queue for visiting | ||
43 | // the nodes, with the queue slice moving along this array until it | ||
44 | // is empty and positioned at the end of the array. Thus our visiting | ||
45 | // order is also our result order. | ||
46 | result := make([]int, l) | ||
47 | queue := result[0:0] | ||
48 | |||
49 | // Initialize the queue with any item of in-degree 0, preserving | ||
50 | // their relative order. | ||
51 | for i, n := range inDegree { | ||
52 | if n == 0 { | ||
53 | queue = append(queue, i) | ||
54 | } | ||
55 | } | ||
56 | |||
57 | for len(queue) != 0 { | ||
58 | i := queue[0] | ||
59 | queue = queue[1:] | ||
60 | for _, j := range edges[i] { | ||
61 | inDegree[j]-- | ||
62 | if inDegree[j] == 0 { | ||
63 | queue = append(queue, j) | ||
64 | } | ||
65 | } | ||
66 | } | ||
67 | |||
68 | return result | ||
69 | } | ||
diff --git a/vendor/github.com/zclconf/go-cty/cty/convert/unify.go b/vendor/github.com/zclconf/go-cty/cty/convert/unify.go new file mode 100644 index 0000000..bd6736b --- /dev/null +++ b/vendor/github.com/zclconf/go-cty/cty/convert/unify.go | |||
@@ -0,0 +1,66 @@ | |||
1 | package convert | ||
2 | |||
3 | import ( | ||
4 | "github.com/zclconf/go-cty/cty" | ||
5 | ) | ||
6 | |||
7 | // The current unify implementation is somewhat inefficient, but we accept this | ||
8 | // under the assumption that it will generally be used with small numbers of | ||
9 | // types and with types of reasonable complexity. However, it does have a | ||
10 | // "happy path" where all of the given types are equal. | ||
11 | // | ||
12 | // This function is likely to have poor performance in cases where any given | ||
13 | // types are very complex (lots of deeply-nested structures) or if the list | ||
14 | // of types itself is very large. In particular, it will walk the nested type | ||
15 | // structure under the given types several times, especially when given a | ||
16 | // list of types for which unification is not possible, since each permutation | ||
17 | // will be tried to determine that result. | ||
18 | func unify(types []cty.Type, unsafe bool) (cty.Type, []Conversion) { | ||
19 | if len(types) == 0 { | ||
20 | // Degenerate case | ||
21 | return cty.NilType, nil | ||
22 | } | ||
23 | |||
24 | prefOrder := sortTypes(types) | ||
25 | |||
26 | // sortTypes gives us an order where earlier items are preferable as | ||
27 | // our result type. We'll now walk through these and choose the first | ||
28 | // one we encounter for which conversions exist for all source types. | ||
29 | conversions := make([]Conversion, len(types)) | ||
30 | Preferences: | ||
31 | for _, wantTypeIdx := range prefOrder { | ||
32 | wantType := types[wantTypeIdx] | ||
33 | for i, tryType := range types { | ||
34 | if i == wantTypeIdx { | ||
35 | // Don't need to convert our wanted type to itself | ||
36 | conversions[i] = nil | ||
37 | continue | ||
38 | } | ||
39 | |||
40 | if tryType.Equals(wantType) { | ||
41 | conversions[i] = nil | ||
42 | continue | ||
43 | } | ||
44 | |||
45 | if unsafe { | ||
46 | conversions[i] = GetConversionUnsafe(tryType, wantType) | ||
47 | } else { | ||
48 | conversions[i] = GetConversion(tryType, wantType) | ||
49 | } | ||
50 | |||
51 | if conversions[i] == nil { | ||
52 | // wantType is not a suitable unification type, so we'll | ||
53 | // try the next one in our preference order. | ||
54 | continue Preferences | ||
55 | } | ||
56 | } | ||
57 | |||
58 | return wantType, conversions | ||
59 | } | ||
60 | |||
61 | // TODO: For structural types, try to invent a new type that they | ||
62 | // can all be unified to, by unifying their respective attributes. | ||
63 | |||
64 | // If we fall out here, no unification is possible | ||
65 | return cty.NilType, nil | ||
66 | } | ||