diff options
Diffstat (limited to 'vendor/github.com/zclconf/go-cty')
72 files changed, 10496 insertions, 0 deletions
diff --git a/vendor/github.com/zclconf/go-cty/LICENSE b/vendor/github.com/zclconf/go-cty/LICENSE new file mode 100644 index 0000000..d6503b5 --- /dev/null +++ b/vendor/github.com/zclconf/go-cty/LICENSE | |||
@@ -0,0 +1,21 @@ | |||
1 | MIT License | ||
2 | |||
3 | Copyright (c) 2017-2018 Martin Atkins | ||
4 | |||
5 | Permission is hereby granted, free of charge, to any person obtaining a copy | ||
6 | of this software and associated documentation files (the "Software"), to deal | ||
7 | in the Software without restriction, including without limitation the rights | ||
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
9 | copies of the Software, and to permit persons to whom the Software is | ||
10 | furnished to do so, subject to the following conditions: | ||
11 | |||
12 | The above copyright notice and this permission notice shall be included in all | ||
13 | copies or substantial portions of the Software. | ||
14 | |||
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||
21 | SOFTWARE. | ||
diff --git a/vendor/github.com/zclconf/go-cty/cty/capsule.go b/vendor/github.com/zclconf/go-cty/cty/capsule.go new file mode 100644 index 0000000..4fce92a --- /dev/null +++ b/vendor/github.com/zclconf/go-cty/cty/capsule.go | |||
@@ -0,0 +1,89 @@ | |||
1 | package cty | ||
2 | |||
3 | import ( | ||
4 | "fmt" | ||
5 | "reflect" | ||
6 | ) | ||
7 | |||
8 | type capsuleType struct { | ||
9 | typeImplSigil | ||
10 | Name string | ||
11 | GoType reflect.Type | ||
12 | } | ||
13 | |||
14 | func (t *capsuleType) Equals(other Type) bool { | ||
15 | if otherP, ok := other.typeImpl.(*capsuleType); ok { | ||
16 | // capsule types compare by pointer identity | ||
17 | return otherP == t | ||
18 | } | ||
19 | return false | ||
20 | } | ||
21 | |||
22 | func (t *capsuleType) FriendlyName() string { | ||
23 | return t.Name | ||
24 | } | ||
25 | |||
26 | func (t *capsuleType) GoString() string { | ||
27 | // To get a useful representation of our native type requires some | ||
28 | // shenanigans. | ||
29 | victimVal := reflect.Zero(t.GoType) | ||
30 | return fmt.Sprintf("cty.Capsule(%q, reflect.TypeOf(%#v))", t.Name, victimVal.Interface()) | ||
31 | } | ||
32 | |||
33 | // Capsule creates a new Capsule type. | ||
34 | // | ||
35 | // A Capsule type is a special type that can be used to transport arbitrary | ||
36 | // Go native values of a given type through the cty type system. A language | ||
37 | // that uses cty as its type system might, for example, provide functions | ||
38 | // that return capsule-typed values and then other functions that operate | ||
39 | // on those values. | ||
40 | // | ||
41 | // From cty's perspective, Capsule types have a few interesting characteristics, | ||
42 | // described in the following paragraphs. | ||
43 | // | ||
44 | // Each capsule type has an associated Go native type that it is able to | ||
45 | // transport. Capsule types compare by identity, so each call to the | ||
46 | // Capsule function creates an entirely-distinct cty Type, even if two calls | ||
47 | // use the same native type. | ||
48 | // | ||
49 | // Each capsule-typed value contains a pointer to a value of the given native | ||
50 | // type. A capsule-typed value supports no operations except equality, and | ||
51 | // equality is implemented by pointer identity of the encapsulated pointer. | ||
52 | // | ||
53 | // The given name is used as the new type's "friendly name". This can be any | ||
54 | // string in principle, but will usually be a short, all-lowercase name aimed | ||
55 | // at users of the embedding language (i.e. not mention Go-specific details) | ||
56 | // and will ideally not create ambiguity with any predefined cty type. | ||
57 | // | ||
58 | // Capsule types are never introduced by any standard cty operation, so a | ||
59 | // calling application opts in to including them within its own type system | ||
60 | // by creating them and introducing them via its own functions. At that point, | ||
61 | // the application is responsible for dealing with any capsule-typed values | ||
62 | // that might be returned. | ||
63 | func Capsule(name string, nativeType reflect.Type) Type { | ||
64 | return Type{ | ||
65 | &capsuleType{ | ||
66 | Name: name, | ||
67 | GoType: nativeType, | ||
68 | }, | ||
69 | } | ||
70 | } | ||
71 | |||
72 | // IsCapsuleType returns true if this type is a capsule type, as created | ||
73 | // by cty.Capsule . | ||
74 | func (t Type) IsCapsuleType() bool { | ||
75 | _, ok := t.typeImpl.(*capsuleType) | ||
76 | return ok | ||
77 | } | ||
78 | |||
79 | // EncapsulatedType returns the encapsulated native type of a capsule type, | ||
80 | // or panics if the receiver is not a Capsule type. | ||
81 | // | ||
82 | // Is IsCapsuleType to determine if this method is safe to call. | ||
83 | func (t Type) EncapsulatedType() reflect.Type { | ||
84 | impl, ok := t.typeImpl.(*capsuleType) | ||
85 | if !ok { | ||
86 | panic("not a capsule type") | ||
87 | } | ||
88 | return impl.GoType | ||
89 | } | ||
diff --git a/vendor/github.com/zclconf/go-cty/cty/collection.go b/vendor/github.com/zclconf/go-cty/cty/collection.go new file mode 100644 index 0000000..ab3919b --- /dev/null +++ b/vendor/github.com/zclconf/go-cty/cty/collection.go | |||
@@ -0,0 +1,34 @@ | |||
1 | package cty | ||
2 | |||
3 | import ( | ||
4 | "errors" | ||
5 | ) | ||
6 | |||
7 | type collectionTypeImpl interface { | ||
8 | ElementType() Type | ||
9 | } | ||
10 | |||
11 | // IsCollectionType returns true if the given type supports the operations | ||
12 | // that are defined for all collection types. | ||
13 | func (t Type) IsCollectionType() bool { | ||
14 | _, ok := t.typeImpl.(collectionTypeImpl) | ||
15 | return ok | ||
16 | } | ||
17 | |||
18 | // ElementType returns the element type of the receiver if it is a collection | ||
19 | // type, or panics if it is not. Use IsCollectionType first to test whether | ||
20 | // this method will succeed. | ||
21 | func (t Type) ElementType() Type { | ||
22 | if ct, ok := t.typeImpl.(collectionTypeImpl); ok { | ||
23 | return ct.ElementType() | ||
24 | } | ||
25 | panic(errors.New("not a collection type")) | ||
26 | } | ||
27 | |||
28 | // ElementCallback is a callback type used for iterating over elements of | ||
29 | // collections and attributes of objects. | ||
30 | // | ||
31 | // The types of key and value depend on what type is being iterated over. | ||
32 | // Return true to stop iterating after the current element, or false to | ||
33 | // continue iterating. | ||
34 | type ElementCallback func(key Value, val Value) (stop bool) | ||
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 | } | ||
diff --git a/vendor/github.com/zclconf/go-cty/cty/doc.go b/vendor/github.com/zclconf/go-cty/cty/doc.go new file mode 100644 index 0000000..d31f054 --- /dev/null +++ b/vendor/github.com/zclconf/go-cty/cty/doc.go | |||
@@ -0,0 +1,18 @@ | |||
1 | // Package cty (pronounced see-tie) provides some infrastructure for a type | ||
2 | // system that might be useful for applications that need to represent | ||
3 | // configuration values provided by the user whose types are not known | ||
4 | // at compile time, particularly if the calling application also allows | ||
5 | // such values to be used in expressions. | ||
6 | // | ||
7 | // The type system consists of primitive types Number, String and Bool, as | ||
8 | // well as List and Map collection types and Object types that can have | ||
9 | // arbitrarily-typed sets of attributes. | ||
10 | // | ||
11 | // A set of operations is defined on these types, which is accessible via | ||
12 | // the wrapper struct Value, which annotates the raw, internal representation | ||
13 | // of a value with its corresponding type. | ||
14 | // | ||
15 | // This package is oriented towards being a building block for configuration | ||
16 | // languages used to bootstrap an application. It is not optimized for use | ||
17 | // in tight loops where CPU time or memory pressure are a concern. | ||
18 | package cty | ||
diff --git a/vendor/github.com/zclconf/go-cty/cty/element_iterator.go b/vendor/github.com/zclconf/go-cty/cty/element_iterator.go new file mode 100644 index 0000000..0bf84c7 --- /dev/null +++ b/vendor/github.com/zclconf/go-cty/cty/element_iterator.go | |||
@@ -0,0 +1,191 @@ | |||
1 | package cty | ||
2 | |||
3 | import ( | ||
4 | "sort" | ||
5 | |||
6 | "github.com/zclconf/go-cty/cty/set" | ||
7 | ) | ||
8 | |||
9 | // ElementIterator is the interface type returned by Value.ElementIterator to | ||
10 | // allow the caller to iterate over elements of a collection-typed value. | ||
11 | // | ||
12 | // Its usage pattern is as follows: | ||
13 | // | ||
14 | // it := val.ElementIterator() | ||
15 | // for it.Next() { | ||
16 | // key, val := it.Element() | ||
17 | // // ... | ||
18 | // } | ||
19 | type ElementIterator interface { | ||
20 | Next() bool | ||
21 | Element() (key Value, value Value) | ||
22 | } | ||
23 | |||
24 | func canElementIterator(val Value) bool { | ||
25 | switch { | ||
26 | case val.ty.IsListType(): | ||
27 | return true | ||
28 | case val.ty.IsMapType(): | ||
29 | return true | ||
30 | case val.ty.IsSetType(): | ||
31 | return true | ||
32 | case val.ty.IsTupleType(): | ||
33 | return true | ||
34 | case val.ty.IsObjectType(): | ||
35 | return true | ||
36 | default: | ||
37 | return false | ||
38 | } | ||
39 | } | ||
40 | |||
41 | func elementIterator(val Value) ElementIterator { | ||
42 | switch { | ||
43 | case val.ty.IsListType(): | ||
44 | return &listElementIterator{ | ||
45 | ety: val.ty.ElementType(), | ||
46 | vals: val.v.([]interface{}), | ||
47 | idx: -1, | ||
48 | } | ||
49 | case val.ty.IsMapType(): | ||
50 | // We iterate the keys in a predictable lexicographical order so | ||
51 | // that results will always be stable given the same input map. | ||
52 | rawMap := val.v.(map[string]interface{}) | ||
53 | keys := make([]string, 0, len(rawMap)) | ||
54 | for key := range rawMap { | ||
55 | keys = append(keys, key) | ||
56 | } | ||
57 | sort.Strings(keys) | ||
58 | |||
59 | return &mapElementIterator{ | ||
60 | ety: val.ty.ElementType(), | ||
61 | vals: rawMap, | ||
62 | keys: keys, | ||
63 | idx: -1, | ||
64 | } | ||
65 | case val.ty.IsSetType(): | ||
66 | rawSet := val.v.(set.Set) | ||
67 | return &setElementIterator{ | ||
68 | ety: val.ty.ElementType(), | ||
69 | setIt: rawSet.Iterator(), | ||
70 | } | ||
71 | case val.ty.IsTupleType(): | ||
72 | return &tupleElementIterator{ | ||
73 | etys: val.ty.TupleElementTypes(), | ||
74 | vals: val.v.([]interface{}), | ||
75 | idx: -1, | ||
76 | } | ||
77 | case val.ty.IsObjectType(): | ||
78 | // We iterate the keys in a predictable lexicographical order so | ||
79 | // that results will always be stable given the same object type. | ||
80 | atys := val.ty.AttributeTypes() | ||
81 | keys := make([]string, 0, len(atys)) | ||
82 | for key := range atys { | ||
83 | keys = append(keys, key) | ||
84 | } | ||
85 | sort.Strings(keys) | ||
86 | |||
87 | return &objectElementIterator{ | ||
88 | atys: atys, | ||
89 | vals: val.v.(map[string]interface{}), | ||
90 | attrNames: keys, | ||
91 | idx: -1, | ||
92 | } | ||
93 | default: | ||
94 | panic("attempt to iterate on non-collection, non-tuple type") | ||
95 | } | ||
96 | } | ||
97 | |||
98 | type listElementIterator struct { | ||
99 | ety Type | ||
100 | vals []interface{} | ||
101 | idx int | ||
102 | } | ||
103 | |||
104 | func (it *listElementIterator) Element() (Value, Value) { | ||
105 | i := it.idx | ||
106 | return NumberIntVal(int64(i)), Value{ | ||
107 | ty: it.ety, | ||
108 | v: it.vals[i], | ||
109 | } | ||
110 | } | ||
111 | |||
112 | func (it *listElementIterator) Next() bool { | ||
113 | it.idx++ | ||
114 | return it.idx < len(it.vals) | ||
115 | } | ||
116 | |||
117 | type mapElementIterator struct { | ||
118 | ety Type | ||
119 | vals map[string]interface{} | ||
120 | keys []string | ||
121 | idx int | ||
122 | } | ||
123 | |||
124 | func (it *mapElementIterator) Element() (Value, Value) { | ||
125 | key := it.keys[it.idx] | ||
126 | return StringVal(key), Value{ | ||
127 | ty: it.ety, | ||
128 | v: it.vals[key], | ||
129 | } | ||
130 | } | ||
131 | |||
132 | func (it *mapElementIterator) Next() bool { | ||
133 | it.idx++ | ||
134 | return it.idx < len(it.keys) | ||
135 | } | ||
136 | |||
137 | type setElementIterator struct { | ||
138 | ety Type | ||
139 | setIt *set.Iterator | ||
140 | } | ||
141 | |||
142 | func (it *setElementIterator) Element() (Value, Value) { | ||
143 | val := Value{ | ||
144 | ty: it.ety, | ||
145 | v: it.setIt.Value(), | ||
146 | } | ||
147 | return val, val | ||
148 | } | ||
149 | |||
150 | func (it *setElementIterator) Next() bool { | ||
151 | return it.setIt.Next() | ||
152 | } | ||
153 | |||
154 | type tupleElementIterator struct { | ||
155 | etys []Type | ||
156 | vals []interface{} | ||
157 | idx int | ||
158 | } | ||
159 | |||
160 | func (it *tupleElementIterator) Element() (Value, Value) { | ||
161 | i := it.idx | ||
162 | return NumberIntVal(int64(i)), Value{ | ||
163 | ty: it.etys[i], | ||
164 | v: it.vals[i], | ||
165 | } | ||
166 | } | ||
167 | |||
168 | func (it *tupleElementIterator) Next() bool { | ||
169 | it.idx++ | ||
170 | return it.idx < len(it.vals) | ||
171 | } | ||
172 | |||
173 | type objectElementIterator struct { | ||
174 | atys map[string]Type | ||
175 | vals map[string]interface{} | ||
176 | attrNames []string | ||
177 | idx int | ||
178 | } | ||
179 | |||
180 | func (it *objectElementIterator) Element() (Value, Value) { | ||
181 | key := it.attrNames[it.idx] | ||
182 | return StringVal(key), Value{ | ||
183 | ty: it.atys[key], | ||
184 | v: it.vals[key], | ||
185 | } | ||
186 | } | ||
187 | |||
188 | func (it *objectElementIterator) Next() bool { | ||
189 | it.idx++ | ||
190 | return it.idx < len(it.attrNames) | ||
191 | } | ||
diff --git a/vendor/github.com/zclconf/go-cty/cty/error.go b/vendor/github.com/zclconf/go-cty/cty/error.go new file mode 100644 index 0000000..dd139f7 --- /dev/null +++ b/vendor/github.com/zclconf/go-cty/cty/error.go | |||
@@ -0,0 +1,55 @@ | |||
1 | package cty | ||
2 | |||
3 | import ( | ||
4 | "fmt" | ||
5 | ) | ||
6 | |||
7 | // PathError is a specialization of error that represents where in a | ||
8 | // potentially-deep data structure an error occured, using a Path. | ||
9 | type PathError struct { | ||
10 | error | ||
11 | Path Path | ||
12 | } | ||
13 | |||
14 | func errorf(path Path, f string, args ...interface{}) error { | ||
15 | // We need to copy the Path because often our caller builds it by | ||
16 | // continually mutating the same underlying buffer. | ||
17 | sPath := make(Path, len(path)) | ||
18 | copy(sPath, path) | ||
19 | return PathError{ | ||
20 | error: fmt.Errorf(f, args...), | ||
21 | Path: sPath, | ||
22 | } | ||
23 | } | ||
24 | |||
25 | // NewErrorf creates a new PathError for the current path by passing the | ||
26 | // given format and arguments to fmt.Errorf and then wrapping the result | ||
27 | // similarly to NewError. | ||
28 | func (p Path) NewErrorf(f string, args ...interface{}) error { | ||
29 | return errorf(p, f, args...) | ||
30 | } | ||
31 | |||
32 | // NewError creates a new PathError for the current path, wrapping the given | ||
33 | // error. | ||
34 | func (p Path) NewError(err error) error { | ||
35 | // if we're being asked to wrap an existing PathError then our new | ||
36 | // PathError will be the concatenation of the two paths, ensuring | ||
37 | // that we still get a single flat PathError that's thus easier for | ||
38 | // callers to deal with. | ||
39 | perr, wrappingPath := err.(PathError) | ||
40 | pathLen := len(p) | ||
41 | if wrappingPath { | ||
42 | pathLen = pathLen + len(perr.Path) | ||
43 | } | ||
44 | |||
45 | sPath := make(Path, pathLen) | ||
46 | copy(sPath, p) | ||
47 | if wrappingPath { | ||
48 | copy(sPath[len(p):], perr.Path) | ||
49 | } | ||
50 | |||
51 | return PathError{ | ||
52 | error: err, | ||
53 | Path: sPath, | ||
54 | } | ||
55 | } | ||
diff --git a/vendor/github.com/zclconf/go-cty/cty/function/argument.go b/vendor/github.com/zclconf/go-cty/cty/function/argument.go new file mode 100644 index 0000000..bfd3015 --- /dev/null +++ b/vendor/github.com/zclconf/go-cty/cty/function/argument.go | |||
@@ -0,0 +1,50 @@ | |||
1 | package function | ||
2 | |||
3 | import ( | ||
4 | "github.com/zclconf/go-cty/cty" | ||
5 | ) | ||
6 | |||
7 | // Parameter represents a parameter to a function. | ||
8 | type Parameter struct { | ||
9 | // Name is an optional name for the argument. This package ignores this | ||
10 | // value, but callers may use it for documentation, etc. | ||
11 | Name string | ||
12 | |||
13 | // A type that any argument for this parameter must conform to. | ||
14 | // cty.DynamicPseudoType can be used, either at top-level or nested | ||
15 | // in a parameterized type, to indicate that any type should be | ||
16 | // permitted, to allow the definition of type-generic functions. | ||
17 | Type cty.Type | ||
18 | |||
19 | // If AllowNull is set then null values may be passed into this | ||
20 | // argument's slot in both the type-check function and the implementation | ||
21 | // function. If not set, such values are rejected by the built-in | ||
22 | // checking rules. | ||
23 | AllowNull bool | ||
24 | |||
25 | // If AllowUnknown is set then unknown values may be passed into this | ||
26 | // argument's slot in the implementation function. If not set, any | ||
27 | // unknown values will cause the function to immediately return | ||
28 | // an unkonwn value without calling the implementation function, thus | ||
29 | // freeing the function implementer from dealing with this case. | ||
30 | AllowUnknown bool | ||
31 | |||
32 | // If AllowDynamicType is set then DynamicVal may be passed into this | ||
33 | // argument's slot in the implementation function. If not set, any | ||
34 | // dynamic values will cause the function to immediately return | ||
35 | // DynamicVal value without calling the implementation function, thus | ||
36 | // freeing the function implementer from dealing with this case. | ||
37 | // | ||
38 | // Note that DynamicVal is also unknown, so in order to receive dynamic | ||
39 | // *values* it is also necessary to set AllowUnknown. | ||
40 | // | ||
41 | // However, it is valid to set AllowDynamicType without AllowUnknown, in | ||
42 | // which case a dynamic value may be passed to the type checking function | ||
43 | // but will not make it to the *implementation* function. Instead, an | ||
44 | // unknown value of the type returned by the type-check function will be | ||
45 | // returned. This is suggested for functions that have a static return | ||
46 | // type since it allows the return value to be typed even if the input | ||
47 | // values are not, thus improving the type-check accuracy of derived | ||
48 | // values. | ||
49 | AllowDynamicType bool | ||
50 | } | ||
diff --git a/vendor/github.com/zclconf/go-cty/cty/function/doc.go b/vendor/github.com/zclconf/go-cty/cty/function/doc.go new file mode 100644 index 0000000..393b311 --- /dev/null +++ b/vendor/github.com/zclconf/go-cty/cty/function/doc.go | |||
@@ -0,0 +1,6 @@ | |||
1 | // Package function builds on the functionality of cty by modeling functions | ||
2 | // that operate on cty Values. | ||
3 | // | ||
4 | // Functions are, at their core, Go anonymous functions. However, this package | ||
5 | // wraps around them utility functions for parameter type checking, etc. | ||
6 | package function | ||
diff --git a/vendor/github.com/zclconf/go-cty/cty/function/error.go b/vendor/github.com/zclconf/go-cty/cty/function/error.go new file mode 100644 index 0000000..2b56779 --- /dev/null +++ b/vendor/github.com/zclconf/go-cty/cty/function/error.go | |||
@@ -0,0 +1,50 @@ | |||
1 | package function | ||
2 | |||
3 | import ( | ||
4 | "fmt" | ||
5 | "runtime/debug" | ||
6 | ) | ||
7 | |||
8 | // ArgError represents an error with one of the arguments in a call. The | ||
9 | // attribute Index represents the zero-based index of the argument in question. | ||
10 | // | ||
11 | // Its error *may* be a cty.PathError, in which case the error actually | ||
12 | // pertains to a nested value within the data structure passed as the argument. | ||
13 | type ArgError struct { | ||
14 | error | ||
15 | Index int | ||
16 | } | ||
17 | |||
18 | func NewArgErrorf(i int, f string, args ...interface{}) error { | ||
19 | return ArgError{ | ||
20 | error: fmt.Errorf(f, args...), | ||
21 | Index: i, | ||
22 | } | ||
23 | } | ||
24 | |||
25 | func NewArgError(i int, err error) error { | ||
26 | return ArgError{ | ||
27 | error: err, | ||
28 | Index: i, | ||
29 | } | ||
30 | } | ||
31 | |||
32 | // PanicError indicates that a panic occurred while executing either a | ||
33 | // function's type or implementation function. This is captured and wrapped | ||
34 | // into a normal error so that callers (expected to be language runtimes) | ||
35 | // are freed from having to deal with panics in buggy functions. | ||
36 | type PanicError struct { | ||
37 | Value interface{} | ||
38 | Stack []byte | ||
39 | } | ||
40 | |||
41 | func errorForPanic(val interface{}) error { | ||
42 | return PanicError{ | ||
43 | Value: val, | ||
44 | Stack: debug.Stack(), | ||
45 | } | ||
46 | } | ||
47 | |||
48 | func (e PanicError) Error() string { | ||
49 | return fmt.Sprintf("panic in function implementation: %s\n%s", e.Value, e.Stack) | ||
50 | } | ||
diff --git a/vendor/github.com/zclconf/go-cty/cty/function/function.go b/vendor/github.com/zclconf/go-cty/cty/function/function.go new file mode 100644 index 0000000..162f7bf --- /dev/null +++ b/vendor/github.com/zclconf/go-cty/cty/function/function.go | |||
@@ -0,0 +1,291 @@ | |||
1 | package function | ||
2 | |||
3 | import ( | ||
4 | "fmt" | ||
5 | |||
6 | "github.com/zclconf/go-cty/cty" | ||
7 | ) | ||
8 | |||
9 | // Function represents a function. This is the main type in this package. | ||
10 | type Function struct { | ||
11 | spec *Spec | ||
12 | } | ||
13 | |||
14 | // Spec is the specification of a function, used to instantiate | ||
15 | // a new Function. | ||
16 | type Spec struct { | ||
17 | // Params is a description of the positional parameters for the function. | ||
18 | // The standard checking logic rejects any calls that do not provide | ||
19 | // arguments conforming to this definition, freeing the function | ||
20 | // implementer from dealing with such inconsistencies. | ||
21 | Params []Parameter | ||
22 | |||
23 | // VarParam is an optional specification of additional "varargs" the | ||
24 | // function accepts. If this is non-nil then callers may provide an | ||
25 | // arbitrary number of additional arguments (after those matching with | ||
26 | // the fixed parameters in Params) that conform to the given specification, | ||
27 | // which will appear as additional values in the slices of values | ||
28 | // provided to the type and implementation functions. | ||
29 | VarParam *Parameter | ||
30 | |||
31 | // Type is the TypeFunc that decides the return type of the function | ||
32 | // given its arguments, which may be Unknown. See the documentation | ||
33 | // of TypeFunc for more information. | ||
34 | // | ||
35 | // Use StaticReturnType if the function's return type does not vary | ||
36 | // depending on its arguments. | ||
37 | Type TypeFunc | ||
38 | |||
39 | // Impl is the ImplFunc that implements the function's behavior. | ||
40 | // | ||
41 | // Functions are expected to behave as pure functions, and not create | ||
42 | // any visible side-effects. | ||
43 | // | ||
44 | // If a TypeFunc is also provided, the value returned from Impl *must* | ||
45 | // conform to the type it returns, or a call to the function will panic. | ||
46 | Impl ImplFunc | ||
47 | } | ||
48 | |||
49 | // New creates a new function with the given specification. | ||
50 | // | ||
51 | // After passing a Spec to this function, the caller must no longer read from | ||
52 | // or mutate it. | ||
53 | func New(spec *Spec) Function { | ||
54 | f := Function{ | ||
55 | spec: spec, | ||
56 | } | ||
57 | return f | ||
58 | } | ||
59 | |||
60 | // TypeFunc is a callback type for determining the return type of a function | ||
61 | // given its arguments. | ||
62 | // | ||
63 | // Any of the values passed to this function may be unknown, even if the | ||
64 | // parameters are not configured to accept unknowns. | ||
65 | // | ||
66 | // If any of the given values are *not* unknown, the TypeFunc may use the | ||
67 | // values for pre-validation and for choosing the return type. For example, | ||
68 | // a hypothetical JSON-unmarshalling function could return | ||
69 | // cty.DynamicPseudoType if the given JSON string is unknown, but return | ||
70 | // a concrete type based on the JSON structure if the JSON string is already | ||
71 | // known. | ||
72 | type TypeFunc func(args []cty.Value) (cty.Type, error) | ||
73 | |||
74 | // ImplFunc is a callback type for the main implementation of a function. | ||
75 | // | ||
76 | // "args" are the values for the arguments, and this slice will always be at | ||
77 | // least as long as the argument definition slice for the function. | ||
78 | // | ||
79 | // "retType" is the type returned from the Type callback, included as a | ||
80 | // convenience to avoid the need to re-compute the return type for generic | ||
81 | // functions whose return type is a function of the arguments. | ||
82 | type ImplFunc func(args []cty.Value, retType cty.Type) (cty.Value, error) | ||
83 | |||
84 | // StaticReturnType returns a TypeFunc that always returns the given type. | ||
85 | // | ||
86 | // This is provided as a convenience for defining a function whose return | ||
87 | // type does not depend on the argument types. | ||
88 | func StaticReturnType(ty cty.Type) TypeFunc { | ||
89 | return func([]cty.Value) (cty.Type, error) { | ||
90 | return ty, nil | ||
91 | } | ||
92 | } | ||
93 | |||
94 | // ReturnType returns the return type of a function given a set of candidate | ||
95 | // argument types, or returns an error if the given types are unacceptable. | ||
96 | // | ||
97 | // If the caller already knows values for at least some of the arguments | ||
98 | // it can be better to call ReturnTypeForValues, since certain functions may | ||
99 | // determine their return types from their values and return DynamicVal if | ||
100 | // the values are unknown. | ||
101 | func (f Function) ReturnType(argTypes []cty.Type) (cty.Type, error) { | ||
102 | vals := make([]cty.Value, len(argTypes)) | ||
103 | for i, ty := range argTypes { | ||
104 | vals[i] = cty.UnknownVal(ty) | ||
105 | } | ||
106 | return f.ReturnTypeForValues(vals) | ||
107 | } | ||
108 | |||
109 | // ReturnTypeForValues is similar to ReturnType but can be used if the caller | ||
110 | // already knows the values of some or all of the arguments, in which case | ||
111 | // the function may be able to determine a more definite result if its | ||
112 | // return type depends on the argument *values*. | ||
113 | // | ||
114 | // For any arguments whose values are not known, pass an Unknown value of | ||
115 | // the appropriate type. | ||
116 | func (f Function) ReturnTypeForValues(args []cty.Value) (ty cty.Type, err error) { | ||
117 | var posArgs []cty.Value | ||
118 | var varArgs []cty.Value | ||
119 | |||
120 | if f.spec.VarParam == nil { | ||
121 | if len(args) != len(f.spec.Params) { | ||
122 | return cty.Type{}, fmt.Errorf( | ||
123 | "wrong number of arguments (%d required; %d given)", | ||
124 | len(f.spec.Params), len(args), | ||
125 | ) | ||
126 | } | ||
127 | |||
128 | posArgs = args | ||
129 | varArgs = nil | ||
130 | } else { | ||
131 | if len(args) < len(f.spec.Params) { | ||
132 | return cty.Type{}, fmt.Errorf( | ||
133 | "wrong number of arguments (at least %d required; %d given)", | ||
134 | len(f.spec.Params), len(args), | ||
135 | ) | ||
136 | } | ||
137 | |||
138 | posArgs = args[0:len(f.spec.Params)] | ||
139 | varArgs = args[len(f.spec.Params):] | ||
140 | } | ||
141 | |||
142 | for i, spec := range f.spec.Params { | ||
143 | val := posArgs[i] | ||
144 | |||
145 | if val.IsNull() && !spec.AllowNull { | ||
146 | return cty.Type{}, NewArgErrorf(i, "must not be null") | ||
147 | } | ||
148 | |||
149 | // AllowUnknown is ignored for type-checking, since we expect to be | ||
150 | // able to type check with unknown values. We *do* still need to deal | ||
151 | // with DynamicPseudoType here though, since the Type function might | ||
152 | // not be ready to deal with that. | ||
153 | |||
154 | if val.Type() == cty.DynamicPseudoType { | ||
155 | if !spec.AllowDynamicType { | ||
156 | return cty.DynamicPseudoType, nil | ||
157 | } | ||
158 | } else if errs := val.Type().TestConformance(spec.Type); errs != nil { | ||
159 | // For now we'll just return the first error in the set, since | ||
160 | // we don't have a good way to return the whole list here. | ||
161 | // Would be good to do something better at some point... | ||
162 | return cty.Type{}, NewArgError(i, errs[0]) | ||
163 | } | ||
164 | } | ||
165 | |||
166 | if varArgs != nil { | ||
167 | spec := f.spec.VarParam | ||
168 | for i, val := range varArgs { | ||
169 | realI := i + len(posArgs) | ||
170 | |||
171 | if val.IsNull() && !spec.AllowNull { | ||
172 | return cty.Type{}, NewArgErrorf(realI, "must not be null") | ||
173 | } | ||
174 | |||
175 | if val.Type() == cty.DynamicPseudoType { | ||
176 | if !spec.AllowDynamicType { | ||
177 | return cty.DynamicPseudoType, nil | ||
178 | } | ||
179 | } else if errs := val.Type().TestConformance(spec.Type); errs != nil { | ||
180 | // For now we'll just return the first error in the set, since | ||
181 | // we don't have a good way to return the whole list here. | ||
182 | // Would be good to do something better at some point... | ||
183 | return cty.Type{}, NewArgError(i, errs[0]) | ||
184 | } | ||
185 | } | ||
186 | } | ||
187 | |||
188 | // Intercept any panics from the function and return them as normal errors, | ||
189 | // so a calling language runtime doesn't need to deal with panics. | ||
190 | defer func() { | ||
191 | if r := recover(); r != nil { | ||
192 | ty = cty.NilType | ||
193 | err = errorForPanic(r) | ||
194 | } | ||
195 | }() | ||
196 | |||
197 | return f.spec.Type(args) | ||
198 | } | ||
199 | |||
200 | // Call actually calls the function with the given arguments, which must | ||
201 | // conform to the function's parameter specification or an error will be | ||
202 | // returned. | ||
203 | func (f Function) Call(args []cty.Value) (val cty.Value, err error) { | ||
204 | expectedType, err := f.ReturnTypeForValues(args) | ||
205 | if err != nil { | ||
206 | return cty.NilVal, err | ||
207 | } | ||
208 | |||
209 | // Type checking already dealt with most situations relating to our | ||
210 | // parameter specification, but we still need to deal with unknown | ||
211 | // values. | ||
212 | posArgs := args[:len(f.spec.Params)] | ||
213 | varArgs := args[len(f.spec.Params):] | ||
214 | |||
215 | for i, spec := range f.spec.Params { | ||
216 | val := posArgs[i] | ||
217 | |||
218 | if !val.IsKnown() && !spec.AllowUnknown { | ||
219 | return cty.UnknownVal(expectedType), nil | ||
220 | } | ||
221 | } | ||
222 | |||
223 | if f.spec.VarParam != nil { | ||
224 | spec := f.spec.VarParam | ||
225 | for _, val := range varArgs { | ||
226 | if !val.IsKnown() && !spec.AllowUnknown { | ||
227 | return cty.UnknownVal(expectedType), nil | ||
228 | } | ||
229 | } | ||
230 | } | ||
231 | |||
232 | var retVal cty.Value | ||
233 | { | ||
234 | // Intercept any panics from the function and return them as normal errors, | ||
235 | // so a calling language runtime doesn't need to deal with panics. | ||
236 | defer func() { | ||
237 | if r := recover(); r != nil { | ||
238 | val = cty.NilVal | ||
239 | err = errorForPanic(r) | ||
240 | } | ||
241 | }() | ||
242 | |||
243 | retVal, err = f.spec.Impl(args, expectedType) | ||
244 | if err != nil { | ||
245 | return cty.NilVal, err | ||
246 | } | ||
247 | } | ||
248 | |||
249 | // Returned value must conform to what the Type function expected, to | ||
250 | // protect callers from having to deal with inconsistencies. | ||
251 | if errs := retVal.Type().TestConformance(expectedType); errs != nil { | ||
252 | panic(fmt.Errorf( | ||
253 | "returned value %#v does not conform to expected return type %#v: %s", | ||
254 | retVal, expectedType, errs[0], | ||
255 | )) | ||
256 | } | ||
257 | |||
258 | return retVal, nil | ||
259 | } | ||
260 | |||
261 | // ProxyFunc the type returned by the method Function.Proxy. | ||
262 | type ProxyFunc func(args ...cty.Value) (cty.Value, error) | ||
263 | |||
264 | // Proxy returns a function that can be called with cty.Value arguments | ||
265 | // to run the function. This is provided as a convenience for when using | ||
266 | // a function directly within Go code. | ||
267 | func (f Function) Proxy() ProxyFunc { | ||
268 | return func(args ...cty.Value) (cty.Value, error) { | ||
269 | return f.Call(args) | ||
270 | } | ||
271 | } | ||
272 | |||
273 | // Params returns information about the function's fixed positional parameters. | ||
274 | // This does not include information about any variadic arguments accepted; | ||
275 | // for that, call VarParam. | ||
276 | func (f Function) Params() []Parameter { | ||
277 | new := make([]Parameter, len(f.spec.Params)) | ||
278 | copy(new, f.spec.Params) | ||
279 | return new | ||
280 | } | ||
281 | |||
282 | // VarParam returns information about the variadic arguments the function | ||
283 | // expects, or nil if the function is not variadic. | ||
284 | func (f Function) VarParam() *Parameter { | ||
285 | if f.spec.VarParam == nil { | ||
286 | return nil | ||
287 | } | ||
288 | |||
289 | ret := *f.spec.VarParam | ||
290 | return &ret | ||
291 | } | ||
diff --git a/vendor/github.com/zclconf/go-cty/cty/function/stdlib/bool.go b/vendor/github.com/zclconf/go-cty/cty/function/stdlib/bool.go new file mode 100644 index 0000000..a473d0e --- /dev/null +++ b/vendor/github.com/zclconf/go-cty/cty/function/stdlib/bool.go | |||
@@ -0,0 +1,73 @@ | |||
1 | package stdlib | ||
2 | |||
3 | import ( | ||
4 | "github.com/zclconf/go-cty/cty" | ||
5 | "github.com/zclconf/go-cty/cty/function" | ||
6 | ) | ||
7 | |||
8 | var NotFunc = function.New(&function.Spec{ | ||
9 | Params: []function.Parameter{ | ||
10 | { | ||
11 | Name: "val", | ||
12 | Type: cty.Bool, | ||
13 | AllowDynamicType: true, | ||
14 | }, | ||
15 | }, | ||
16 | Type: function.StaticReturnType(cty.Bool), | ||
17 | Impl: func(args []cty.Value, retType cty.Type) (cty.Value, error) { | ||
18 | return args[0].Not(), nil | ||
19 | }, | ||
20 | }) | ||
21 | |||
22 | var AndFunc = function.New(&function.Spec{ | ||
23 | Params: []function.Parameter{ | ||
24 | { | ||
25 | Name: "a", | ||
26 | Type: cty.Bool, | ||
27 | AllowDynamicType: true, | ||
28 | }, | ||
29 | { | ||
30 | Name: "b", | ||
31 | Type: cty.Bool, | ||
32 | AllowDynamicType: true, | ||
33 | }, | ||
34 | }, | ||
35 | Type: function.StaticReturnType(cty.Bool), | ||
36 | Impl: func(args []cty.Value, retType cty.Type) (cty.Value, error) { | ||
37 | return args[0].And(args[1]), nil | ||
38 | }, | ||
39 | }) | ||
40 | |||
41 | var OrFunc = function.New(&function.Spec{ | ||
42 | Params: []function.Parameter{ | ||
43 | { | ||
44 | Name: "a", | ||
45 | Type: cty.Bool, | ||
46 | AllowDynamicType: true, | ||
47 | }, | ||
48 | { | ||
49 | Name: "b", | ||
50 | Type: cty.Bool, | ||
51 | AllowDynamicType: true, | ||
52 | }, | ||
53 | }, | ||
54 | Type: function.StaticReturnType(cty.Bool), | ||
55 | Impl: func(args []cty.Value, retType cty.Type) (cty.Value, error) { | ||
56 | return args[0].Or(args[1]), nil | ||
57 | }, | ||
58 | }) | ||
59 | |||
60 | // Not returns the logical complement of the given boolean value. | ||
61 | func Not(num cty.Value) (cty.Value, error) { | ||
62 | return NotFunc.Call([]cty.Value{num}) | ||
63 | } | ||
64 | |||
65 | // And returns true if and only if both of the given boolean values are true. | ||
66 | func And(a, b cty.Value) (cty.Value, error) { | ||
67 | return AndFunc.Call([]cty.Value{a, b}) | ||
68 | } | ||
69 | |||
70 | // Or returns true if either of the given boolean values are true. | ||
71 | func Or(a, b cty.Value) (cty.Value, error) { | ||
72 | return OrFunc.Call([]cty.Value{a, b}) | ||
73 | } | ||
diff --git a/vendor/github.com/zclconf/go-cty/cty/function/stdlib/bytes.go b/vendor/github.com/zclconf/go-cty/cty/function/stdlib/bytes.go new file mode 100644 index 0000000..a132e0c --- /dev/null +++ b/vendor/github.com/zclconf/go-cty/cty/function/stdlib/bytes.go | |||
@@ -0,0 +1,112 @@ | |||
1 | package stdlib | ||
2 | |||
3 | import ( | ||
4 | "fmt" | ||
5 | "reflect" | ||
6 | |||
7 | "github.com/zclconf/go-cty/cty" | ||
8 | "github.com/zclconf/go-cty/cty/function" | ||
9 | "github.com/zclconf/go-cty/cty/gocty" | ||
10 | ) | ||
11 | |||
12 | // Bytes is a capsule type that can be used with the binary functions to | ||
13 | // support applications that need to support raw buffers in addition to | ||
14 | // UTF-8 strings. | ||
15 | var Bytes = cty.Capsule("bytes", reflect.TypeOf([]byte(nil))) | ||
16 | |||
17 | // BytesVal creates a new Bytes value from the given buffer, which must be | ||
18 | // non-nil or this function will panic. | ||
19 | // | ||
20 | // Once a byte slice has been wrapped in a Bytes capsule, its underlying array | ||
21 | // must be considered immutable. | ||
22 | func BytesVal(buf []byte) cty.Value { | ||
23 | if buf == nil { | ||
24 | panic("can't make Bytes value from nil slice") | ||
25 | } | ||
26 | |||
27 | return cty.CapsuleVal(Bytes, &buf) | ||
28 | } | ||
29 | |||
30 | // BytesLen is a Function that returns the length of the buffer encapsulated | ||
31 | // in a Bytes value. | ||
32 | var BytesLenFunc = function.New(&function.Spec{ | ||
33 | Params: []function.Parameter{ | ||
34 | { | ||
35 | Name: "buf", | ||
36 | Type: Bytes, | ||
37 | AllowDynamicType: true, | ||
38 | }, | ||
39 | }, | ||
40 | Type: function.StaticReturnType(cty.Number), | ||
41 | Impl: func(args []cty.Value, retType cty.Type) (cty.Value, error) { | ||
42 | bufPtr := args[0].EncapsulatedValue().(*[]byte) | ||
43 | return cty.NumberIntVal(int64(len(*bufPtr))), nil | ||
44 | }, | ||
45 | }) | ||
46 | |||
47 | // BytesSlice is a Function that returns a slice of the given Bytes value. | ||
48 | var BytesSliceFunc = function.New(&function.Spec{ | ||
49 | Params: []function.Parameter{ | ||
50 | { | ||
51 | Name: "buf", | ||
52 | Type: Bytes, | ||
53 | AllowDynamicType: true, | ||
54 | }, | ||
55 | { | ||
56 | Name: "offset", | ||
57 | Type: cty.Number, | ||
58 | AllowDynamicType: true, | ||
59 | }, | ||
60 | { | ||
61 | Name: "length", | ||
62 | Type: cty.Number, | ||
63 | AllowDynamicType: true, | ||
64 | }, | ||
65 | }, | ||
66 | Type: function.StaticReturnType(Bytes), | ||
67 | Impl: func(args []cty.Value, retType cty.Type) (cty.Value, error) { | ||
68 | bufPtr := args[0].EncapsulatedValue().(*[]byte) | ||
69 | |||
70 | var offset, length int | ||
71 | |||
72 | var err error | ||
73 | err = gocty.FromCtyValue(args[1], &offset) | ||
74 | if err != nil { | ||
75 | return cty.NilVal, err | ||
76 | } | ||
77 | err = gocty.FromCtyValue(args[2], &length) | ||
78 | if err != nil { | ||
79 | return cty.NilVal, err | ||
80 | } | ||
81 | |||
82 | if offset < 0 || length < 0 { | ||
83 | return cty.NilVal, fmt.Errorf("offset and length must be non-negative") | ||
84 | } | ||
85 | |||
86 | if offset > len(*bufPtr) { | ||
87 | return cty.NilVal, fmt.Errorf( | ||
88 | "offset %d is greater than total buffer length %d", | ||
89 | offset, len(*bufPtr), | ||
90 | ) | ||
91 | } | ||
92 | |||
93 | end := offset + length | ||
94 | |||
95 | if end > len(*bufPtr) { | ||
96 | return cty.NilVal, fmt.Errorf( | ||
97 | "offset %d + length %d is greater than total buffer length %d", | ||
98 | offset, length, len(*bufPtr), | ||
99 | ) | ||
100 | } | ||
101 | |||
102 | return BytesVal((*bufPtr)[offset:end]), nil | ||
103 | }, | ||
104 | }) | ||
105 | |||
106 | func BytesLen(buf cty.Value) (cty.Value, error) { | ||
107 | return BytesLenFunc.Call([]cty.Value{buf}) | ||
108 | } | ||
109 | |||
110 | func BytesSlice(buf cty.Value, offset cty.Value, length cty.Value) (cty.Value, error) { | ||
111 | return BytesSliceFunc.Call([]cty.Value{buf, offset, length}) | ||
112 | } | ||
diff --git a/vendor/github.com/zclconf/go-cty/cty/function/stdlib/collection.go b/vendor/github.com/zclconf/go-cty/cty/function/stdlib/collection.go new file mode 100644 index 0000000..967ba03 --- /dev/null +++ b/vendor/github.com/zclconf/go-cty/cty/function/stdlib/collection.go | |||
@@ -0,0 +1,140 @@ | |||
1 | package stdlib | ||
2 | |||
3 | import ( | ||
4 | "fmt" | ||
5 | |||
6 | "github.com/zclconf/go-cty/cty" | ||
7 | "github.com/zclconf/go-cty/cty/function" | ||
8 | "github.com/zclconf/go-cty/cty/gocty" | ||
9 | ) | ||
10 | |||
11 | var HasIndexFunc = function.New(&function.Spec{ | ||
12 | Params: []function.Parameter{ | ||
13 | { | ||
14 | Name: "collection", | ||
15 | Type: cty.DynamicPseudoType, | ||
16 | AllowDynamicType: true, | ||
17 | }, | ||
18 | { | ||
19 | Name: "key", | ||
20 | Type: cty.DynamicPseudoType, | ||
21 | AllowDynamicType: true, | ||
22 | }, | ||
23 | }, | ||
24 | Type: func(args []cty.Value) (ret cty.Type, err error) { | ||
25 | collTy := args[0].Type() | ||
26 | if !(collTy.IsTupleType() || collTy.IsListType() || collTy.IsMapType() || collTy == cty.DynamicPseudoType) { | ||
27 | return cty.NilType, fmt.Errorf("collection must be a list, a map or a tuple") | ||
28 | } | ||
29 | return cty.Bool, nil | ||
30 | }, | ||
31 | Impl: func(args []cty.Value, retType cty.Type) (ret cty.Value, err error) { | ||
32 | return args[0].HasIndex(args[1]), nil | ||
33 | }, | ||
34 | }) | ||
35 | |||
36 | var IndexFunc = function.New(&function.Spec{ | ||
37 | Params: []function.Parameter{ | ||
38 | { | ||
39 | Name: "collection", | ||
40 | Type: cty.DynamicPseudoType, | ||
41 | }, | ||
42 | { | ||
43 | Name: "key", | ||
44 | Type: cty.DynamicPseudoType, | ||
45 | AllowDynamicType: true, | ||
46 | }, | ||
47 | }, | ||
48 | Type: func(args []cty.Value) (ret cty.Type, err error) { | ||
49 | collTy := args[0].Type() | ||
50 | key := args[1] | ||
51 | keyTy := key.Type() | ||
52 | switch { | ||
53 | case collTy.IsTupleType(): | ||
54 | if keyTy != cty.Number && keyTy != cty.DynamicPseudoType { | ||
55 | return cty.NilType, fmt.Errorf("key for tuple must be number") | ||
56 | } | ||
57 | if !key.IsKnown() { | ||
58 | return cty.DynamicPseudoType, nil | ||
59 | } | ||
60 | var idx int | ||
61 | err := gocty.FromCtyValue(key, &idx) | ||
62 | if err != nil { | ||
63 | return cty.NilType, fmt.Errorf("invalid key for tuple: %s", err) | ||
64 | } | ||
65 | |||
66 | etys := collTy.TupleElementTypes() | ||
67 | |||
68 | if idx >= len(etys) || idx < 0 { | ||
69 | return cty.NilType, fmt.Errorf("key must be between 0 and %d inclusive", len(etys)) | ||
70 | } | ||
71 | |||
72 | return etys[idx], nil | ||
73 | |||
74 | case collTy.IsListType(): | ||
75 | if keyTy != cty.Number && keyTy != cty.DynamicPseudoType { | ||
76 | return cty.NilType, fmt.Errorf("key for list must be number") | ||
77 | } | ||
78 | |||
79 | return collTy.ElementType(), nil | ||
80 | |||
81 | case collTy.IsMapType(): | ||
82 | if keyTy != cty.String && keyTy != cty.DynamicPseudoType { | ||
83 | return cty.NilType, fmt.Errorf("key for map must be string") | ||
84 | } | ||
85 | |||
86 | return collTy.ElementType(), nil | ||
87 | |||
88 | default: | ||
89 | return cty.NilType, fmt.Errorf("collection must be a list, a map or a tuple") | ||
90 | } | ||
91 | }, | ||
92 | Impl: func(args []cty.Value, retType cty.Type) (ret cty.Value, err error) { | ||
93 | has, err := HasIndex(args[0], args[1]) | ||
94 | if err != nil { | ||
95 | return cty.NilVal, err | ||
96 | } | ||
97 | if has.False() { // safe because collection and key are guaranteed known here | ||
98 | return cty.NilVal, fmt.Errorf("invalid index") | ||
99 | } | ||
100 | |||
101 | return args[0].Index(args[1]), nil | ||
102 | }, | ||
103 | }) | ||
104 | |||
105 | var LengthFunc = function.New(&function.Spec{ | ||
106 | Params: []function.Parameter{ | ||
107 | { | ||
108 | Name: "collection", | ||
109 | Type: cty.DynamicPseudoType, | ||
110 | AllowDynamicType: true, | ||
111 | }, | ||
112 | }, | ||
113 | Type: func(args []cty.Value) (ret cty.Type, err error) { | ||
114 | collTy := args[0].Type() | ||
115 | if !(collTy.IsTupleType() || collTy.IsListType() || collTy.IsMapType() || collTy.IsSetType() || collTy == cty.DynamicPseudoType) { | ||
116 | return cty.NilType, fmt.Errorf("collection must be a list, a map or a tuple") | ||
117 | } | ||
118 | return cty.Number, nil | ||
119 | }, | ||
120 | Impl: func(args []cty.Value, retType cty.Type) (ret cty.Value, err error) { | ||
121 | return args[0].Length(), nil | ||
122 | }, | ||
123 | }) | ||
124 | |||
125 | // HasIndex determines whether the given collection can be indexed with the | ||
126 | // given key. | ||
127 | func HasIndex(collection cty.Value, key cty.Value) (cty.Value, error) { | ||
128 | return HasIndexFunc.Call([]cty.Value{collection, key}) | ||
129 | } | ||
130 | |||
131 | // Index returns an element from the given collection using the given key, | ||
132 | // or returns an error if there is no element for the given key. | ||
133 | func Index(collection cty.Value, key cty.Value) (cty.Value, error) { | ||
134 | return IndexFunc.Call([]cty.Value{collection, key}) | ||
135 | } | ||
136 | |||
137 | // Length returns the number of elements in the given collection. | ||
138 | func Length(collection cty.Value) (cty.Value, error) { | ||
139 | return LengthFunc.Call([]cty.Value{collection}) | ||
140 | } | ||
diff --git a/vendor/github.com/zclconf/go-cty/cty/function/stdlib/csv.go b/vendor/github.com/zclconf/go-cty/cty/function/stdlib/csv.go new file mode 100644 index 0000000..5070a5a --- /dev/null +++ b/vendor/github.com/zclconf/go-cty/cty/function/stdlib/csv.go | |||
@@ -0,0 +1,93 @@ | |||
1 | package stdlib | ||
2 | |||
3 | import ( | ||
4 | "encoding/csv" | ||
5 | "fmt" | ||
6 | "io" | ||
7 | "strings" | ||
8 | |||
9 | "github.com/zclconf/go-cty/cty" | ||
10 | "github.com/zclconf/go-cty/cty/function" | ||
11 | ) | ||
12 | |||
13 | var CSVDecodeFunc = function.New(&function.Spec{ | ||
14 | Params: []function.Parameter{ | ||
15 | { | ||
16 | Name: "str", | ||
17 | Type: cty.String, | ||
18 | }, | ||
19 | }, | ||
20 | Type: func(args []cty.Value) (cty.Type, error) { | ||
21 | str := args[0] | ||
22 | if !str.IsKnown() { | ||
23 | return cty.DynamicPseudoType, nil | ||
24 | } | ||
25 | |||
26 | r := strings.NewReader(str.AsString()) | ||
27 | cr := csv.NewReader(r) | ||
28 | headers, err := cr.Read() | ||
29 | if err == io.EOF { | ||
30 | return cty.DynamicPseudoType, fmt.Errorf("missing header line") | ||
31 | } | ||
32 | if err != nil { | ||
33 | return cty.DynamicPseudoType, err | ||
34 | } | ||
35 | |||
36 | atys := make(map[string]cty.Type, len(headers)) | ||
37 | for _, name := range headers { | ||
38 | if _, exists := atys[name]; exists { | ||
39 | return cty.DynamicPseudoType, fmt.Errorf("duplicate column name %q", name) | ||
40 | } | ||
41 | atys[name] = cty.String | ||
42 | } | ||
43 | return cty.List(cty.Object(atys)), nil | ||
44 | }, | ||
45 | Impl: func(args []cty.Value, retType cty.Type) (cty.Value, error) { | ||
46 | ety := retType.ElementType() | ||
47 | atys := ety.AttributeTypes() | ||
48 | str := args[0] | ||
49 | r := strings.NewReader(str.AsString()) | ||
50 | cr := csv.NewReader(r) | ||
51 | cr.FieldsPerRecord = len(atys) | ||
52 | |||
53 | // Read the header row first, since that'll tell us which indices | ||
54 | // map to which attribute names. | ||
55 | headers, err := cr.Read() | ||
56 | if err != nil { | ||
57 | return cty.DynamicVal, err | ||
58 | } | ||
59 | |||
60 | var rows []cty.Value | ||
61 | for { | ||
62 | cols, err := cr.Read() | ||
63 | if err == io.EOF { | ||
64 | break | ||
65 | } | ||
66 | if err != nil { | ||
67 | return cty.DynamicVal, err | ||
68 | } | ||
69 | |||
70 | vals := make(map[string]cty.Value, len(cols)) | ||
71 | for i, str := range cols { | ||
72 | name := headers[i] | ||
73 | vals[name] = cty.StringVal(str) | ||
74 | } | ||
75 | rows = append(rows, cty.ObjectVal(vals)) | ||
76 | } | ||
77 | |||
78 | if len(rows) == 0 { | ||
79 | return cty.ListValEmpty(ety), nil | ||
80 | } | ||
81 | return cty.ListVal(rows), nil | ||
82 | }, | ||
83 | }) | ||
84 | |||
85 | // CSVDecode parses the given CSV (RFC 4180) string and, if it is valid, | ||
86 | // returns a list of objects representing the rows. | ||
87 | // | ||
88 | // The result is always a list of some object type. The first row of the | ||
89 | // input is used to determine the object attributes, and subsequent rows | ||
90 | // determine the values of those attributes. | ||
91 | func CSVDecode(str cty.Value) (cty.Value, error) { | ||
92 | return CSVDecodeFunc.Call([]cty.Value{str}) | ||
93 | } | ||
diff --git a/vendor/github.com/zclconf/go-cty/cty/function/stdlib/doc.go b/vendor/github.com/zclconf/go-cty/cty/function/stdlib/doc.go new file mode 100644 index 0000000..cfb613e --- /dev/null +++ b/vendor/github.com/zclconf/go-cty/cty/function/stdlib/doc.go | |||
@@ -0,0 +1,13 @@ | |||
1 | // Package stdlib is a collection of cty functions that are expected to be | ||
2 | // generally useful, and are thus factored out into this shared library in | ||
3 | // the hope that cty-using applications will have consistent behavior when | ||
4 | // using these functions. | ||
5 | // | ||
6 | // See the parent package "function" for more information on the purpose | ||
7 | // and usage of cty functions. | ||
8 | // | ||
9 | // This package contains both Go functions, which provide convenient access | ||
10 | // to call the functions from Go code, and the Function objects themselves. | ||
11 | // The latter follow the naming scheme of appending "Func" to the end of | ||
12 | // the function name. | ||
13 | package stdlib | ||
diff --git a/vendor/github.com/zclconf/go-cty/cty/function/stdlib/format.go b/vendor/github.com/zclconf/go-cty/cty/function/stdlib/format.go new file mode 100644 index 0000000..fb24f20 --- /dev/null +++ b/vendor/github.com/zclconf/go-cty/cty/function/stdlib/format.go | |||
@@ -0,0 +1,496 @@ | |||
1 | package stdlib | ||
2 | |||
3 | import ( | ||
4 | "bytes" | ||
5 | "fmt" | ||
6 | "math/big" | ||
7 | "strings" | ||
8 | |||
9 | "github.com/apparentlymart/go-textseg/textseg" | ||
10 | |||
11 | "github.com/zclconf/go-cty/cty" | ||
12 | "github.com/zclconf/go-cty/cty/convert" | ||
13 | "github.com/zclconf/go-cty/cty/function" | ||
14 | "github.com/zclconf/go-cty/cty/json" | ||
15 | ) | ||
16 | |||
17 | //go:generate ragel -Z format_fsm.rl | ||
18 | //go:generate gofmt -w format_fsm.go | ||
19 | |||
20 | var FormatFunc = function.New(&function.Spec{ | ||
21 | Params: []function.Parameter{ | ||
22 | { | ||
23 | Name: "format", | ||
24 | Type: cty.String, | ||
25 | }, | ||
26 | }, | ||
27 | VarParam: &function.Parameter{ | ||
28 | Name: "args", | ||
29 | Type: cty.DynamicPseudoType, | ||
30 | AllowNull: true, | ||
31 | }, | ||
32 | Type: function.StaticReturnType(cty.String), | ||
33 | Impl: func(args []cty.Value, retType cty.Type) (cty.Value, error) { | ||
34 | for _, arg := range args[1:] { | ||
35 | if !arg.IsWhollyKnown() { | ||
36 | // We require all nested values to be known because the only | ||
37 | // thing we can do for a collection/structural type is print | ||
38 | // it as JSON and that requires it to be wholly known. | ||
39 | return cty.UnknownVal(cty.String), nil | ||
40 | } | ||
41 | } | ||
42 | str, err := formatFSM(args[0].AsString(), args[1:]) | ||
43 | return cty.StringVal(str), err | ||
44 | }, | ||
45 | }) | ||
46 | |||
47 | var FormatListFunc = function.New(&function.Spec{ | ||
48 | Params: []function.Parameter{ | ||
49 | { | ||
50 | Name: "format", | ||
51 | Type: cty.String, | ||
52 | }, | ||
53 | }, | ||
54 | VarParam: &function.Parameter{ | ||
55 | Name: "args", | ||
56 | Type: cty.DynamicPseudoType, | ||
57 | AllowNull: true, | ||
58 | AllowUnknown: true, | ||
59 | }, | ||
60 | Type: function.StaticReturnType(cty.List(cty.String)), | ||
61 | Impl: func(args []cty.Value, retType cty.Type) (cty.Value, error) { | ||
62 | fmtVal := args[0] | ||
63 | args = args[1:] | ||
64 | |||
65 | if len(args) == 0 { | ||
66 | // With no arguments, this function is equivalent to Format, but | ||
67 | // returning a single-element list result. | ||
68 | result, err := Format(fmtVal, args...) | ||
69 | return cty.ListVal([]cty.Value{result}), err | ||
70 | } | ||
71 | |||
72 | fmtStr := fmtVal.AsString() | ||
73 | |||
74 | // Each of our arguments will be dealt with either as an iterator | ||
75 | // or as a single value. Iterators are used for sequence-type values | ||
76 | // (lists, sets, tuples) while everything else is treated as a | ||
77 | // single value. The sequences we iterate over are required to be | ||
78 | // all the same length. | ||
79 | iterLen := -1 | ||
80 | lenChooser := -1 | ||
81 | iterators := make([]cty.ElementIterator, len(args)) | ||
82 | singleVals := make([]cty.Value, len(args)) | ||
83 | for i, arg := range args { | ||
84 | argTy := arg.Type() | ||
85 | switch { | ||
86 | case (argTy.IsListType() || argTy.IsSetType() || argTy.IsTupleType()) && !arg.IsNull(): | ||
87 | thisLen := arg.LengthInt() | ||
88 | if iterLen == -1 { | ||
89 | iterLen = thisLen | ||
90 | lenChooser = i | ||
91 | } else { | ||
92 | if thisLen != iterLen { | ||
93 | return cty.NullVal(cty.List(cty.String)), function.NewArgErrorf( | ||
94 | i+1, | ||
95 | "argument %d has length %d, which is inconsistent with argument %d of length %d", | ||
96 | i+1, thisLen, | ||
97 | lenChooser+1, iterLen, | ||
98 | ) | ||
99 | } | ||
100 | } | ||
101 | iterators[i] = arg.ElementIterator() | ||
102 | default: | ||
103 | singleVals[i] = arg | ||
104 | } | ||
105 | } | ||
106 | |||
107 | if iterLen == 0 { | ||
108 | // If our sequences are all empty then our result must be empty. | ||
109 | return cty.ListValEmpty(cty.String), nil | ||
110 | } | ||
111 | |||
112 | if iterLen == -1 { | ||
113 | // If we didn't encounter any iterables at all then we're going | ||
114 | // to just do one iteration with items from singleVals. | ||
115 | iterLen = 1 | ||
116 | } | ||
117 | |||
118 | ret := make([]cty.Value, 0, iterLen) | ||
119 | fmtArgs := make([]cty.Value, len(iterators)) | ||
120 | Results: | ||
121 | for iterIdx := 0; iterIdx < iterLen; iterIdx++ { | ||
122 | |||
123 | // Construct our arguments for a single format call | ||
124 | for i := range fmtArgs { | ||
125 | switch { | ||
126 | case iterators[i] != nil: | ||
127 | iterator := iterators[i] | ||
128 | iterator.Next() | ||
129 | _, val := iterator.Element() | ||
130 | fmtArgs[i] = val | ||
131 | default: | ||
132 | fmtArgs[i] = singleVals[i] | ||
133 | } | ||
134 | |||
135 | // If any of the arguments to this call would be unknown then | ||
136 | // this particular result is unknown, but we'll keep going | ||
137 | // to see if any other iterations can produce known values. | ||
138 | if !fmtArgs[i].IsWhollyKnown() { | ||
139 | // We require all nested values to be known because the only | ||
140 | // thing we can do for a collection/structural type is print | ||
141 | // it as JSON and that requires it to be wholly known. | ||
142 | ret = append(ret, cty.UnknownVal(cty.String)) | ||
143 | continue Results | ||
144 | } | ||
145 | } | ||
146 | |||
147 | str, err := formatFSM(fmtStr, fmtArgs) | ||
148 | if err != nil { | ||
149 | return cty.NullVal(cty.List(cty.String)), fmt.Errorf( | ||
150 | "error on format iteration %d: %s", iterIdx, err, | ||
151 | ) | ||
152 | } | ||
153 | |||
154 | ret = append(ret, cty.StringVal(str)) | ||
155 | } | ||
156 | |||
157 | return cty.ListVal(ret), nil | ||
158 | }, | ||
159 | }) | ||
160 | |||
161 | // Format produces a string representation of zero or more values using a | ||
162 | // format string similar to the "printf" function in C. | ||
163 | // | ||
164 | // It supports the following "verbs": | ||
165 | // | ||
166 | // %% Literal percent sign, consuming no value | ||
167 | // %v A default formatting of the value based on type, as described below. | ||
168 | // %#v JSON serialization of the value | ||
169 | // %t Converts to boolean and then produces "true" or "false" | ||
170 | // %b Converts to number, requires integer, produces binary representation | ||
171 | // %d Converts to number, requires integer, produces decimal representation | ||
172 | // %o Converts to number, requires integer, produces octal representation | ||
173 | // %x Converts to number, requires integer, produces hexadecimal representation | ||
174 | // with lowercase letters | ||
175 | // %X Like %x but with uppercase letters | ||
176 | // %e Converts to number, produces scientific notation like -1.234456e+78 | ||
177 | // %E Like %e but with an uppercase "E" representing the exponent | ||
178 | // %f Converts to number, produces decimal representation with fractional | ||
179 | // part but no exponent, like 123.456 | ||
180 | // %g %e for large exponents or %f otherwise | ||
181 | // %G %E for large exponents or %f otherwise | ||
182 | // %s Converts to string and produces the string's characters | ||
183 | // %q Converts to string and produces JSON-quoted string representation, | ||
184 | // like %v. | ||
185 | // | ||
186 | // The default format selections made by %v are: | ||
187 | // | ||
188 | // string %s | ||
189 | // number %g | ||
190 | // bool %t | ||
191 | // other %#v | ||
192 | // | ||
193 | // Null values produce the literal keyword "null" for %v and %#v, and produce | ||
194 | // an error otherwise. | ||
195 | // | ||
196 | // Width is specified by an optional decimal number immediately preceding the | ||
197 | // verb letter. If absent, the width is whatever is necessary to represent the | ||
198 | // value. Precision is specified after the (optional) width by a period | ||
199 | // followed by a decimal number. If no period is present, a default precision | ||
200 | // is used. A period with no following number is invalid. | ||
201 | // For examples: | ||
202 | // | ||
203 | // %f default width, default precision | ||
204 | // %9f width 9, default precision | ||
205 | // %.2f default width, precision 2 | ||
206 | // %9.2f width 9, precision 2 | ||
207 | // | ||
208 | // Width and precision are measured in unicode characters (grapheme clusters). | ||
209 | // | ||
210 | // For most values, width is the minimum number of characters to output, | ||
211 | // padding the formatted form with spaces if necessary. | ||
212 | // | ||
213 | // For strings, precision limits the length of the input to be formatted (not | ||
214 | // the size of the output), truncating if necessary. | ||
215 | // | ||
216 | // For numbers, width sets the minimum width of the field and precision sets | ||
217 | // the number of places after the decimal, if appropriate, except that for | ||
218 | // %g/%G precision sets the total number of significant digits. | ||
219 | // | ||
220 | // The following additional symbols can be used immediately after the percent | ||
221 | // introducer as flags: | ||
222 | // | ||
223 | // (a space) leave a space where the sign would be if number is positive | ||
224 | // + Include a sign for a number even if it is positive (numeric only) | ||
225 | // - Pad with spaces on the left rather than the right | ||
226 | // 0 Pad with zeros rather than spaces. | ||
227 | // | ||
228 | // Flag characters are ignored for verbs that do not support them. | ||
229 | // | ||
230 | // By default, % sequences consume successive arguments starting with the first. | ||
231 | // Introducing a [n] sequence immediately before the verb letter, where n is a | ||
232 | // decimal integer, explicitly chooses a particular value argument by its | ||
233 | // one-based index. Subsequent calls without an explicit index will then | ||
234 | // proceed with n+1, n+2, etc. | ||
235 | // | ||
236 | // An error is produced if the format string calls for an impossible conversion | ||
237 | // or accesses more values than are given. An error is produced also for | ||
238 | // an unsupported format verb. | ||
239 | func Format(format cty.Value, vals ...cty.Value) (cty.Value, error) { | ||
240 | args := make([]cty.Value, 0, len(vals)+1) | ||
241 | args = append(args, format) | ||
242 | args = append(args, vals...) | ||
243 | return FormatFunc.Call(args) | ||
244 | } | ||
245 | |||
246 | // FormatList applies the same formatting behavior as Format, but accepts | ||
247 | // a mixture of list and non-list values as arguments. Any list arguments | ||
248 | // passed must have the same length, which dictates the length of the | ||
249 | // resulting list. | ||
250 | // | ||
251 | // Any non-list arguments are used repeatedly for each iteration over the | ||
252 | // list arguments. The list arguments are iterated in order by key, so | ||
253 | // corresponding items are formatted together. | ||
254 | func FormatList(format cty.Value, vals ...cty.Value) (cty.Value, error) { | ||
255 | args := make([]cty.Value, 0, len(vals)+1) | ||
256 | args = append(args, format) | ||
257 | args = append(args, vals...) | ||
258 | return FormatListFunc.Call(args) | ||
259 | } | ||
260 | |||
261 | type formatVerb struct { | ||
262 | Raw string | ||
263 | Offset int | ||
264 | |||
265 | ArgNum int | ||
266 | Mode rune | ||
267 | |||
268 | Zero bool | ||
269 | Sharp bool | ||
270 | Plus bool | ||
271 | Minus bool | ||
272 | Space bool | ||
273 | |||
274 | HasPrec bool | ||
275 | Prec int | ||
276 | |||
277 | HasWidth bool | ||
278 | Width int | ||
279 | } | ||
280 | |||
281 | // formatAppend is called by formatFSM (generated by format_fsm.rl) for each | ||
282 | // formatting sequence that is encountered. | ||
283 | func formatAppend(verb *formatVerb, buf *bytes.Buffer, args []cty.Value) error { | ||
284 | argIdx := verb.ArgNum - 1 | ||
285 | if argIdx >= len(args) { | ||
286 | return fmt.Errorf( | ||
287 | "not enough arguments for %q at %d: need index %d but have %d total", | ||
288 | verb.Raw, verb.Offset, | ||
289 | verb.ArgNum, len(args), | ||
290 | ) | ||
291 | } | ||
292 | arg := args[argIdx] | ||
293 | |||
294 | if verb.Mode != 'v' && arg.IsNull() { | ||
295 | return fmt.Errorf("unsupported value for %q at %d: null value cannot be formatted", verb.Raw, verb.Offset) | ||
296 | } | ||
297 | |||
298 | // Normalize to make some things easier for downstream formatters | ||
299 | if !verb.HasWidth { | ||
300 | verb.Width = -1 | ||
301 | } | ||
302 | if !verb.HasPrec { | ||
303 | verb.Prec = -1 | ||
304 | } | ||
305 | |||
306 | // For our first pass we'll ensure the verb is supported and then fan | ||
307 | // out to other functions based on what conversion is needed. | ||
308 | switch verb.Mode { | ||
309 | |||
310 | case 'v': | ||
311 | return formatAppendAsIs(verb, buf, arg) | ||
312 | |||
313 | case 't': | ||
314 | return formatAppendBool(verb, buf, arg) | ||
315 | |||
316 | case 'b', 'd', 'o', 'x', 'X', 'e', 'E', 'f', 'g', 'G': | ||
317 | return formatAppendNumber(verb, buf, arg) | ||
318 | |||
319 | case 's', 'q': | ||
320 | return formatAppendString(verb, buf, arg) | ||
321 | |||
322 | default: | ||
323 | return fmt.Errorf("unsupported format verb %q in %q at offset %d", verb.Mode, verb.Raw, verb.Offset) | ||
324 | } | ||
325 | } | ||
326 | |||
327 | func formatAppendAsIs(verb *formatVerb, buf *bytes.Buffer, arg cty.Value) error { | ||
328 | |||
329 | if !verb.Sharp && !arg.IsNull() { | ||
330 | // Unless the caller overrode it with the sharp flag, we'll try some | ||
331 | // specialized formats before we fall back on JSON. | ||
332 | switch arg.Type() { | ||
333 | case cty.String: | ||
334 | fmted := arg.AsString() | ||
335 | fmted = formatPadWidth(verb, fmted) | ||
336 | buf.WriteString(fmted) | ||
337 | return nil | ||
338 | case cty.Number: | ||
339 | bf := arg.AsBigFloat() | ||
340 | fmted := bf.Text('g', -1) | ||
341 | fmted = formatPadWidth(verb, fmted) | ||
342 | buf.WriteString(fmted) | ||
343 | return nil | ||
344 | } | ||
345 | } | ||
346 | |||
347 | jb, err := json.Marshal(arg, arg.Type()) | ||
348 | if err != nil { | ||
349 | return fmt.Errorf("unsupported value for %q at %d: %s", verb.Raw, verb.Offset, err) | ||
350 | } | ||
351 | fmted := formatPadWidth(verb, string(jb)) | ||
352 | buf.WriteString(fmted) | ||
353 | |||
354 | return nil | ||
355 | } | ||
356 | |||
357 | func formatAppendBool(verb *formatVerb, buf *bytes.Buffer, arg cty.Value) error { | ||
358 | var err error | ||
359 | arg, err = convert.Convert(arg, cty.Bool) | ||
360 | if err != nil { | ||
361 | return fmt.Errorf("unsupported value for %q at %d: %s", verb.Raw, verb.Offset, err) | ||
362 | } | ||
363 | |||
364 | if arg.True() { | ||
365 | buf.WriteString("true") | ||
366 | } else { | ||
367 | buf.WriteString("false") | ||
368 | } | ||
369 | return nil | ||
370 | } | ||
371 | |||
372 | func formatAppendNumber(verb *formatVerb, buf *bytes.Buffer, arg cty.Value) error { | ||
373 | var err error | ||
374 | arg, err = convert.Convert(arg, cty.Number) | ||
375 | if err != nil { | ||
376 | return fmt.Errorf("unsupported value for %q at %d: %s", verb.Raw, verb.Offset, err) | ||
377 | } | ||
378 | |||
379 | switch verb.Mode { | ||
380 | case 'b', 'd', 'o', 'x', 'X': | ||
381 | return formatAppendInteger(verb, buf, arg) | ||
382 | default: | ||
383 | bf := arg.AsBigFloat() | ||
384 | |||
385 | // For floats our format syntax is a subset of Go's, so it's | ||
386 | // safe for us to just lean on the existing Go implementation. | ||
387 | fmtstr := formatStripIndexSegment(verb.Raw) | ||
388 | fmted := fmt.Sprintf(fmtstr, bf) | ||
389 | buf.WriteString(fmted) | ||
390 | return nil | ||
391 | } | ||
392 | } | ||
393 | |||
394 | func formatAppendInteger(verb *formatVerb, buf *bytes.Buffer, arg cty.Value) error { | ||
395 | bf := arg.AsBigFloat() | ||
396 | bi, acc := bf.Int(nil) | ||
397 | if acc != big.Exact { | ||
398 | return fmt.Errorf("unsupported value for %q at %d: an integer is required", verb.Raw, verb.Offset) | ||
399 | } | ||
400 | |||
401 | // For integers our format syntax is a subset of Go's, so it's | ||
402 | // safe for us to just lean on the existing Go implementation. | ||
403 | fmtstr := formatStripIndexSegment(verb.Raw) | ||
404 | fmted := fmt.Sprintf(fmtstr, bi) | ||
405 | buf.WriteString(fmted) | ||
406 | return nil | ||
407 | } | ||
408 | |||
409 | func formatAppendString(verb *formatVerb, buf *bytes.Buffer, arg cty.Value) error { | ||
410 | var err error | ||
411 | arg, err = convert.Convert(arg, cty.String) | ||
412 | if err != nil { | ||
413 | return fmt.Errorf("unsupported value for %q at %d: %s", verb.Raw, verb.Offset, err) | ||
414 | } | ||
415 | |||
416 | // We _cannot_ directly use the Go fmt.Sprintf implementation for strings | ||
417 | // because it measures widths and precisions in runes rather than grapheme | ||
418 | // clusters. | ||
419 | |||
420 | str := arg.AsString() | ||
421 | if verb.Prec > 0 { | ||
422 | strB := []byte(str) | ||
423 | pos := 0 | ||
424 | wanted := verb.Prec | ||
425 | for i := 0; i < wanted; i++ { | ||
426 | next := strB[pos:] | ||
427 | if len(next) == 0 { | ||
428 | // ran out of characters before we hit our max width | ||
429 | break | ||
430 | } | ||
431 | d, _, _ := textseg.ScanGraphemeClusters(strB[pos:], true) | ||
432 | pos += d | ||
433 | } | ||
434 | str = str[:pos] | ||
435 | } | ||
436 | |||
437 | switch verb.Mode { | ||
438 | case 's': | ||
439 | fmted := formatPadWidth(verb, str) | ||
440 | buf.WriteString(fmted) | ||
441 | case 'q': | ||
442 | jb, err := json.Marshal(cty.StringVal(str), cty.String) | ||
443 | if err != nil { | ||
444 | // Should never happen, since we know this is a known, non-null string | ||
445 | panic(fmt.Errorf("failed to marshal %#v as JSON: %s", arg, err)) | ||
446 | } | ||
447 | fmted := formatPadWidth(verb, string(jb)) | ||
448 | buf.WriteString(fmted) | ||
449 | default: | ||
450 | // Should never happen because formatAppend should've already validated | ||
451 | panic(fmt.Errorf("invalid string formatting mode %q", verb.Mode)) | ||
452 | } | ||
453 | return nil | ||
454 | } | ||
455 | |||
456 | func formatPadWidth(verb *formatVerb, fmted string) string { | ||
457 | if verb.Width < 0 { | ||
458 | return fmted | ||
459 | } | ||
460 | |||
461 | // Safe to ignore errors because ScanGraphemeClusters cannot produce errors | ||
462 | givenLen, _ := textseg.TokenCount([]byte(fmted), textseg.ScanGraphemeClusters) | ||
463 | wantLen := verb.Width | ||
464 | if givenLen >= wantLen { | ||
465 | return fmted | ||
466 | } | ||
467 | |||
468 | padLen := wantLen - givenLen | ||
469 | padChar := " " | ||
470 | if verb.Zero { | ||
471 | padChar = "0" | ||
472 | } | ||
473 | pads := strings.Repeat(padChar, padLen) | ||
474 | |||
475 | if verb.Minus { | ||
476 | return fmted + pads | ||
477 | } | ||
478 | return pads + fmted | ||
479 | } | ||
480 | |||
481 | // formatStripIndexSegment strips out any [nnn] segment present in a verb | ||
482 | // string so that we can pass it through to Go's fmt.Sprintf with a single | ||
483 | // argument. This is used in cases where we're just leaning on Go's formatter | ||
484 | // because it's a superset of ours. | ||
485 | func formatStripIndexSegment(rawVerb string) string { | ||
486 | // We assume the string has already been validated here, since we should | ||
487 | // only be using this function with strings that were accepted by our | ||
488 | // scanner in formatFSM. | ||
489 | start := strings.Index(rawVerb, "[") | ||
490 | end := strings.Index(rawVerb, "]") | ||
491 | if start == -1 || end == -1 { | ||
492 | return rawVerb | ||
493 | } | ||
494 | |||
495 | return rawVerb[:start] + rawVerb[end+1:] | ||
496 | } | ||
diff --git a/vendor/github.com/zclconf/go-cty/cty/function/stdlib/format_fsm.go b/vendor/github.com/zclconf/go-cty/cty/function/stdlib/format_fsm.go new file mode 100644 index 0000000..86876ba --- /dev/null +++ b/vendor/github.com/zclconf/go-cty/cty/function/stdlib/format_fsm.go | |||
@@ -0,0 +1,358 @@ | |||
1 | // line 1 "format_fsm.rl" | ||
2 | // This file is generated from format_fsm.rl. DO NOT EDIT. | ||
3 | |||
4 | // line 5 "format_fsm.rl" | ||
5 | |||
6 | package stdlib | ||
7 | |||
8 | import ( | ||
9 | "bytes" | ||
10 | "fmt" | ||
11 | "unicode/utf8" | ||
12 | |||
13 | "github.com/zclconf/go-cty/cty" | ||
14 | ) | ||
15 | |||
16 | // line 20 "format_fsm.go" | ||
17 | var _formatfsm_actions []byte = []byte{ | ||
18 | 0, 1, 0, 1, 1, 1, 2, 1, 4, | ||
19 | 1, 5, 1, 6, 1, 7, 1, 8, | ||
20 | 1, 9, 1, 10, 1, 11, 1, 14, | ||
21 | 1, 16, 1, 17, 1, 18, 2, 3, | ||
22 | 4, 2, 12, 10, 2, 12, 16, 2, | ||
23 | 12, 18, 2, 13, 14, 2, 15, 10, | ||
24 | 2, 15, 18, | ||
25 | } | ||
26 | |||
27 | var _formatfsm_key_offsets []byte = []byte{ | ||
28 | 0, 0, 14, 27, 34, 36, 39, 43, | ||
29 | 51, | ||
30 | } | ||
31 | |||
32 | var _formatfsm_trans_keys []byte = []byte{ | ||
33 | 32, 35, 37, 43, 45, 46, 48, 91, | ||
34 | 49, 57, 65, 90, 97, 122, 32, 35, | ||
35 | 43, 45, 46, 48, 91, 49, 57, 65, | ||
36 | 90, 97, 122, 91, 48, 57, 65, 90, | ||
37 | 97, 122, 49, 57, 93, 48, 57, 65, | ||
38 | 90, 97, 122, 46, 91, 48, 57, 65, | ||
39 | 90, 97, 122, 37, | ||
40 | } | ||
41 | |||
42 | var _formatfsm_single_lengths []byte = []byte{ | ||
43 | 0, 8, 7, 1, 0, 1, 0, 2, | ||
44 | 1, | ||
45 | } | ||
46 | |||
47 | var _formatfsm_range_lengths []byte = []byte{ | ||
48 | 0, 3, 3, 3, 1, 1, 2, 3, | ||
49 | 0, | ||
50 | } | ||
51 | |||
52 | var _formatfsm_index_offsets []byte = []byte{ | ||
53 | 0, 0, 12, 23, 28, 30, 33, 36, | ||
54 | 42, | ||
55 | } | ||
56 | |||
57 | var _formatfsm_indicies []byte = []byte{ | ||
58 | 1, 2, 3, 4, 5, 6, 7, 10, | ||
59 | 8, 9, 9, 0, 1, 2, 4, 5, | ||
60 | 6, 7, 10, 8, 9, 9, 0, 13, | ||
61 | 11, 12, 12, 0, 14, 0, 15, 14, | ||
62 | 0, 9, 9, 0, 16, 19, 17, 18, | ||
63 | 18, 0, 20, 3, | ||
64 | } | ||
65 | |||
66 | var _formatfsm_trans_targs []byte = []byte{ | ||
67 | 0, 2, 2, 8, 2, 2, 3, 2, | ||
68 | 7, 8, 4, 3, 8, 4, 5, 6, | ||
69 | 3, 7, 8, 4, 1, | ||
70 | } | ||
71 | |||
72 | var _formatfsm_trans_actions []byte = []byte{ | ||
73 | 7, 17, 9, 3, 15, 13, 25, 11, | ||
74 | 43, 29, 19, 27, 49, 46, 21, 0, | ||
75 | 37, 23, 40, 34, 1, | ||
76 | } | ||
77 | |||
78 | var _formatfsm_eof_actions []byte = []byte{ | ||
79 | 0, 31, 31, 31, 31, 31, 31, 31, | ||
80 | 5, | ||
81 | } | ||
82 | |||
83 | const formatfsm_start int = 8 | ||
84 | const formatfsm_first_final int = 8 | ||
85 | const formatfsm_error int = 0 | ||
86 | |||
87 | const formatfsm_en_main int = 8 | ||
88 | |||
89 | // line 19 "format_fsm.rl" | ||
90 | |||
91 | func formatFSM(format string, a []cty.Value) (string, error) { | ||
92 | var buf bytes.Buffer | ||
93 | data := format | ||
94 | nextArg := 1 // arg numbers are 1-based | ||
95 | var verb formatVerb | ||
96 | |||
97 | // line 153 "format_fsm.rl" | ||
98 | |||
99 | // Ragel state | ||
100 | p := 0 // "Pointer" into data | ||
101 | pe := len(data) // End-of-data "pointer" | ||
102 | cs := 0 // current state (will be initialized by ragel-generated code) | ||
103 | ts := 0 | ||
104 | te := 0 | ||
105 | eof := pe | ||
106 | |||
107 | // Keep Go compiler happy even if generated code doesn't use these | ||
108 | _ = ts | ||
109 | _ = te | ||
110 | _ = eof | ||
111 | |||
112 | // line 121 "format_fsm.go" | ||
113 | { | ||
114 | cs = formatfsm_start | ||
115 | } | ||
116 | |||
117 | // line 126 "format_fsm.go" | ||
118 | { | ||
119 | var _klen int | ||
120 | var _trans int | ||
121 | var _acts int | ||
122 | var _nacts uint | ||
123 | var _keys int | ||
124 | if p == pe { | ||
125 | goto _test_eof | ||
126 | } | ||
127 | if cs == 0 { | ||
128 | goto _out | ||
129 | } | ||
130 | _resume: | ||
131 | _keys = int(_formatfsm_key_offsets[cs]) | ||
132 | _trans = int(_formatfsm_index_offsets[cs]) | ||
133 | |||
134 | _klen = int(_formatfsm_single_lengths[cs]) | ||
135 | if _klen > 0 { | ||
136 | _lower := int(_keys) | ||
137 | var _mid int | ||
138 | _upper := int(_keys + _klen - 1) | ||
139 | for { | ||
140 | if _upper < _lower { | ||
141 | break | ||
142 | } | ||
143 | |||
144 | _mid = _lower + ((_upper - _lower) >> 1) | ||
145 | switch { | ||
146 | case data[p] < _formatfsm_trans_keys[_mid]: | ||
147 | _upper = _mid - 1 | ||
148 | case data[p] > _formatfsm_trans_keys[_mid]: | ||
149 | _lower = _mid + 1 | ||
150 | default: | ||
151 | _trans += int(_mid - int(_keys)) | ||
152 | goto _match | ||
153 | } | ||
154 | } | ||
155 | _keys += _klen | ||
156 | _trans += _klen | ||
157 | } | ||
158 | |||
159 | _klen = int(_formatfsm_range_lengths[cs]) | ||
160 | if _klen > 0 { | ||
161 | _lower := int(_keys) | ||
162 | var _mid int | ||
163 | _upper := int(_keys + (_klen << 1) - 2) | ||
164 | for { | ||
165 | if _upper < _lower { | ||
166 | break | ||
167 | } | ||
168 | |||
169 | _mid = _lower + (((_upper - _lower) >> 1) & ^1) | ||
170 | switch { | ||
171 | case data[p] < _formatfsm_trans_keys[_mid]: | ||
172 | _upper = _mid - 2 | ||
173 | case data[p] > _formatfsm_trans_keys[_mid+1]: | ||
174 | _lower = _mid + 2 | ||
175 | default: | ||
176 | _trans += int((_mid - int(_keys)) >> 1) | ||
177 | goto _match | ||
178 | } | ||
179 | } | ||
180 | _trans += _klen | ||
181 | } | ||
182 | |||
183 | _match: | ||
184 | _trans = int(_formatfsm_indicies[_trans]) | ||
185 | cs = int(_formatfsm_trans_targs[_trans]) | ||
186 | |||
187 | if _formatfsm_trans_actions[_trans] == 0 { | ||
188 | goto _again | ||
189 | } | ||
190 | |||
191 | _acts = int(_formatfsm_trans_actions[_trans]) | ||
192 | _nacts = uint(_formatfsm_actions[_acts]) | ||
193 | _acts++ | ||
194 | for ; _nacts > 0; _nacts-- { | ||
195 | _acts++ | ||
196 | switch _formatfsm_actions[_acts-1] { | ||
197 | case 0: | ||
198 | // line 29 "format_fsm.rl" | ||
199 | |||
200 | verb = formatVerb{ | ||
201 | ArgNum: nextArg, | ||
202 | Prec: -1, | ||
203 | Width: -1, | ||
204 | } | ||
205 | ts = p | ||
206 | |||
207 | case 1: | ||
208 | // line 38 "format_fsm.rl" | ||
209 | |||
210 | buf.WriteByte(data[p]) | ||
211 | |||
212 | case 4: | ||
213 | // line 49 "format_fsm.rl" | ||
214 | |||
215 | // We'll try to slurp a whole UTF-8 sequence here, to give the user | ||
216 | // better feedback. | ||
217 | r, _ := utf8.DecodeRuneInString(data[p:]) | ||
218 | return buf.String(), fmt.Errorf("unrecognized format character %q at offset %d", r, p) | ||
219 | |||
220 | case 5: | ||
221 | // line 56 "format_fsm.rl" | ||
222 | |||
223 | verb.Sharp = true | ||
224 | |||
225 | case 6: | ||
226 | // line 59 "format_fsm.rl" | ||
227 | |||
228 | verb.Zero = true | ||
229 | |||
230 | case 7: | ||
231 | // line 62 "format_fsm.rl" | ||
232 | |||
233 | verb.Minus = true | ||
234 | |||
235 | case 8: | ||
236 | // line 65 "format_fsm.rl" | ||
237 | |||
238 | verb.Plus = true | ||
239 | |||
240 | case 9: | ||
241 | // line 68 "format_fsm.rl" | ||
242 | |||
243 | verb.Space = true | ||
244 | |||
245 | case 10: | ||
246 | // line 72 "format_fsm.rl" | ||
247 | |||
248 | verb.ArgNum = 0 | ||
249 | |||
250 | case 11: | ||
251 | // line 75 "format_fsm.rl" | ||
252 | |||
253 | verb.ArgNum = (10 * verb.ArgNum) + (int(data[p]) - '0') | ||
254 | |||
255 | case 12: | ||
256 | // line 79 "format_fsm.rl" | ||
257 | |||
258 | verb.HasWidth = true | ||
259 | |||
260 | case 13: | ||
261 | // line 82 "format_fsm.rl" | ||
262 | |||
263 | verb.Width = 0 | ||
264 | |||
265 | case 14: | ||
266 | // line 85 "format_fsm.rl" | ||
267 | |||
268 | verb.Width = (10 * verb.Width) + (int(data[p]) - '0') | ||
269 | |||
270 | case 15: | ||
271 | // line 89 "format_fsm.rl" | ||
272 | |||
273 | verb.HasPrec = true | ||
274 | |||
275 | case 16: | ||
276 | // line 92 "format_fsm.rl" | ||
277 | |||
278 | verb.Prec = 0 | ||
279 | |||
280 | case 17: | ||
281 | // line 95 "format_fsm.rl" | ||
282 | |||
283 | verb.Prec = (10 * verb.Prec) + (int(data[p]) - '0') | ||
284 | |||
285 | case 18: | ||
286 | // line 99 "format_fsm.rl" | ||
287 | |||
288 | verb.Mode = rune(data[p]) | ||
289 | te = p + 1 | ||
290 | verb.Raw = data[ts:te] | ||
291 | verb.Offset = ts | ||
292 | |||
293 | err := formatAppend(&verb, &buf, a) | ||
294 | if err != nil { | ||
295 | return buf.String(), err | ||
296 | } | ||
297 | nextArg = verb.ArgNum + 1 | ||
298 | |||
299 | // line 324 "format_fsm.go" | ||
300 | } | ||
301 | } | ||
302 | |||
303 | _again: | ||
304 | if cs == 0 { | ||
305 | goto _out | ||
306 | } | ||
307 | p++ | ||
308 | if p != pe { | ||
309 | goto _resume | ||
310 | } | ||
311 | _test_eof: | ||
312 | { | ||
313 | } | ||
314 | if p == eof { | ||
315 | __acts := _formatfsm_eof_actions[cs] | ||
316 | __nacts := uint(_formatfsm_actions[__acts]) | ||
317 | __acts++ | ||
318 | for ; __nacts > 0; __nacts-- { | ||
319 | __acts++ | ||
320 | switch _formatfsm_actions[__acts-1] { | ||
321 | case 2: | ||
322 | // line 42 "format_fsm.rl" | ||
323 | |||
324 | case 3: | ||
325 | // line 45 "format_fsm.rl" | ||
326 | |||
327 | return buf.String(), fmt.Errorf("invalid format string starting at offset %d", p) | ||
328 | |||
329 | case 4: | ||
330 | // line 49 "format_fsm.rl" | ||
331 | |||
332 | // We'll try to slurp a whole UTF-8 sequence here, to give the user | ||
333 | // better feedback. | ||
334 | r, _ := utf8.DecodeRuneInString(data[p:]) | ||
335 | return buf.String(), fmt.Errorf("unrecognized format character %q at offset %d", r, p) | ||
336 | |||
337 | // line 363 "format_fsm.go" | ||
338 | } | ||
339 | } | ||
340 | } | ||
341 | |||
342 | _out: | ||
343 | { | ||
344 | } | ||
345 | } | ||
346 | |||
347 | // line 171 "format_fsm.rl" | ||
348 | |||
349 | // If we fall out here without being in a final state then we've | ||
350 | // encountered something that the scanner can't match, which should | ||
351 | // be impossible (the scanner matches all bytes _somehow_) but we'll | ||
352 | // flag it anyway rather than just losing data from the end. | ||
353 | if cs < formatfsm_first_final { | ||
354 | return buf.String(), fmt.Errorf("extraneous characters beginning at offset %i", p) | ||
355 | } | ||
356 | |||
357 | return buf.String(), nil | ||
358 | } | ||
diff --git a/vendor/github.com/zclconf/go-cty/cty/function/stdlib/format_fsm.rl b/vendor/github.com/zclconf/go-cty/cty/function/stdlib/format_fsm.rl new file mode 100644 index 0000000..85d43bb --- /dev/null +++ b/vendor/github.com/zclconf/go-cty/cty/function/stdlib/format_fsm.rl | |||
@@ -0,0 +1,182 @@ | |||
1 | // This file is generated from format_fsm.rl. DO NOT EDIT. | ||
2 | %%{ | ||
3 | # (except you are actually in scan_tokens.rl here, so edit away!) | ||
4 | machine formatfsm; | ||
5 | }%% | ||
6 | |||
7 | package stdlib | ||
8 | |||
9 | import ( | ||
10 | "bytes" | ||
11 | "fmt" | ||
12 | "unicode/utf8" | ||
13 | |||
14 | "github.com/zclconf/go-cty/cty" | ||
15 | ) | ||
16 | |||
17 | %%{ | ||
18 | write data; | ||
19 | }%% | ||
20 | |||
21 | func formatFSM(format string, a []cty.Value) (string, error) { | ||
22 | var buf bytes.Buffer | ||
23 | data := format | ||
24 | nextArg := 1 // arg numbers are 1-based | ||
25 | var verb formatVerb | ||
26 | |||
27 | %%{ | ||
28 | |||
29 | action begin { | ||
30 | verb = formatVerb{ | ||
31 | ArgNum: nextArg, | ||
32 | Prec: -1, | ||
33 | Width: -1, | ||
34 | } | ||
35 | ts = p | ||
36 | } | ||
37 | |||
38 | action emit { | ||
39 | buf.WriteByte(fc); | ||
40 | } | ||
41 | |||
42 | action finish_ok { | ||
43 | } | ||
44 | |||
45 | action finish_err { | ||
46 | return buf.String(), fmt.Errorf("invalid format string starting at offset %d", p) | ||
47 | } | ||
48 | |||
49 | action err_char { | ||
50 | // We'll try to slurp a whole UTF-8 sequence here, to give the user | ||
51 | // better feedback. | ||
52 | r, _ := utf8.DecodeRuneInString(data[p:]) | ||
53 | return buf.String(), fmt.Errorf("unrecognized format character %q at offset %d", r, p) | ||
54 | } | ||
55 | |||
56 | action flag_sharp { | ||
57 | verb.Sharp = true | ||
58 | } | ||
59 | action flag_zero { | ||
60 | verb.Zero = true | ||
61 | } | ||
62 | action flag_minus { | ||
63 | verb.Minus = true | ||
64 | } | ||
65 | action flag_plus { | ||
66 | verb.Plus = true | ||
67 | } | ||
68 | action flag_space { | ||
69 | verb.Space = true | ||
70 | } | ||
71 | |||
72 | action argidx_reset { | ||
73 | verb.ArgNum = 0 | ||
74 | } | ||
75 | action argidx_num { | ||
76 | verb.ArgNum = (10 * verb.ArgNum) + (int(fc) - '0') | ||
77 | } | ||
78 | |||
79 | action has_width { | ||
80 | verb.HasWidth = true | ||
81 | } | ||
82 | action width_reset { | ||
83 | verb.Width = 0 | ||
84 | } | ||
85 | action width_num { | ||
86 | verb.Width = (10 * verb.Width) + (int(fc) - '0') | ||
87 | } | ||
88 | |||
89 | action has_prec { | ||
90 | verb.HasPrec = true | ||
91 | } | ||
92 | action prec_reset { | ||
93 | verb.Prec = 0 | ||
94 | } | ||
95 | action prec_num { | ||
96 | verb.Prec = (10 * verb.Prec) + (int(fc) - '0') | ||
97 | } | ||
98 | |||
99 | action mode { | ||
100 | verb.Mode = rune(fc) | ||
101 | te = p+1 | ||
102 | verb.Raw = data[ts:te] | ||
103 | verb.Offset = ts | ||
104 | |||
105 | err := formatAppend(&verb, &buf, a) | ||
106 | if err != nil { | ||
107 | return buf.String(), err | ||
108 | } | ||
109 | nextArg = verb.ArgNum + 1 | ||
110 | } | ||
111 | |||
112 | # a number that isn't zero and doesn't have a leading zero | ||
113 | num = [1-9] [0-9]*; | ||
114 | |||
115 | flags = ( | ||
116 | '0' @flag_zero | | ||
117 | '#' @flag_sharp | | ||
118 | '-' @flag_minus | | ||
119 | '+' @flag_plus | | ||
120 | ' ' @flag_space | ||
121 | )*; | ||
122 | |||
123 | argidx = (( | ||
124 | '[' (num $argidx_num) ']' | ||
125 | ) >argidx_reset)?; | ||
126 | |||
127 | width = ( | ||
128 | ( num $width_num ) >width_reset %has_width | ||
129 | )?; | ||
130 | |||
131 | precision = ( | ||
132 | ('.' ( digit* $prec_num )) >prec_reset %has_prec | ||
133 | )?; | ||
134 | |||
135 | # We accept any letter here, but will be more picky in formatAppend | ||
136 | mode = ('a'..'z' | 'A'..'Z') @mode; | ||
137 | |||
138 | fmt_verb = ( | ||
139 | '%' @begin | ||
140 | flags | ||
141 | width | ||
142 | precision | ||
143 | argidx | ||
144 | mode | ||
145 | ); | ||
146 | |||
147 | main := ( | ||
148 | [^%] @emit | | ||
149 | '%%' @emit | | ||
150 | fmt_verb | ||
151 | )* @/finish_err %/finish_ok $!err_char; | ||
152 | |||
153 | }%% | ||
154 | |||
155 | // Ragel state | ||
156 | p := 0 // "Pointer" into data | ||
157 | pe := len(data) // End-of-data "pointer" | ||
158 | cs := 0 // current state (will be initialized by ragel-generated code) | ||
159 | ts := 0 | ||
160 | te := 0 | ||
161 | eof := pe | ||
162 | |||
163 | // Keep Go compiler happy even if generated code doesn't use these | ||
164 | _ = ts | ||
165 | _ = te | ||
166 | _ = eof | ||
167 | |||
168 | %%{ | ||
169 | write init; | ||
170 | write exec; | ||
171 | }%% | ||
172 | |||
173 | // If we fall out here without being in a final state then we've | ||
174 | // encountered something that the scanner can't match, which should | ||
175 | // be impossible (the scanner matches all bytes _somehow_) but we'll | ||
176 | // flag it anyway rather than just losing data from the end. | ||
177 | if cs < formatfsm_first_final { | ||
178 | return buf.String(), fmt.Errorf("extraneous characters beginning at offset %i", p) | ||
179 | } | ||
180 | |||
181 | return buf.String(), nil | ||
182 | } | ||
diff --git a/vendor/github.com/zclconf/go-cty/cty/function/stdlib/general.go b/vendor/github.com/zclconf/go-cty/cty/function/stdlib/general.go new file mode 100644 index 0000000..6b31f26 --- /dev/null +++ b/vendor/github.com/zclconf/go-cty/cty/function/stdlib/general.go | |||
@@ -0,0 +1,107 @@ | |||
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 EqualFunc = function.New(&function.Spec{ | ||
12 | Params: []function.Parameter{ | ||
13 | { | ||
14 | Name: "a", | ||
15 | Type: cty.DynamicPseudoType, | ||
16 | AllowUnknown: true, | ||
17 | AllowDynamicType: true, | ||
18 | AllowNull: true, | ||
19 | }, | ||
20 | { | ||
21 | Name: "b", | ||
22 | Type: cty.DynamicPseudoType, | ||
23 | AllowUnknown: true, | ||
24 | AllowDynamicType: true, | ||
25 | AllowNull: true, | ||
26 | }, | ||
27 | }, | ||
28 | Type: function.StaticReturnType(cty.Bool), | ||
29 | Impl: func(args []cty.Value, retType cty.Type) (ret cty.Value, err error) { | ||
30 | return args[0].Equals(args[1]), nil | ||
31 | }, | ||
32 | }) | ||
33 | |||
34 | var NotEqualFunc = function.New(&function.Spec{ | ||
35 | Params: []function.Parameter{ | ||
36 | { | ||
37 | Name: "a", | ||
38 | Type: cty.DynamicPseudoType, | ||
39 | AllowUnknown: true, | ||
40 | AllowDynamicType: true, | ||
41 | AllowNull: true, | ||
42 | }, | ||
43 | { | ||
44 | Name: "b", | ||
45 | Type: cty.DynamicPseudoType, | ||
46 | AllowUnknown: true, | ||
47 | AllowDynamicType: true, | ||
48 | AllowNull: true, | ||
49 | }, | ||
50 | }, | ||
51 | Type: function.StaticReturnType(cty.Bool), | ||
52 | Impl: func(args []cty.Value, retType cty.Type) (ret cty.Value, err error) { | ||
53 | return args[0].Equals(args[1]).Not(), nil | ||
54 | }, | ||
55 | }) | ||
56 | |||
57 | var CoalesceFunc = function.New(&function.Spec{ | ||
58 | Params: []function.Parameter{}, | ||
59 | VarParam: &function.Parameter{ | ||
60 | Name: "vals", | ||
61 | Type: cty.DynamicPseudoType, | ||
62 | AllowUnknown: true, | ||
63 | AllowDynamicType: true, | ||
64 | AllowNull: true, | ||
65 | }, | ||
66 | Type: func(args []cty.Value) (ret cty.Type, err error) { | ||
67 | argTypes := make([]cty.Type, len(args)) | ||
68 | for i, val := range args { | ||
69 | argTypes[i] = val.Type() | ||
70 | } | ||
71 | retType, _ := convert.UnifyUnsafe(argTypes) | ||
72 | if retType == cty.NilType { | ||
73 | return cty.NilType, fmt.Errorf("all arguments must have the same type") | ||
74 | } | ||
75 | return retType, nil | ||
76 | }, | ||
77 | Impl: func(args []cty.Value, retType cty.Type) (ret cty.Value, err error) { | ||
78 | for _, argVal := range args { | ||
79 | if !argVal.IsKnown() { | ||
80 | return cty.UnknownVal(retType), nil | ||
81 | } | ||
82 | if argVal.IsNull() { | ||
83 | continue | ||
84 | } | ||
85 | |||
86 | return convert.Convert(argVal, retType) | ||
87 | } | ||
88 | return cty.NilVal, fmt.Errorf("no non-null arguments") | ||
89 | }, | ||
90 | }) | ||
91 | |||
92 | // Equal determines whether the two given values are equal, returning a | ||
93 | // bool value. | ||
94 | func Equal(a cty.Value, b cty.Value) (cty.Value, error) { | ||
95 | return EqualFunc.Call([]cty.Value{a, b}) | ||
96 | } | ||
97 | |||
98 | // NotEqual is the opposite of Equal. | ||
99 | func NotEqual(a cty.Value, b cty.Value) (cty.Value, error) { | ||
100 | return NotEqualFunc.Call([]cty.Value{a, b}) | ||
101 | } | ||
102 | |||
103 | // Coalesce returns the first of the given arguments that is not null. If | ||
104 | // all arguments are null, an error is produced. | ||
105 | func Coalesce(vals ...cty.Value) (cty.Value, error) { | ||
106 | return CoalesceFunc.Call(vals) | ||
107 | } | ||
diff --git a/vendor/github.com/zclconf/go-cty/cty/function/stdlib/json.go b/vendor/github.com/zclconf/go-cty/cty/function/stdlib/json.go new file mode 100644 index 0000000..07901c6 --- /dev/null +++ b/vendor/github.com/zclconf/go-cty/cty/function/stdlib/json.go | |||
@@ -0,0 +1,72 @@ | |||
1 | package stdlib | ||
2 | |||
3 | import ( | ||
4 | "github.com/zclconf/go-cty/cty" | ||
5 | "github.com/zclconf/go-cty/cty/function" | ||
6 | "github.com/zclconf/go-cty/cty/json" | ||
7 | ) | ||
8 | |||
9 | var JSONEncodeFunc = function.New(&function.Spec{ | ||
10 | Params: []function.Parameter{ | ||
11 | { | ||
12 | Name: "val", | ||
13 | Type: cty.DynamicPseudoType, | ||
14 | AllowDynamicType: true, | ||
15 | }, | ||
16 | }, | ||
17 | Type: function.StaticReturnType(cty.String), | ||
18 | Impl: func(args []cty.Value, retType cty.Type) (cty.Value, error) { | ||
19 | val := args[0] | ||
20 | if !val.IsWhollyKnown() { | ||
21 | // We can't serialize unknowns, so if the value is unknown or | ||
22 | // contains any _nested_ unknowns then our result must be | ||
23 | // unknown. | ||
24 | return cty.UnknownVal(retType), nil | ||
25 | } | ||
26 | |||
27 | buf, err := json.Marshal(val, val.Type()) | ||
28 | if err != nil { | ||
29 | return cty.NilVal, err | ||
30 | } | ||
31 | |||
32 | return cty.StringVal(string(buf)), nil | ||
33 | }, | ||
34 | }) | ||
35 | |||
36 | var JSONDecodeFunc = function.New(&function.Spec{ | ||
37 | Params: []function.Parameter{ | ||
38 | { | ||
39 | Name: "str", | ||
40 | Type: cty.String, | ||
41 | }, | ||
42 | }, | ||
43 | Type: func(args []cty.Value) (cty.Type, error) { | ||
44 | str := args[0] | ||
45 | if !str.IsKnown() { | ||
46 | return cty.DynamicPseudoType, nil | ||
47 | } | ||
48 | |||
49 | buf := []byte(str.AsString()) | ||
50 | return json.ImpliedType(buf) | ||
51 | }, | ||
52 | Impl: func(args []cty.Value, retType cty.Type) (cty.Value, error) { | ||
53 | buf := []byte(args[0].AsString()) | ||
54 | return json.Unmarshal(buf, retType) | ||
55 | }, | ||
56 | }) | ||
57 | |||
58 | // JSONEncode returns a JSON serialization of the given value. | ||
59 | func JSONEncode(val cty.Value) (cty.Value, error) { | ||
60 | return JSONEncodeFunc.Call([]cty.Value{val}) | ||
61 | } | ||
62 | |||
63 | // JSONDecode parses the given JSON string and, if it is valid, returns the | ||
64 | // value it represents. | ||
65 | // | ||
66 | // Note that applying JSONDecode to the result of JSONEncode may not produce | ||
67 | // an identically-typed result, since JSON encoding is lossy for cty Types. | ||
68 | // The resulting value will consist only of primitive types, object types, and | ||
69 | // tuple types. | ||
70 | func JSONDecode(str cty.Value) (cty.Value, error) { | ||
71 | return JSONDecodeFunc.Call([]cty.Value{str}) | ||
72 | } | ||
diff --git a/vendor/github.com/zclconf/go-cty/cty/function/stdlib/number.go b/vendor/github.com/zclconf/go-cty/cty/function/stdlib/number.go new file mode 100644 index 0000000..bd9b2e5 --- /dev/null +++ b/vendor/github.com/zclconf/go-cty/cty/function/stdlib/number.go | |||
@@ -0,0 +1,428 @@ | |||
1 | package stdlib | ||
2 | |||
3 | import ( | ||
4 | "fmt" | ||
5 | "math/big" | ||
6 | |||
7 | "github.com/zclconf/go-cty/cty" | ||
8 | "github.com/zclconf/go-cty/cty/function" | ||
9 | ) | ||
10 | |||
11 | var AbsoluteFunc = function.New(&function.Spec{ | ||
12 | Params: []function.Parameter{ | ||
13 | { | ||
14 | Name: "num", | ||
15 | Type: cty.Number, | ||
16 | AllowDynamicType: true, | ||
17 | }, | ||
18 | }, | ||
19 | Type: function.StaticReturnType(cty.Number), | ||
20 | Impl: func(args []cty.Value, retType cty.Type) (cty.Value, error) { | ||
21 | return args[0].Absolute(), nil | ||
22 | }, | ||
23 | }) | ||
24 | |||
25 | var AddFunc = function.New(&function.Spec{ | ||
26 | Params: []function.Parameter{ | ||
27 | { | ||
28 | Name: "a", | ||
29 | Type: cty.Number, | ||
30 | AllowDynamicType: true, | ||
31 | }, | ||
32 | { | ||
33 | Name: "b", | ||
34 | Type: cty.Number, | ||
35 | AllowDynamicType: true, | ||
36 | }, | ||
37 | }, | ||
38 | Type: function.StaticReturnType(cty.Number), | ||
39 | Impl: func(args []cty.Value, retType cty.Type) (ret cty.Value, err error) { | ||
40 | // big.Float.Add can panic if the input values are opposing infinities, | ||
41 | // so we must catch that here in order to remain within | ||
42 | // the cty Function abstraction. | ||
43 | defer func() { | ||
44 | if r := recover(); r != nil { | ||
45 | if _, ok := r.(big.ErrNaN); ok { | ||
46 | ret = cty.NilVal | ||
47 | err = fmt.Errorf("can't compute sum of opposing infinities") | ||
48 | } else { | ||
49 | // not a panic we recognize | ||
50 | panic(r) | ||
51 | } | ||
52 | } | ||
53 | }() | ||
54 | return args[0].Add(args[1]), nil | ||
55 | }, | ||
56 | }) | ||
57 | |||
58 | var SubtractFunc = function.New(&function.Spec{ | ||
59 | Params: []function.Parameter{ | ||
60 | { | ||
61 | Name: "a", | ||
62 | Type: cty.Number, | ||
63 | AllowDynamicType: true, | ||
64 | }, | ||
65 | { | ||
66 | Name: "b", | ||
67 | Type: cty.Number, | ||
68 | AllowDynamicType: true, | ||
69 | }, | ||
70 | }, | ||
71 | Type: function.StaticReturnType(cty.Number), | ||
72 | Impl: func(args []cty.Value, retType cty.Type) (ret cty.Value, err error) { | ||
73 | // big.Float.Sub can panic if the input values are infinities, | ||
74 | // so we must catch that here in order to remain within | ||
75 | // the cty Function abstraction. | ||
76 | defer func() { | ||
77 | if r := recover(); r != nil { | ||
78 | if _, ok := r.(big.ErrNaN); ok { | ||
79 | ret = cty.NilVal | ||
80 | err = fmt.Errorf("can't subtract infinity from itself") | ||
81 | } else { | ||
82 | // not a panic we recognize | ||
83 | panic(r) | ||
84 | } | ||
85 | } | ||
86 | }() | ||
87 | return args[0].Subtract(args[1]), nil | ||
88 | }, | ||
89 | }) | ||
90 | |||
91 | var MultiplyFunc = function.New(&function.Spec{ | ||
92 | Params: []function.Parameter{ | ||
93 | { | ||
94 | Name: "a", | ||
95 | Type: cty.Number, | ||
96 | AllowDynamicType: true, | ||
97 | }, | ||
98 | { | ||
99 | Name: "b", | ||
100 | Type: cty.Number, | ||
101 | AllowDynamicType: true, | ||
102 | }, | ||
103 | }, | ||
104 | Type: function.StaticReturnType(cty.Number), | ||
105 | Impl: func(args []cty.Value, retType cty.Type) (ret cty.Value, err error) { | ||
106 | // big.Float.Mul can panic if the input values are both zero or both | ||
107 | // infinity, so we must catch that here in order to remain within | ||
108 | // the cty Function abstraction. | ||
109 | defer func() { | ||
110 | if r := recover(); r != nil { | ||
111 | if _, ok := r.(big.ErrNaN); ok { | ||
112 | ret = cty.NilVal | ||
113 | err = fmt.Errorf("can't multiply zero by infinity") | ||
114 | } else { | ||
115 | // not a panic we recognize | ||
116 | panic(r) | ||
117 | } | ||
118 | } | ||
119 | }() | ||
120 | |||
121 | return args[0].Multiply(args[1]), nil | ||
122 | }, | ||
123 | }) | ||
124 | |||
125 | var DivideFunc = function.New(&function.Spec{ | ||
126 | Params: []function.Parameter{ | ||
127 | { | ||
128 | Name: "a", | ||
129 | Type: cty.Number, | ||
130 | AllowDynamicType: true, | ||
131 | }, | ||
132 | { | ||
133 | Name: "b", | ||
134 | Type: cty.Number, | ||
135 | AllowDynamicType: true, | ||
136 | }, | ||
137 | }, | ||
138 | Type: function.StaticReturnType(cty.Number), | ||
139 | Impl: func(args []cty.Value, retType cty.Type) (ret cty.Value, err error) { | ||
140 | // big.Float.Quo can panic if the input values are both zero or both | ||
141 | // infinity, so we must catch that here in order to remain within | ||
142 | // the cty Function abstraction. | ||
143 | defer func() { | ||
144 | if r := recover(); r != nil { | ||
145 | if _, ok := r.(big.ErrNaN); ok { | ||
146 | ret = cty.NilVal | ||
147 | err = fmt.Errorf("can't divide zero by zero or infinity by infinity") | ||
148 | } else { | ||
149 | // not a panic we recognize | ||
150 | panic(r) | ||
151 | } | ||
152 | } | ||
153 | }() | ||
154 | |||
155 | return args[0].Divide(args[1]), nil | ||
156 | }, | ||
157 | }) | ||
158 | |||
159 | var ModuloFunc = function.New(&function.Spec{ | ||
160 | Params: []function.Parameter{ | ||
161 | { | ||
162 | Name: "a", | ||
163 | Type: cty.Number, | ||
164 | AllowDynamicType: true, | ||
165 | }, | ||
166 | { | ||
167 | Name: "b", | ||
168 | Type: cty.Number, | ||
169 | AllowDynamicType: true, | ||
170 | }, | ||
171 | }, | ||
172 | Type: function.StaticReturnType(cty.Number), | ||
173 | Impl: func(args []cty.Value, retType cty.Type) (ret cty.Value, err error) { | ||
174 | // big.Float.Mul can panic if the input values are both zero or both | ||
175 | // infinity, so we must catch that here in order to remain within | ||
176 | // the cty Function abstraction. | ||
177 | defer func() { | ||
178 | if r := recover(); r != nil { | ||
179 | if _, ok := r.(big.ErrNaN); ok { | ||
180 | ret = cty.NilVal | ||
181 | err = fmt.Errorf("can't use modulo with zero and infinity") | ||
182 | } else { | ||
183 | // not a panic we recognize | ||
184 | panic(r) | ||
185 | } | ||
186 | } | ||
187 | }() | ||
188 | |||
189 | return args[0].Modulo(args[1]), nil | ||
190 | }, | ||
191 | }) | ||
192 | |||
193 | var GreaterThanFunc = function.New(&function.Spec{ | ||
194 | Params: []function.Parameter{ | ||
195 | { | ||
196 | Name: "a", | ||
197 | Type: cty.Number, | ||
198 | AllowDynamicType: true, | ||
199 | }, | ||
200 | { | ||
201 | Name: "b", | ||
202 | Type: cty.Number, | ||
203 | AllowDynamicType: true, | ||
204 | }, | ||
205 | }, | ||
206 | Type: function.StaticReturnType(cty.Bool), | ||
207 | Impl: func(args []cty.Value, retType cty.Type) (ret cty.Value, err error) { | ||
208 | return args[0].GreaterThan(args[1]), nil | ||
209 | }, | ||
210 | }) | ||
211 | |||
212 | var GreaterThanOrEqualToFunc = function.New(&function.Spec{ | ||
213 | Params: []function.Parameter{ | ||
214 | { | ||
215 | Name: "a", | ||
216 | Type: cty.Number, | ||
217 | AllowDynamicType: true, | ||
218 | }, | ||
219 | { | ||
220 | Name: "b", | ||
221 | Type: cty.Number, | ||
222 | AllowDynamicType: true, | ||
223 | }, | ||
224 | }, | ||
225 | Type: function.StaticReturnType(cty.Bool), | ||
226 | Impl: func(args []cty.Value, retType cty.Type) (ret cty.Value, err error) { | ||
227 | return args[0].GreaterThanOrEqualTo(args[1]), nil | ||
228 | }, | ||
229 | }) | ||
230 | |||
231 | var LessThanFunc = function.New(&function.Spec{ | ||
232 | Params: []function.Parameter{ | ||
233 | { | ||
234 | Name: "a", | ||
235 | Type: cty.Number, | ||
236 | AllowDynamicType: true, | ||
237 | }, | ||
238 | { | ||
239 | Name: "b", | ||
240 | Type: cty.Number, | ||
241 | AllowDynamicType: true, | ||
242 | }, | ||
243 | }, | ||
244 | Type: function.StaticReturnType(cty.Bool), | ||
245 | Impl: func(args []cty.Value, retType cty.Type) (ret cty.Value, err error) { | ||
246 | return args[0].LessThan(args[1]), nil | ||
247 | }, | ||
248 | }) | ||
249 | |||
250 | var LessThanOrEqualToFunc = function.New(&function.Spec{ | ||
251 | Params: []function.Parameter{ | ||
252 | { | ||
253 | Name: "a", | ||
254 | Type: cty.Number, | ||
255 | AllowDynamicType: true, | ||
256 | }, | ||
257 | { | ||
258 | Name: "b", | ||
259 | Type: cty.Number, | ||
260 | AllowDynamicType: true, | ||
261 | }, | ||
262 | }, | ||
263 | Type: function.StaticReturnType(cty.Bool), | ||
264 | Impl: func(args []cty.Value, retType cty.Type) (ret cty.Value, err error) { | ||
265 | return args[0].LessThanOrEqualTo(args[1]), nil | ||
266 | }, | ||
267 | }) | ||
268 | |||
269 | var NegateFunc = function.New(&function.Spec{ | ||
270 | Params: []function.Parameter{ | ||
271 | { | ||
272 | Name: "num", | ||
273 | Type: cty.Number, | ||
274 | AllowDynamicType: true, | ||
275 | }, | ||
276 | }, | ||
277 | Type: function.StaticReturnType(cty.Number), | ||
278 | Impl: func(args []cty.Value, retType cty.Type) (cty.Value, error) { | ||
279 | return args[0].Negate(), nil | ||
280 | }, | ||
281 | }) | ||
282 | |||
283 | var MinFunc = function.New(&function.Spec{ | ||
284 | Params: []function.Parameter{}, | ||
285 | VarParam: &function.Parameter{ | ||
286 | Name: "numbers", | ||
287 | Type: cty.Number, | ||
288 | AllowDynamicType: true, | ||
289 | }, | ||
290 | Type: function.StaticReturnType(cty.Number), | ||
291 | Impl: func(args []cty.Value, retType cty.Type) (cty.Value, error) { | ||
292 | if len(args) == 0 { | ||
293 | return cty.NilVal, fmt.Errorf("must pass at least one number") | ||
294 | } | ||
295 | |||
296 | min := cty.PositiveInfinity | ||
297 | for _, num := range args { | ||
298 | if num.LessThan(min).True() { | ||
299 | min = num | ||
300 | } | ||
301 | } | ||
302 | |||
303 | return min, nil | ||
304 | }, | ||
305 | }) | ||
306 | |||
307 | var MaxFunc = function.New(&function.Spec{ | ||
308 | Params: []function.Parameter{}, | ||
309 | VarParam: &function.Parameter{ | ||
310 | Name: "numbers", | ||
311 | Type: cty.Number, | ||
312 | AllowDynamicType: true, | ||
313 | }, | ||
314 | Type: function.StaticReturnType(cty.Number), | ||
315 | Impl: func(args []cty.Value, retType cty.Type) (cty.Value, error) { | ||
316 | if len(args) == 0 { | ||
317 | return cty.NilVal, fmt.Errorf("must pass at least one number") | ||
318 | } | ||
319 | |||
320 | max := cty.NegativeInfinity | ||
321 | for _, num := range args { | ||
322 | if num.GreaterThan(max).True() { | ||
323 | max = num | ||
324 | } | ||
325 | } | ||
326 | |||
327 | return max, nil | ||
328 | }, | ||
329 | }) | ||
330 | |||
331 | var IntFunc = function.New(&function.Spec{ | ||
332 | Params: []function.Parameter{ | ||
333 | { | ||
334 | Name: "num", | ||
335 | Type: cty.Number, | ||
336 | AllowDynamicType: true, | ||
337 | }, | ||
338 | }, | ||
339 | Type: function.StaticReturnType(cty.Number), | ||
340 | Impl: func(args []cty.Value, retType cty.Type) (cty.Value, error) { | ||
341 | bf := args[0].AsBigFloat() | ||
342 | if bf.IsInt() { | ||
343 | return args[0], nil | ||
344 | } | ||
345 | bi, _ := bf.Int(nil) | ||
346 | bf = (&big.Float{}).SetInt(bi) | ||
347 | return cty.NumberVal(bf), nil | ||
348 | }, | ||
349 | }) | ||
350 | |||
351 | // Absolute returns the magnitude of the given number, without its sign. | ||
352 | // That is, it turns negative values into positive values. | ||
353 | func Absolute(num cty.Value) (cty.Value, error) { | ||
354 | return AbsoluteFunc.Call([]cty.Value{num}) | ||
355 | } | ||
356 | |||
357 | // Add returns the sum of the two given numbers. | ||
358 | func Add(a cty.Value, b cty.Value) (cty.Value, error) { | ||
359 | return AddFunc.Call([]cty.Value{a, b}) | ||
360 | } | ||
361 | |||
362 | // Subtract returns the difference between the two given numbers. | ||
363 | func Subtract(a cty.Value, b cty.Value) (cty.Value, error) { | ||
364 | return SubtractFunc.Call([]cty.Value{a, b}) | ||
365 | } | ||
366 | |||
367 | // Multiply returns the product of the two given numbers. | ||
368 | func Multiply(a cty.Value, b cty.Value) (cty.Value, error) { | ||
369 | return MultiplyFunc.Call([]cty.Value{a, b}) | ||
370 | } | ||
371 | |||
372 | // Divide returns a divided by b, where both a and b are numbers. | ||
373 | func Divide(a cty.Value, b cty.Value) (cty.Value, error) { | ||
374 | return DivideFunc.Call([]cty.Value{a, b}) | ||
375 | } | ||
376 | |||
377 | // Negate returns the given number multipled by -1. | ||
378 | func Negate(num cty.Value) (cty.Value, error) { | ||
379 | return NegateFunc.Call([]cty.Value{num}) | ||
380 | } | ||
381 | |||
382 | // LessThan returns true if a is less than b. | ||
383 | func LessThan(a cty.Value, b cty.Value) (cty.Value, error) { | ||
384 | return LessThanFunc.Call([]cty.Value{a, b}) | ||
385 | } | ||
386 | |||
387 | // LessThanOrEqualTo returns true if a is less than b. | ||
388 | func LessThanOrEqualTo(a cty.Value, b cty.Value) (cty.Value, error) { | ||
389 | return LessThanOrEqualToFunc.Call([]cty.Value{a, b}) | ||
390 | } | ||
391 | |||
392 | // GreaterThan returns true if a is less than b. | ||
393 | func GreaterThan(a cty.Value, b cty.Value) (cty.Value, error) { | ||
394 | return GreaterThanFunc.Call([]cty.Value{a, b}) | ||
395 | } | ||
396 | |||
397 | // GreaterThanOrEqualTo returns true if a is less than b. | ||
398 | func GreaterThanOrEqualTo(a cty.Value, b cty.Value) (cty.Value, error) { | ||
399 | return GreaterThanOrEqualToFunc.Call([]cty.Value{a, b}) | ||
400 | } | ||
401 | |||
402 | // Modulo returns the remainder of a divided by b under integer division, | ||
403 | // where both a and b are numbers. | ||
404 | func Modulo(a cty.Value, b cty.Value) (cty.Value, error) { | ||
405 | return ModuloFunc.Call([]cty.Value{a, b}) | ||
406 | } | ||
407 | |||
408 | // Min returns the minimum number from the given numbers. | ||
409 | func Min(numbers ...cty.Value) (cty.Value, error) { | ||
410 | return MinFunc.Call(numbers) | ||
411 | } | ||
412 | |||
413 | // Max returns the maximum number from the given numbers. | ||
414 | func Max(numbers ...cty.Value) (cty.Value, error) { | ||
415 | return MaxFunc.Call(numbers) | ||
416 | } | ||
417 | |||
418 | // Int removes the fractional component of the given number returning an | ||
419 | // integer representing the whole number component, rounding towards zero. | ||
420 | // For example, -1.5 becomes -1. | ||
421 | // | ||
422 | // If an infinity is passed to Int, an error is returned. | ||
423 | func Int(num cty.Value) (cty.Value, error) { | ||
424 | if num == cty.PositiveInfinity || num == cty.NegativeInfinity { | ||
425 | return cty.NilVal, fmt.Errorf("can't truncate infinity to an integer") | ||
426 | } | ||
427 | return IntFunc.Call([]cty.Value{num}) | ||
428 | } | ||
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 | } | ||
diff --git a/vendor/github.com/zclconf/go-cty/cty/function/stdlib/set.go b/vendor/github.com/zclconf/go-cty/cty/function/stdlib/set.go new file mode 100644 index 0000000..100078f --- /dev/null +++ b/vendor/github.com/zclconf/go-cty/cty/function/stdlib/set.go | |||
@@ -0,0 +1,195 @@ | |||
1 | package stdlib | ||
2 | |||
3 | import ( | ||
4 | "fmt" | ||
5 | |||
6 | "github.com/zclconf/go-cty/cty/convert" | ||
7 | |||
8 | "github.com/zclconf/go-cty/cty" | ||
9 | "github.com/zclconf/go-cty/cty/function" | ||
10 | ) | ||
11 | |||
12 | var SetHasElementFunc = function.New(&function.Spec{ | ||
13 | Params: []function.Parameter{ | ||
14 | { | ||
15 | Name: "set", | ||
16 | Type: cty.Set(cty.DynamicPseudoType), | ||
17 | AllowDynamicType: true, | ||
18 | }, | ||
19 | { | ||
20 | Name: "elem", | ||
21 | Type: cty.DynamicPseudoType, | ||
22 | AllowDynamicType: true, | ||
23 | }, | ||
24 | }, | ||
25 | Type: function.StaticReturnType(cty.Bool), | ||
26 | Impl: func(args []cty.Value, retType cty.Type) (ret cty.Value, err error) { | ||
27 | return args[0].HasElement(args[1]), nil | ||
28 | }, | ||
29 | }) | ||
30 | |||
31 | var SetUnionFunc = function.New(&function.Spec{ | ||
32 | Params: []function.Parameter{ | ||
33 | { | ||
34 | Name: "first_set", | ||
35 | Type: cty.Set(cty.DynamicPseudoType), | ||
36 | AllowDynamicType: true, | ||
37 | }, | ||
38 | }, | ||
39 | VarParam: &function.Parameter{ | ||
40 | Name: "other_sets", | ||
41 | Type: cty.Set(cty.DynamicPseudoType), | ||
42 | AllowDynamicType: true, | ||
43 | }, | ||
44 | Type: setOperationReturnType, | ||
45 | Impl: setOperationImpl(func(s1, s2 cty.ValueSet) cty.ValueSet { | ||
46 | return s1.Union(s2) | ||
47 | }), | ||
48 | }) | ||
49 | |||
50 | var SetIntersectionFunc = function.New(&function.Spec{ | ||
51 | Params: []function.Parameter{ | ||
52 | { | ||
53 | Name: "first_set", | ||
54 | Type: cty.Set(cty.DynamicPseudoType), | ||
55 | AllowDynamicType: true, | ||
56 | }, | ||
57 | }, | ||
58 | VarParam: &function.Parameter{ | ||
59 | Name: "other_sets", | ||
60 | Type: cty.Set(cty.DynamicPseudoType), | ||
61 | AllowDynamicType: true, | ||
62 | }, | ||
63 | Type: setOperationReturnType, | ||
64 | Impl: setOperationImpl(func(s1, s2 cty.ValueSet) cty.ValueSet { | ||
65 | return s1.Intersection(s2) | ||
66 | }), | ||
67 | }) | ||
68 | |||
69 | var SetSubtractFunc = function.New(&function.Spec{ | ||
70 | Params: []function.Parameter{ | ||
71 | { | ||
72 | Name: "a", | ||
73 | Type: cty.Set(cty.DynamicPseudoType), | ||
74 | AllowDynamicType: true, | ||
75 | }, | ||
76 | { | ||
77 | Name: "b", | ||
78 | Type: cty.Set(cty.DynamicPseudoType), | ||
79 | AllowDynamicType: true, | ||
80 | }, | ||
81 | }, | ||
82 | Type: setOperationReturnType, | ||
83 | Impl: setOperationImpl(func(s1, s2 cty.ValueSet) cty.ValueSet { | ||
84 | return s1.Subtract(s2) | ||
85 | }), | ||
86 | }) | ||
87 | |||
88 | var SetSymmetricDifferenceFunc = function.New(&function.Spec{ | ||
89 | Params: []function.Parameter{ | ||
90 | { | ||
91 | Name: "first_set", | ||
92 | Type: cty.Set(cty.DynamicPseudoType), | ||
93 | AllowDynamicType: true, | ||
94 | }, | ||
95 | }, | ||
96 | VarParam: &function.Parameter{ | ||
97 | Name: "other_sets", | ||
98 | Type: cty.Set(cty.DynamicPseudoType), | ||
99 | AllowDynamicType: true, | ||
100 | }, | ||
101 | Type: setOperationReturnType, | ||
102 | Impl: setOperationImpl(func(s1, s2 cty.ValueSet) cty.ValueSet { | ||
103 | return s1.Subtract(s2) | ||
104 | }), | ||
105 | }) | ||
106 | |||
107 | // SetHasElement determines whether the given set contains the given value as an | ||
108 | // element. | ||
109 | func SetHasElement(set cty.Value, elem cty.Value) (cty.Value, error) { | ||
110 | return SetHasElementFunc.Call([]cty.Value{set, elem}) | ||
111 | } | ||
112 | |||
113 | // SetUnion returns a new set containing all of the elements from the given | ||
114 | // sets, which must have element types that can all be converted to some | ||
115 | // common type using the standard type unification rules. If conversion | ||
116 | // is not possible, an error is returned. | ||
117 | // | ||
118 | // The union operation is performed after type conversion, which may result | ||
119 | // in some previously-distinct values being conflated. | ||
120 | // | ||
121 | // At least one set must be provided. | ||
122 | func SetUnion(sets ...cty.Value) (cty.Value, error) { | ||
123 | return SetUnionFunc.Call(sets) | ||
124 | } | ||
125 | |||
126 | // Intersection returns a new set containing the elements that exist | ||
127 | // in all of the given sets, which must have element types that can all be | ||
128 | // converted to some common type using the standard type unification rules. | ||
129 | // If conversion is not possible, an error is returned. | ||
130 | // | ||
131 | // The intersection operation is performed after type conversion, which may | ||
132 | // result in some previously-distinct values being conflated. | ||
133 | // | ||
134 | // At least one set must be provided. | ||
135 | func SetIntersection(sets ...cty.Value) (cty.Value, error) { | ||
136 | return SetIntersectionFunc.Call(sets) | ||
137 | } | ||
138 | |||
139 | // SetSubtract returns a new set containing the elements from the | ||
140 | // first set that are not present in the second set. The sets must have | ||
141 | // element types that can both be converted to some common type using the | ||
142 | // standard type unification rules. If conversion is not possible, an error | ||
143 | // is returned. | ||
144 | // | ||
145 | // The subtract operation is performed after type conversion, which may | ||
146 | // result in some previously-distinct values being conflated. | ||
147 | func SetSubtract(a, b cty.Value) (cty.Value, error) { | ||
148 | return SetSubtractFunc.Call([]cty.Value{a, b}) | ||
149 | } | ||
150 | |||
151 | // SetSymmetricDifference returns a new set containing elements that appear | ||
152 | // in any of the given sets but not multiple. The sets must have | ||
153 | // element types that can all be converted to some common type using the | ||
154 | // standard type unification rules. If conversion is not possible, an error | ||
155 | // is returned. | ||
156 | // | ||
157 | // The difference operation is performed after type conversion, which may | ||
158 | // result in some previously-distinct values being conflated. | ||
159 | func SetSymmetricDifference(sets ...cty.Value) (cty.Value, error) { | ||
160 | return SetSymmetricDifferenceFunc.Call(sets) | ||
161 | } | ||
162 | |||
163 | func setOperationReturnType(args []cty.Value) (ret cty.Type, err error) { | ||
164 | var etys []cty.Type | ||
165 | for _, arg := range args { | ||
166 | etys = append(etys, arg.Type().ElementType()) | ||
167 | } | ||
168 | newEty, _ := convert.UnifyUnsafe(etys) | ||
169 | if newEty == cty.NilType { | ||
170 | return cty.NilType, fmt.Errorf("given sets must all have compatible element types") | ||
171 | } | ||
172 | return cty.Set(newEty), nil | ||
173 | } | ||
174 | |||
175 | func setOperationImpl(f func(s1, s2 cty.ValueSet) cty.ValueSet) function.ImplFunc { | ||
176 | return func(args []cty.Value, retType cty.Type) (ret cty.Value, err error) { | ||
177 | first := args[0] | ||
178 | first, err = convert.Convert(first, retType) | ||
179 | if err != nil { | ||
180 | return cty.NilVal, function.NewArgError(0, err) | ||
181 | } | ||
182 | |||
183 | set := first.AsValueSet() | ||
184 | for i, arg := range args[1:] { | ||
185 | arg, err := convert.Convert(arg, retType) | ||
186 | if err != nil { | ||
187 | return cty.NilVal, function.NewArgError(i+1, err) | ||
188 | } | ||
189 | |||
190 | argSet := arg.AsValueSet() | ||
191 | set = f(set, argSet) | ||
192 | } | ||
193 | return cty.SetValFromValueSet(set), nil | ||
194 | } | ||
195 | } | ||
diff --git a/vendor/github.com/zclconf/go-cty/cty/function/stdlib/string.go b/vendor/github.com/zclconf/go-cty/cty/function/stdlib/string.go new file mode 100644 index 0000000..d7c89fa --- /dev/null +++ b/vendor/github.com/zclconf/go-cty/cty/function/stdlib/string.go | |||
@@ -0,0 +1,234 @@ | |||
1 | package stdlib | ||
2 | |||
3 | import ( | ||
4 | "strings" | ||
5 | |||
6 | "github.com/zclconf/go-cty/cty" | ||
7 | "github.com/zclconf/go-cty/cty/function" | ||
8 | "github.com/zclconf/go-cty/cty/gocty" | ||
9 | "github.com/apparentlymart/go-textseg/textseg" | ||
10 | ) | ||
11 | |||
12 | var UpperFunc = function.New(&function.Spec{ | ||
13 | Params: []function.Parameter{ | ||
14 | { | ||
15 | Name: "str", | ||
16 | Type: cty.String, | ||
17 | AllowDynamicType: true, | ||
18 | }, | ||
19 | }, | ||
20 | Type: function.StaticReturnType(cty.String), | ||
21 | Impl: func(args []cty.Value, retType cty.Type) (cty.Value, error) { | ||
22 | in := args[0].AsString() | ||
23 | out := strings.ToUpper(in) | ||
24 | return cty.StringVal(out), nil | ||
25 | }, | ||
26 | }) | ||
27 | |||
28 | var LowerFunc = function.New(&function.Spec{ | ||
29 | Params: []function.Parameter{ | ||
30 | { | ||
31 | Name: "str", | ||
32 | Type: cty.String, | ||
33 | AllowDynamicType: true, | ||
34 | }, | ||
35 | }, | ||
36 | Type: function.StaticReturnType(cty.String), | ||
37 | Impl: func(args []cty.Value, retType cty.Type) (cty.Value, error) { | ||
38 | in := args[0].AsString() | ||
39 | out := strings.ToLower(in) | ||
40 | return cty.StringVal(out), nil | ||
41 | }, | ||
42 | }) | ||
43 | |||
44 | var ReverseFunc = function.New(&function.Spec{ | ||
45 | Params: []function.Parameter{ | ||
46 | { | ||
47 | Name: "str", | ||
48 | Type: cty.String, | ||
49 | AllowDynamicType: true, | ||
50 | }, | ||
51 | }, | ||
52 | Type: function.StaticReturnType(cty.String), | ||
53 | Impl: func(args []cty.Value, retType cty.Type) (cty.Value, error) { | ||
54 | in := []byte(args[0].AsString()) | ||
55 | out := make([]byte, len(in)) | ||
56 | pos := len(out) | ||
57 | |||
58 | inB := []byte(in) | ||
59 | for i := 0; i < len(in); { | ||
60 | d, _, _ := textseg.ScanGraphemeClusters(inB[i:], true) | ||
61 | cluster := in[i : i+d] | ||
62 | pos -= len(cluster) | ||
63 | copy(out[pos:], cluster) | ||
64 | i += d | ||
65 | } | ||
66 | |||
67 | return cty.StringVal(string(out)), nil | ||
68 | }, | ||
69 | }) | ||
70 | |||
71 | var StrlenFunc = function.New(&function.Spec{ | ||
72 | Params: []function.Parameter{ | ||
73 | { | ||
74 | Name: "str", | ||
75 | Type: cty.String, | ||
76 | AllowDynamicType: true, | ||
77 | }, | ||
78 | }, | ||
79 | Type: function.StaticReturnType(cty.Number), | ||
80 | Impl: func(args []cty.Value, retType cty.Type) (cty.Value, error) { | ||
81 | in := args[0].AsString() | ||
82 | l := 0 | ||
83 | |||
84 | inB := []byte(in) | ||
85 | for i := 0; i < len(in); { | ||
86 | d, _, _ := textseg.ScanGraphemeClusters(inB[i:], true) | ||
87 | l++ | ||
88 | i += d | ||
89 | } | ||
90 | |||
91 | return cty.NumberIntVal(int64(l)), nil | ||
92 | }, | ||
93 | }) | ||
94 | |||
95 | var SubstrFunc = function.New(&function.Spec{ | ||
96 | Params: []function.Parameter{ | ||
97 | { | ||
98 | Name: "str", | ||
99 | Type: cty.String, | ||
100 | AllowDynamicType: true, | ||
101 | }, | ||
102 | { | ||
103 | Name: "offset", | ||
104 | Type: cty.Number, | ||
105 | AllowDynamicType: true, | ||
106 | }, | ||
107 | { | ||
108 | Name: "length", | ||
109 | Type: cty.Number, | ||
110 | AllowDynamicType: true, | ||
111 | }, | ||
112 | }, | ||
113 | Type: function.StaticReturnType(cty.String), | ||
114 | Impl: func(args []cty.Value, retType cty.Type) (cty.Value, error) { | ||
115 | in := []byte(args[0].AsString()) | ||
116 | var offset, length int | ||
117 | |||
118 | var err error | ||
119 | err = gocty.FromCtyValue(args[1], &offset) | ||
120 | if err != nil { | ||
121 | return cty.NilVal, err | ||
122 | } | ||
123 | err = gocty.FromCtyValue(args[2], &length) | ||
124 | if err != nil { | ||
125 | return cty.NilVal, err | ||
126 | } | ||
127 | |||
128 | if offset < 0 { | ||
129 | totalLenNum, err := Strlen(args[0]) | ||
130 | if err != nil { | ||
131 | // should never happen | ||
132 | panic("Stdlen returned an error") | ||
133 | } | ||
134 | |||
135 | var totalLen int | ||
136 | err = gocty.FromCtyValue(totalLenNum, &totalLen) | ||
137 | if err != nil { | ||
138 | // should never happen | ||
139 | panic("Stdlen returned a non-int number") | ||
140 | } | ||
141 | |||
142 | offset += totalLen | ||
143 | } | ||
144 | |||
145 | sub := in | ||
146 | pos := 0 | ||
147 | var i int | ||
148 | |||
149 | // First we'll seek forward to our offset | ||
150 | if offset > 0 { | ||
151 | for i = 0; i < len(sub); { | ||
152 | d, _, _ := textseg.ScanGraphemeClusters(sub[i:], true) | ||
153 | i += d | ||
154 | pos++ | ||
155 | if pos == offset { | ||
156 | break | ||
157 | } | ||
158 | if i >= len(in) { | ||
159 | return cty.StringVal(""), nil | ||
160 | } | ||
161 | } | ||
162 | |||
163 | sub = sub[i:] | ||
164 | } | ||
165 | |||
166 | if length < 0 { | ||
167 | // Taking the remainder of the string is a fast path since | ||
168 | // we can just return the rest of the buffer verbatim. | ||
169 | return cty.StringVal(string(sub)), nil | ||
170 | } | ||
171 | |||
172 | // Otherwise we need to start seeking forward again until we | ||
173 | // reach the length we want. | ||
174 | pos = 0 | ||
175 | for i = 0; i < len(sub); { | ||
176 | d, _, _ := textseg.ScanGraphemeClusters(sub[i:], true) | ||
177 | i += d | ||
178 | pos++ | ||
179 | if pos == length { | ||
180 | break | ||
181 | } | ||
182 | } | ||
183 | |||
184 | sub = sub[:i] | ||
185 | |||
186 | return cty.StringVal(string(sub)), nil | ||
187 | }, | ||
188 | }) | ||
189 | |||
190 | // Upper is a Function that converts a given string to uppercase. | ||
191 | func Upper(str cty.Value) (cty.Value, error) { | ||
192 | return UpperFunc.Call([]cty.Value{str}) | ||
193 | } | ||
194 | |||
195 | // Lower is a Function that converts a given string to lowercase. | ||
196 | func Lower(str cty.Value) (cty.Value, error) { | ||
197 | return LowerFunc.Call([]cty.Value{str}) | ||
198 | } | ||
199 | |||
200 | // Reverse is a Function that reverses the order of the characters in the | ||
201 | // given string. | ||
202 | // | ||
203 | // As usual, "character" for the sake of this function is a grapheme cluster, | ||
204 | // so combining diacritics (for example) will be considered together as a | ||
205 | // single character. | ||
206 | func Reverse(str cty.Value) (cty.Value, error) { | ||
207 | return ReverseFunc.Call([]cty.Value{str}) | ||
208 | } | ||
209 | |||
210 | // Strlen is a Function that returns the length of the given string in | ||
211 | // characters. | ||
212 | // | ||
213 | // As usual, "character" for the sake of this function is a grapheme cluster, | ||
214 | // so combining diacritics (for example) will be considered together as a | ||
215 | // single character. | ||
216 | func Strlen(str cty.Value) (cty.Value, error) { | ||
217 | return StrlenFunc.Call([]cty.Value{str}) | ||
218 | } | ||
219 | |||
220 | // Substr is a Function that extracts a sequence of characters from another | ||
221 | // string and creates a new string. | ||
222 | // | ||
223 | // As usual, "character" for the sake of this function is a grapheme cluster, | ||
224 | // so combining diacritics (for example) will be considered together as a | ||
225 | // single character. | ||
226 | // | ||
227 | // The "offset" index may be negative, in which case it is relative to the | ||
228 | // end of the given string. | ||
229 | // | ||
230 | // The "length" may be -1, in which case the remainder of the string after | ||
231 | // the given offset will be returned. | ||
232 | func Substr(str cty.Value, offset cty.Value, length cty.Value) (cty.Value, error) { | ||
233 | return SubstrFunc.Call([]cty.Value{str, offset, length}) | ||
234 | } | ||
diff --git a/vendor/github.com/zclconf/go-cty/cty/function/unpredictable.go b/vendor/github.com/zclconf/go-cty/cty/function/unpredictable.go new file mode 100644 index 0000000..3495550 --- /dev/null +++ b/vendor/github.com/zclconf/go-cty/cty/function/unpredictable.go | |||
@@ -0,0 +1,31 @@ | |||
1 | package function | ||
2 | |||
3 | import ( | ||
4 | "github.com/zclconf/go-cty/cty" | ||
5 | ) | ||
6 | |||
7 | // Unpredictable wraps a given function such that it retains the same arguments | ||
8 | // and type checking behavior but will return an unknown value when called. | ||
9 | // | ||
10 | // It is recommended that most functions be "pure", which is to say that they | ||
11 | // will always produce the same value given particular input. However, | ||
12 | // sometimes it is necessary to offer functions whose behavior depends on | ||
13 | // some external state, such as reading a file or determining the current time. | ||
14 | // In such cases, an unpredictable wrapper might be used to stand in for | ||
15 | // the function during some sort of prior "checking" phase in order to delay | ||
16 | // the actual effect until later. | ||
17 | // | ||
18 | // While Unpredictable can support a function that isn't pure in its | ||
19 | // implementation, it still expects a function to be pure in its type checking | ||
20 | // behavior, except for the special case of returning cty.DynamicPseudoType | ||
21 | // if it is not yet able to predict its return value based on current argument | ||
22 | // information. | ||
23 | func Unpredictable(f Function) Function { | ||
24 | newSpec := *f.spec // shallow copy | ||
25 | newSpec.Impl = unpredictableImpl | ||
26 | return New(&newSpec) | ||
27 | } | ||
28 | |||
29 | func unpredictableImpl(args []cty.Value, retType cty.Type) (cty.Value, error) { | ||
30 | return cty.UnknownVal(retType), nil | ||
31 | } | ||
diff --git a/vendor/github.com/zclconf/go-cty/cty/gob.go b/vendor/github.com/zclconf/go-cty/cty/gob.go new file mode 100644 index 0000000..3d73199 --- /dev/null +++ b/vendor/github.com/zclconf/go-cty/cty/gob.go | |||
@@ -0,0 +1,125 @@ | |||
1 | package cty | ||
2 | |||
3 | import ( | ||
4 | "bytes" | ||
5 | "encoding/gob" | ||
6 | "fmt" | ||
7 | "math/big" | ||
8 | ) | ||
9 | |||
10 | // GobEncode is an implementation of the gob.GobEncoder interface, which | ||
11 | // allows Values to be included in structures encoded with encoding/gob. | ||
12 | // | ||
13 | // Currently it is not possible to represent values of capsule types in gob, | ||
14 | // because the types themselves cannot be represented. | ||
15 | func (val Value) GobEncode() ([]byte, error) { | ||
16 | buf := &bytes.Buffer{} | ||
17 | enc := gob.NewEncoder(buf) | ||
18 | |||
19 | gv := gobValue{ | ||
20 | Version: 0, | ||
21 | Ty: val.ty, | ||
22 | V: val.v, | ||
23 | } | ||
24 | |||
25 | err := enc.Encode(gv) | ||
26 | if err != nil { | ||
27 | return nil, fmt.Errorf("error encoding cty.Value: %s", err) | ||
28 | } | ||
29 | |||
30 | return buf.Bytes(), nil | ||
31 | } | ||
32 | |||
33 | // GobDecode is an implementation of the gob.GobDecoder interface, which | ||
34 | // inverts the operation performed by GobEncode. See the documentation of | ||
35 | // GobEncode for considerations when using cty.Value instances with gob. | ||
36 | func (val *Value) GobDecode(buf []byte) error { | ||
37 | r := bytes.NewReader(buf) | ||
38 | dec := gob.NewDecoder(r) | ||
39 | |||
40 | var gv gobValue | ||
41 | err := dec.Decode(&gv) | ||
42 | if err != nil { | ||
43 | return fmt.Errorf("error decoding cty.Value: %s", err) | ||
44 | } | ||
45 | if gv.Version != 0 { | ||
46 | return fmt.Errorf("unsupported cty.Value encoding version %d; only 0 is supported", gv.Version) | ||
47 | } | ||
48 | |||
49 | // big.Float seems to, for some reason, lose its "pointerness" when we | ||
50 | // round-trip it, so we'll fix that here. | ||
51 | if bf, ok := gv.V.(big.Float); ok { | ||
52 | gv.V = &bf | ||
53 | } | ||
54 | |||
55 | val.ty = gv.Ty | ||
56 | val.v = gv.V | ||
57 | |||
58 | return nil | ||
59 | } | ||
60 | |||
61 | // GobEncode is an implementation of the gob.GobEncoder interface, which | ||
62 | // allows Types to be included in structures encoded with encoding/gob. | ||
63 | // | ||
64 | // Currently it is not possible to represent capsule types in gob. | ||
65 | func (t Type) GobEncode() ([]byte, error) { | ||
66 | buf := &bytes.Buffer{} | ||
67 | enc := gob.NewEncoder(buf) | ||
68 | |||
69 | gt := gobType{ | ||
70 | Version: 0, | ||
71 | Impl: t.typeImpl, | ||
72 | } | ||
73 | |||
74 | err := enc.Encode(gt) | ||
75 | if err != nil { | ||
76 | return nil, fmt.Errorf("error encoding cty.Type: %s", err) | ||
77 | } | ||
78 | |||
79 | return buf.Bytes(), nil | ||
80 | } | ||
81 | |||
82 | // GobDecode is an implementatino of the gob.GobDecoder interface, which | ||
83 | // reverses the encoding performed by GobEncode to allow types to be recovered | ||
84 | // from gob buffers. | ||
85 | func (t *Type) GobDecode(buf []byte) error { | ||
86 | r := bytes.NewReader(buf) | ||
87 | dec := gob.NewDecoder(r) | ||
88 | |||
89 | var gt gobType | ||
90 | err := dec.Decode(>) | ||
91 | if err != nil { | ||
92 | return fmt.Errorf("error decoding cty.Type: %s", err) | ||
93 | } | ||
94 | if gt.Version != 0 { | ||
95 | return fmt.Errorf("unsupported cty.Type encoding version %d; only 0 is supported", gt.Version) | ||
96 | } | ||
97 | |||
98 | t.typeImpl = gt.Impl | ||
99 | |||
100 | return nil | ||
101 | } | ||
102 | |||
103 | // Capsule types cannot currently be gob-encoded, because they rely on pointer | ||
104 | // equality and we have no way to recover the original pointer on decode. | ||
105 | func (t *capsuleType) GobEncode() ([]byte, error) { | ||
106 | return nil, fmt.Errorf("cannot gob-encode capsule type %q", t.FriendlyName()) | ||
107 | } | ||
108 | |||
109 | func (t *capsuleType) GobDecode() ([]byte, error) { | ||
110 | return nil, fmt.Errorf("cannot gob-decode capsule type %q", t.FriendlyName()) | ||
111 | } | ||
112 | |||
113 | type gobValue struct { | ||
114 | Version int | ||
115 | Ty Type | ||
116 | V interface{} | ||
117 | } | ||
118 | |||
119 | type gobType struct { | ||
120 | Version int | ||
121 | Impl typeImpl | ||
122 | } | ||
123 | |||
124 | type gobCapsuleTypeImpl struct { | ||
125 | } | ||
diff --git a/vendor/github.com/zclconf/go-cty/cty/gocty/doc.go b/vendor/github.com/zclconf/go-cty/cty/gocty/doc.go new file mode 100644 index 0000000..a5177d2 --- /dev/null +++ b/vendor/github.com/zclconf/go-cty/cty/gocty/doc.go | |||
@@ -0,0 +1,7 @@ | |||
1 | // Package gocty deals with converting between cty Values and native go | ||
2 | // values. | ||
3 | // | ||
4 | // It operates under a similar principle to the encoding/json and | ||
5 | // encoding/xml packages in the standard library, using reflection to | ||
6 | // populate native Go data structures from cty values and vice-versa. | ||
7 | package gocty | ||
diff --git a/vendor/github.com/zclconf/go-cty/cty/gocty/helpers.go b/vendor/github.com/zclconf/go-cty/cty/gocty/helpers.go new file mode 100644 index 0000000..94ffd2f --- /dev/null +++ b/vendor/github.com/zclconf/go-cty/cty/gocty/helpers.go | |||
@@ -0,0 +1,43 @@ | |||
1 | package gocty | ||
2 | |||
3 | import ( | ||
4 | "math/big" | ||
5 | "reflect" | ||
6 | |||
7 | "github.com/zclconf/go-cty/cty" | ||
8 | "github.com/zclconf/go-cty/cty/set" | ||
9 | ) | ||
10 | |||
11 | var valueType = reflect.TypeOf(cty.Value{}) | ||
12 | var typeType = reflect.TypeOf(cty.Type{}) | ||
13 | |||
14 | var setType = reflect.TypeOf(set.Set{}) | ||
15 | |||
16 | var bigFloatType = reflect.TypeOf(big.Float{}) | ||
17 | var bigIntType = reflect.TypeOf(big.Int{}) | ||
18 | |||
19 | var emptyInterfaceType = reflect.TypeOf(interface{}(nil)) | ||
20 | |||
21 | var stringType = reflect.TypeOf("") | ||
22 | |||
23 | // structTagIndices interrogates the fields of the given type (which must | ||
24 | // be a struct type, or we'll panic) and returns a map from the cty | ||
25 | // attribute names declared via struct tags to the indices of the | ||
26 | // fields holding those tags. | ||
27 | // | ||
28 | // This function will panic if two fields within the struct are tagged with | ||
29 | // the same cty attribute name. | ||
30 | func structTagIndices(st reflect.Type) map[string]int { | ||
31 | ct := st.NumField() | ||
32 | ret := make(map[string]int, ct) | ||
33 | |||
34 | for i := 0; i < ct; i++ { | ||
35 | field := st.Field(i) | ||
36 | attrName := field.Tag.Get("cty") | ||
37 | if attrName != "" { | ||
38 | ret[attrName] = i | ||
39 | } | ||
40 | } | ||
41 | |||
42 | return ret | ||
43 | } | ||
diff --git a/vendor/github.com/zclconf/go-cty/cty/gocty/in.go b/vendor/github.com/zclconf/go-cty/cty/gocty/in.go new file mode 100644 index 0000000..642501b --- /dev/null +++ b/vendor/github.com/zclconf/go-cty/cty/gocty/in.go | |||
@@ -0,0 +1,528 @@ | |||
1 | package gocty | ||
2 | |||
3 | import ( | ||
4 | "math/big" | ||
5 | "reflect" | ||
6 | |||
7 | "github.com/zclconf/go-cty/cty" | ||
8 | "github.com/zclconf/go-cty/cty/set" | ||
9 | ) | ||
10 | |||
11 | // ToCtyValue produces a cty.Value from a Go value. The result will conform | ||
12 | // to the given type, or an error will be returned if this is not possible. | ||
13 | // | ||
14 | // The target type serves as a hint to resolve ambiguities in the mapping. | ||
15 | // For example, the Go type set.Set tells us that the value is a set but | ||
16 | // does not describe the set's element type. This also allows for convenient | ||
17 | // conversions, such as populating a set from a slice rather than having to | ||
18 | // first explicitly instantiate a set.Set. | ||
19 | // | ||
20 | // The audience of this function is assumed to be the developers of Go code | ||
21 | // that is integrating with cty, and thus the error messages it returns are | ||
22 | // presented from Go's perspective. These messages are thus not appropriate | ||
23 | // for display to end-users. An error returned from ToCtyValue represents a | ||
24 | // bug in the calling program, not user error. | ||
25 | func ToCtyValue(val interface{}, ty cty.Type) (cty.Value, error) { | ||
26 | // 'path' starts off as empty but will grow for each level of recursive | ||
27 | // call we make, so by the time toCtyValue returns it is likely to have | ||
28 | // unused capacity on the end of it, depending on how deeply-recursive | ||
29 | // the given Type is. | ||
30 | path := make(cty.Path, 0) | ||
31 | return toCtyValue(reflect.ValueOf(val), ty, path) | ||
32 | } | ||
33 | |||
34 | func toCtyValue(val reflect.Value, ty cty.Type, path cty.Path) (cty.Value, error) { | ||
35 | |||
36 | switch ty { | ||
37 | case cty.Bool: | ||
38 | return toCtyBool(val, path) | ||
39 | case cty.Number: | ||
40 | return toCtyNumber(val, path) | ||
41 | case cty.String: | ||
42 | return toCtyString(val, path) | ||
43 | case cty.DynamicPseudoType: | ||
44 | return toCtyDynamic(val, path) | ||
45 | } | ||
46 | |||
47 | switch { | ||
48 | case ty.IsListType(): | ||
49 | return toCtyList(val, ty.ElementType(), path) | ||
50 | case ty.IsMapType(): | ||
51 | return toCtyMap(val, ty.ElementType(), path) | ||
52 | case ty.IsSetType(): | ||
53 | return toCtySet(val, ty.ElementType(), path) | ||
54 | case ty.IsObjectType(): | ||
55 | return toCtyObject(val, ty.AttributeTypes(), path) | ||
56 | case ty.IsTupleType(): | ||
57 | return toCtyTuple(val, ty.TupleElementTypes(), path) | ||
58 | case ty.IsCapsuleType(): | ||
59 | return toCtyCapsule(val, ty, path) | ||
60 | } | ||
61 | |||
62 | // We should never fall out here | ||
63 | return cty.NilVal, path.NewErrorf("unsupported target type %#v", ty) | ||
64 | } | ||
65 | |||
66 | func toCtyBool(val reflect.Value, path cty.Path) (cty.Value, error) { | ||
67 | if val = toCtyUnwrapPointer(val); !val.IsValid() { | ||
68 | return cty.NullVal(cty.Bool), nil | ||
69 | } | ||
70 | |||
71 | switch val.Kind() { | ||
72 | |||
73 | case reflect.Bool: | ||
74 | return cty.BoolVal(val.Bool()), nil | ||
75 | |||
76 | default: | ||
77 | return cty.NilVal, path.NewErrorf("can't convert Go %s to bool", val.Kind()) | ||
78 | |||
79 | } | ||
80 | |||
81 | } | ||
82 | |||
83 | func toCtyNumber(val reflect.Value, path cty.Path) (cty.Value, error) { | ||
84 | if val = toCtyUnwrapPointer(val); !val.IsValid() { | ||
85 | return cty.NullVal(cty.Number), nil | ||
86 | } | ||
87 | |||
88 | switch val.Kind() { | ||
89 | |||
90 | case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: | ||
91 | return cty.NumberIntVal(val.Int()), nil | ||
92 | |||
93 | case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: | ||
94 | return cty.NumberUIntVal(val.Uint()), nil | ||
95 | |||
96 | case reflect.Float32, reflect.Float64: | ||
97 | return cty.NumberFloatVal(val.Float()), nil | ||
98 | |||
99 | case reflect.Struct: | ||
100 | if val.Type().AssignableTo(bigIntType) { | ||
101 | bigInt := val.Interface().(big.Int) | ||
102 | bigFloat := (&big.Float{}).SetInt(&bigInt) | ||
103 | val = reflect.ValueOf(*bigFloat) | ||
104 | } | ||
105 | |||
106 | if val.Type().AssignableTo(bigFloatType) { | ||
107 | bigFloat := val.Interface().(big.Float) | ||
108 | return cty.NumberVal(&bigFloat), nil | ||
109 | } | ||
110 | |||
111 | fallthrough | ||
112 | default: | ||
113 | return cty.NilVal, path.NewErrorf("can't convert Go %s to number", val.Kind()) | ||
114 | |||
115 | } | ||
116 | |||
117 | } | ||
118 | |||
119 | func toCtyString(val reflect.Value, path cty.Path) (cty.Value, error) { | ||
120 | if val = toCtyUnwrapPointer(val); !val.IsValid() { | ||
121 | return cty.NullVal(cty.String), nil | ||
122 | } | ||
123 | |||
124 | switch val.Kind() { | ||
125 | |||
126 | case reflect.String: | ||
127 | return cty.StringVal(val.String()), nil | ||
128 | |||
129 | default: | ||
130 | return cty.NilVal, path.NewErrorf("can't convert Go %s to string", val.Kind()) | ||
131 | |||
132 | } | ||
133 | |||
134 | } | ||
135 | |||
136 | func toCtyList(val reflect.Value, ety cty.Type, path cty.Path) (cty.Value, error) { | ||
137 | if val = toCtyUnwrapPointer(val); !val.IsValid() { | ||
138 | return cty.NullVal(cty.List(ety)), nil | ||
139 | } | ||
140 | |||
141 | switch val.Kind() { | ||
142 | |||
143 | case reflect.Slice: | ||
144 | if val.IsNil() { | ||
145 | return cty.NullVal(cty.List(ety)), nil | ||
146 | } | ||
147 | fallthrough | ||
148 | case reflect.Array: | ||
149 | if val.Len() == 0 { | ||
150 | return cty.ListValEmpty(ety), nil | ||
151 | } | ||
152 | |||
153 | // While we work on our elements we'll temporarily grow | ||
154 | // path to give us a place to put our index step. | ||
155 | path = append(path, cty.PathStep(nil)) | ||
156 | |||
157 | vals := make([]cty.Value, val.Len()) | ||
158 | for i := range vals { | ||
159 | var err error | ||
160 | path[len(path)-1] = cty.IndexStep{ | ||
161 | Key: cty.NumberIntVal(int64(i)), | ||
162 | } | ||
163 | vals[i], err = toCtyValue(val.Index(i), ety, path) | ||
164 | if err != nil { | ||
165 | return cty.NilVal, err | ||
166 | } | ||
167 | } | ||
168 | |||
169 | // Discard our extra path segment, retaining it as extra capacity | ||
170 | // for future appending to the path. | ||
171 | path = path[:len(path)-1] | ||
172 | |||
173 | return cty.ListVal(vals), nil | ||
174 | |||
175 | default: | ||
176 | return cty.NilVal, path.NewErrorf("can't convert Go %s to %#v", val.Kind(), cty.List(ety)) | ||
177 | |||
178 | } | ||
179 | } | ||
180 | |||
181 | func toCtyMap(val reflect.Value, ety cty.Type, path cty.Path) (cty.Value, error) { | ||
182 | if val = toCtyUnwrapPointer(val); !val.IsValid() { | ||
183 | return cty.NullVal(cty.Map(ety)), nil | ||
184 | } | ||
185 | |||
186 | switch val.Kind() { | ||
187 | |||
188 | case reflect.Map: | ||
189 | if val.IsNil() { | ||
190 | return cty.NullVal(cty.Map(ety)), nil | ||
191 | } | ||
192 | |||
193 | if val.Len() == 0 { | ||
194 | return cty.MapValEmpty(ety), nil | ||
195 | } | ||
196 | |||
197 | keyType := val.Type().Key() | ||
198 | if keyType.Kind() != reflect.String { | ||
199 | return cty.NilVal, path.NewErrorf("can't convert Go map with key type %s; key type must be string", keyType) | ||
200 | } | ||
201 | |||
202 | // While we work on our elements we'll temporarily grow | ||
203 | // path to give us a place to put our index step. | ||
204 | path = append(path, cty.PathStep(nil)) | ||
205 | |||
206 | vals := make(map[string]cty.Value, val.Len()) | ||
207 | for _, kv := range val.MapKeys() { | ||
208 | k := kv.String() | ||
209 | var err error | ||
210 | path[len(path)-1] = cty.IndexStep{ | ||
211 | Key: cty.StringVal(k), | ||
212 | } | ||
213 | vals[k], err = toCtyValue(val.MapIndex(reflect.ValueOf(k)), ety, path) | ||
214 | if err != nil { | ||
215 | return cty.NilVal, err | ||
216 | } | ||
217 | } | ||
218 | |||
219 | // Discard our extra path segment, retaining it as extra capacity | ||
220 | // for future appending to the path. | ||
221 | path = path[:len(path)-1] | ||
222 | |||
223 | return cty.MapVal(vals), nil | ||
224 | |||
225 | default: | ||
226 | return cty.NilVal, path.NewErrorf("can't convert Go %s to %#v", val.Kind(), cty.Map(ety)) | ||
227 | |||
228 | } | ||
229 | } | ||
230 | |||
231 | func toCtySet(val reflect.Value, ety cty.Type, path cty.Path) (cty.Value, error) { | ||
232 | if val = toCtyUnwrapPointer(val); !val.IsValid() { | ||
233 | return cty.NullVal(cty.Set(ety)), nil | ||
234 | } | ||
235 | |||
236 | var vals []cty.Value | ||
237 | |||
238 | switch val.Kind() { | ||
239 | |||
240 | case reflect.Slice: | ||
241 | if val.IsNil() { | ||
242 | return cty.NullVal(cty.Set(ety)), nil | ||
243 | } | ||
244 | fallthrough | ||
245 | case reflect.Array: | ||
246 | if val.Len() == 0 { | ||
247 | return cty.SetValEmpty(ety), nil | ||
248 | } | ||
249 | |||
250 | vals = make([]cty.Value, val.Len()) | ||
251 | for i := range vals { | ||
252 | var err error | ||
253 | vals[i], err = toCtyValue(val.Index(i), ety, path) | ||
254 | if err != nil { | ||
255 | return cty.NilVal, err | ||
256 | } | ||
257 | } | ||
258 | |||
259 | case reflect.Struct: | ||
260 | |||
261 | if !val.Type().AssignableTo(setType) { | ||
262 | return cty.NilVal, path.NewErrorf("can't convert Go %s to %#v", val.Type(), cty.Set(ety)) | ||
263 | } | ||
264 | |||
265 | rawSet := val.Interface().(set.Set) | ||
266 | inVals := rawSet.Values() | ||
267 | |||
268 | if len(inVals) == 0 { | ||
269 | return cty.SetValEmpty(ety), nil | ||
270 | } | ||
271 | |||
272 | vals = make([]cty.Value, len(inVals)) | ||
273 | for i := range inVals { | ||
274 | var err error | ||
275 | vals[i], err = toCtyValue(reflect.ValueOf(inVals[i]), ety, path) | ||
276 | if err != nil { | ||
277 | return cty.NilVal, err | ||
278 | } | ||
279 | } | ||
280 | |||
281 | default: | ||
282 | return cty.NilVal, path.NewErrorf("can't convert Go %s to %#v", val.Kind(), cty.Set(ety)) | ||
283 | |||
284 | } | ||
285 | |||
286 | return cty.SetVal(vals), nil | ||
287 | } | ||
288 | |||
289 | func toCtyObject(val reflect.Value, attrTypes map[string]cty.Type, path cty.Path) (cty.Value, error) { | ||
290 | if val = toCtyUnwrapPointer(val); !val.IsValid() { | ||
291 | return cty.NullVal(cty.Object(attrTypes)), nil | ||
292 | } | ||
293 | |||
294 | switch val.Kind() { | ||
295 | |||
296 | case reflect.Map: | ||
297 | if val.IsNil() { | ||
298 | return cty.NullVal(cty.Object(attrTypes)), nil | ||
299 | } | ||
300 | |||
301 | keyType := val.Type().Key() | ||
302 | if keyType.Kind() != reflect.String { | ||
303 | return cty.NilVal, path.NewErrorf("can't convert Go map with key type %s; key type must be string", keyType) | ||
304 | } | ||
305 | |||
306 | if len(attrTypes) == 0 { | ||
307 | return cty.EmptyObjectVal, nil | ||
308 | } | ||
309 | |||
310 | // While we work on our elements we'll temporarily grow | ||
311 | // path to give us a place to put our GetAttr step. | ||
312 | path = append(path, cty.PathStep(nil)) | ||
313 | |||
314 | haveKeys := make(map[string]struct{}, val.Len()) | ||
315 | for _, kv := range val.MapKeys() { | ||
316 | haveKeys[kv.String()] = struct{}{} | ||
317 | } | ||
318 | |||
319 | vals := make(map[string]cty.Value, len(attrTypes)) | ||
320 | for k, at := range attrTypes { | ||
321 | var err error | ||
322 | path[len(path)-1] = cty.GetAttrStep{ | ||
323 | Name: k, | ||
324 | } | ||
325 | |||
326 | if _, have := haveKeys[k]; !have { | ||
327 | vals[k] = cty.NullVal(at) | ||
328 | continue | ||
329 | } | ||
330 | |||
331 | vals[k], err = toCtyValue(val.MapIndex(reflect.ValueOf(k)), at, path) | ||
332 | if err != nil { | ||
333 | return cty.NilVal, err | ||
334 | } | ||
335 | } | ||
336 | |||
337 | // Discard our extra path segment, retaining it as extra capacity | ||
338 | // for future appending to the path. | ||
339 | path = path[:len(path)-1] | ||
340 | |||
341 | return cty.ObjectVal(vals), nil | ||
342 | |||
343 | case reflect.Struct: | ||
344 | if len(attrTypes) == 0 { | ||
345 | return cty.EmptyObjectVal, nil | ||
346 | } | ||
347 | |||
348 | // While we work on our elements we'll temporarily grow | ||
349 | // path to give us a place to put our GetAttr step. | ||
350 | path = append(path, cty.PathStep(nil)) | ||
351 | |||
352 | attrFields := structTagIndices(val.Type()) | ||
353 | |||
354 | vals := make(map[string]cty.Value, len(attrTypes)) | ||
355 | for k, at := range attrTypes { | ||
356 | path[len(path)-1] = cty.GetAttrStep{ | ||
357 | Name: k, | ||
358 | } | ||
359 | |||
360 | if fieldIdx, have := attrFields[k]; have { | ||
361 | var err error | ||
362 | vals[k], err = toCtyValue(val.Field(fieldIdx), at, path) | ||
363 | if err != nil { | ||
364 | return cty.NilVal, err | ||
365 | } | ||
366 | } else { | ||
367 | vals[k] = cty.NullVal(at) | ||
368 | } | ||
369 | } | ||
370 | |||
371 | // Discard our extra path segment, retaining it as extra capacity | ||
372 | // for future appending to the path. | ||
373 | path = path[:len(path)-1] | ||
374 | |||
375 | return cty.ObjectVal(vals), nil | ||
376 | |||
377 | default: | ||
378 | return cty.NilVal, path.NewErrorf("can't convert Go %s to %#v", val.Kind(), cty.Object(attrTypes)) | ||
379 | |||
380 | } | ||
381 | } | ||
382 | |||
383 | func toCtyTuple(val reflect.Value, elemTypes []cty.Type, path cty.Path) (cty.Value, error) { | ||
384 | if val = toCtyUnwrapPointer(val); !val.IsValid() { | ||
385 | return cty.NullVal(cty.Tuple(elemTypes)), nil | ||
386 | } | ||
387 | |||
388 | switch val.Kind() { | ||
389 | |||
390 | case reflect.Slice: | ||
391 | if val.IsNil() { | ||
392 | return cty.NullVal(cty.Tuple(elemTypes)), nil | ||
393 | } | ||
394 | |||
395 | if val.Len() != len(elemTypes) { | ||
396 | return cty.NilVal, path.NewErrorf("wrong number of elements %d; need %d", val.Len(), len(elemTypes)) | ||
397 | } | ||
398 | |||
399 | if len(elemTypes) == 0 { | ||
400 | return cty.EmptyTupleVal, nil | ||
401 | } | ||
402 | |||
403 | // While we work on our elements we'll temporarily grow | ||
404 | // path to give us a place to put our Index step. | ||
405 | path = append(path, cty.PathStep(nil)) | ||
406 | |||
407 | vals := make([]cty.Value, len(elemTypes)) | ||
408 | for i, ety := range elemTypes { | ||
409 | var err error | ||
410 | |||
411 | path[len(path)-1] = cty.IndexStep{ | ||
412 | Key: cty.NumberIntVal(int64(i)), | ||
413 | } | ||
414 | |||
415 | vals[i], err = toCtyValue(val.Index(i), ety, path) | ||
416 | if err != nil { | ||
417 | return cty.NilVal, err | ||
418 | } | ||
419 | } | ||
420 | |||
421 | // Discard our extra path segment, retaining it as extra capacity | ||
422 | // for future appending to the path. | ||
423 | path = path[:len(path)-1] | ||
424 | |||
425 | return cty.TupleVal(vals), nil | ||
426 | |||
427 | case reflect.Struct: | ||
428 | fieldCount := val.Type().NumField() | ||
429 | if fieldCount != len(elemTypes) { | ||
430 | return cty.NilVal, path.NewErrorf("wrong number of struct fields %d; need %d", fieldCount, len(elemTypes)) | ||
431 | } | ||
432 | |||
433 | if len(elemTypes) == 0 { | ||
434 | return cty.EmptyTupleVal, nil | ||
435 | } | ||
436 | |||
437 | // While we work on our elements we'll temporarily grow | ||
438 | // path to give us a place to put our Index step. | ||
439 | path = append(path, cty.PathStep(nil)) | ||
440 | |||
441 | vals := make([]cty.Value, len(elemTypes)) | ||
442 | for i, ety := range elemTypes { | ||
443 | var err error | ||
444 | |||
445 | path[len(path)-1] = cty.IndexStep{ | ||
446 | Key: cty.NumberIntVal(int64(i)), | ||
447 | } | ||
448 | |||
449 | vals[i], err = toCtyValue(val.Field(i), ety, path) | ||
450 | if err != nil { | ||
451 | return cty.NilVal, err | ||
452 | } | ||
453 | } | ||
454 | |||
455 | // Discard our extra path segment, retaining it as extra capacity | ||
456 | // for future appending to the path. | ||
457 | path = path[:len(path)-1] | ||
458 | |||
459 | return cty.TupleVal(vals), nil | ||
460 | |||
461 | default: | ||
462 | return cty.NilVal, path.NewErrorf("can't convert Go %s to %#v", val.Kind(), cty.Tuple(elemTypes)) | ||
463 | |||
464 | } | ||
465 | } | ||
466 | |||
467 | func toCtyCapsule(val reflect.Value, capsuleType cty.Type, path cty.Path) (cty.Value, error) { | ||
468 | if val = toCtyUnwrapPointer(val); !val.IsValid() { | ||
469 | return cty.NullVal(capsuleType), nil | ||
470 | } | ||
471 | |||
472 | if val.Kind() != reflect.Ptr { | ||
473 | if !val.CanAddr() { | ||
474 | return cty.NilVal, path.NewErrorf("source value for capsule %#v must be addressable", capsuleType) | ||
475 | } | ||
476 | |||
477 | val = val.Addr() | ||
478 | } | ||
479 | |||
480 | if !val.Type().Elem().AssignableTo(capsuleType.EncapsulatedType()) { | ||
481 | return cty.NilVal, path.NewErrorf("value of type %T not compatible with capsule %#v", val.Interface(), capsuleType) | ||
482 | } | ||
483 | |||
484 | return cty.CapsuleVal(capsuleType, val.Interface()), nil | ||
485 | } | ||
486 | |||
487 | func toCtyDynamic(val reflect.Value, path cty.Path) (cty.Value, error) { | ||
488 | if val = toCtyUnwrapPointer(val); !val.IsValid() { | ||
489 | return cty.NullVal(cty.DynamicPseudoType), nil | ||
490 | } | ||
491 | |||
492 | switch val.Kind() { | ||
493 | |||
494 | case reflect.Struct: | ||
495 | if !val.Type().AssignableTo(valueType) { | ||
496 | return cty.NilVal, path.NewErrorf("can't convert Go %s dynamically; only cty.Value allowed", val.Type()) | ||
497 | } | ||
498 | |||
499 | return val.Interface().(cty.Value), nil | ||
500 | |||
501 | default: | ||
502 | return cty.NilVal, path.NewErrorf("can't convert Go %s dynamically; only cty.Value allowed", val.Kind()) | ||
503 | |||
504 | } | ||
505 | |||
506 | } | ||
507 | |||
508 | // toCtyUnwrapPointer is a helper for dealing with Go pointers. It has three | ||
509 | // possible outcomes: | ||
510 | // | ||
511 | // - Given value isn't a pointer, so it's just returned as-is. | ||
512 | // - Given value is a non-nil pointer, in which case it is dereferenced | ||
513 | // and the result returned. | ||
514 | // - Given value is a nil pointer, in which case an invalid value is returned. | ||
515 | // | ||
516 | // For nested pointer types, like **int, they are all dereferenced in turn | ||
517 | // until a non-pointer value is found, or until a nil pointer is encountered. | ||
518 | func toCtyUnwrapPointer(val reflect.Value) reflect.Value { | ||
519 | for val.Kind() == reflect.Ptr || val.Kind() == reflect.Interface { | ||
520 | if val.IsNil() { | ||
521 | return reflect.Value{} | ||
522 | } | ||
523 | |||
524 | val = val.Elem() | ||
525 | } | ||
526 | |||
527 | return val | ||
528 | } | ||
diff --git a/vendor/github.com/zclconf/go-cty/cty/gocty/out.go b/vendor/github.com/zclconf/go-cty/cty/gocty/out.go new file mode 100644 index 0000000..99b65a7 --- /dev/null +++ b/vendor/github.com/zclconf/go-cty/cty/gocty/out.go | |||
@@ -0,0 +1,705 @@ | |||
1 | package gocty | ||
2 | |||
3 | import ( | ||
4 | "math/big" | ||
5 | "reflect" | ||
6 | |||
7 | "math" | ||
8 | |||
9 | "github.com/zclconf/go-cty/cty" | ||
10 | ) | ||
11 | |||
12 | // FromCtyValue assigns a cty.Value to a reflect.Value, which must be a pointer, | ||
13 | // using a fixed set of conversion rules. | ||
14 | // | ||
15 | // This function considers its audience to be the creator of the cty Value | ||
16 | // given, and thus the error messages it generates are (unlike with ToCtyValue) | ||
17 | // presented in cty terminology that is generally appropriate to return to | ||
18 | // end-users in applications where cty data structures are built from | ||
19 | // user-provided configuration. In particular this means that if incorrect | ||
20 | // target types are provided by the calling application the resulting error | ||
21 | // messages are likely to be confusing, since we assume that the given target | ||
22 | // type is correct and the cty.Value is where the error lies. | ||
23 | // | ||
24 | // If an error is returned, the target data structure may have been partially | ||
25 | // populated, but the degree to which this is true is an implementation | ||
26 | // detail that the calling application should not rely on. | ||
27 | // | ||
28 | // The function will panic if given a non-pointer as the Go value target, | ||
29 | // since that is considered to be a bug in the calling program. | ||
30 | func FromCtyValue(val cty.Value, target interface{}) error { | ||
31 | tVal := reflect.ValueOf(target) | ||
32 | if tVal.Kind() != reflect.Ptr { | ||
33 | panic("target value is not a pointer") | ||
34 | } | ||
35 | if tVal.IsNil() { | ||
36 | panic("target value is nil pointer") | ||
37 | } | ||
38 | |||
39 | // 'path' starts off as empty but will grow for each level of recursive | ||
40 | // call we make, so by the time fromCtyValue returns it is likely to have | ||
41 | // unused capacity on the end of it, depending on how deeply-recursive | ||
42 | // the given cty.Value is. | ||
43 | path := make(cty.Path, 0) | ||
44 | return fromCtyValue(val, tVal, path) | ||
45 | } | ||
46 | |||
47 | func fromCtyValue(val cty.Value, target reflect.Value, path cty.Path) error { | ||
48 | ty := val.Type() | ||
49 | |||
50 | deepTarget := fromCtyPopulatePtr(target, false) | ||
51 | |||
52 | // If we're decoding into a cty.Value then we just pass through the | ||
53 | // value as-is, to enable partial decoding. This is the only situation | ||
54 | // where unknown values are permitted. | ||
55 | if deepTarget.Kind() == reflect.Struct && deepTarget.Type().AssignableTo(valueType) { | ||
56 | deepTarget.Set(reflect.ValueOf(val)) | ||
57 | return nil | ||
58 | } | ||
59 | |||
60 | // Lists and maps can be nil without indirection, but everything else | ||
61 | // requires a pointer and we set it immediately to nil. | ||
62 | // We also make an exception for capsule types because we want to handle | ||
63 | // pointers specially for these. | ||
64 | // (fromCtyList and fromCtyMap must therefore deal with val.IsNull, while | ||
65 | // other types can assume no nulls after this point.) | ||
66 | if val.IsNull() && !val.Type().IsListType() && !val.Type().IsMapType() && !val.Type().IsCapsuleType() { | ||
67 | target = fromCtyPopulatePtr(target, true) | ||
68 | if target.Kind() != reflect.Ptr { | ||
69 | return path.NewErrorf("null value is not allowed") | ||
70 | } | ||
71 | |||
72 | target.Set(reflect.Zero(target.Type())) | ||
73 | return nil | ||
74 | } | ||
75 | |||
76 | target = deepTarget | ||
77 | |||
78 | if !val.IsKnown() { | ||
79 | return path.NewErrorf("value must be known") | ||
80 | } | ||
81 | |||
82 | switch ty { | ||
83 | case cty.Bool: | ||
84 | return fromCtyBool(val, target, path) | ||
85 | case cty.Number: | ||
86 | return fromCtyNumber(val, target, path) | ||
87 | case cty.String: | ||
88 | return fromCtyString(val, target, path) | ||
89 | } | ||
90 | |||
91 | switch { | ||
92 | case ty.IsListType(): | ||
93 | return fromCtyList(val, target, path) | ||
94 | case ty.IsMapType(): | ||
95 | return fromCtyMap(val, target, path) | ||
96 | case ty.IsSetType(): | ||
97 | return fromCtySet(val, target, path) | ||
98 | case ty.IsObjectType(): | ||
99 | return fromCtyObject(val, target, path) | ||
100 | case ty.IsTupleType(): | ||
101 | return fromCtyTuple(val, target, path) | ||
102 | case ty.IsCapsuleType(): | ||
103 | return fromCtyCapsule(val, target, path) | ||
104 | } | ||
105 | |||
106 | // We should never fall out here; reaching here indicates a bug in this | ||
107 | // function. | ||
108 | return path.NewErrorf("unsupported source type %#v", ty) | ||
109 | } | ||
110 | |||
111 | func fromCtyBool(val cty.Value, target reflect.Value, path cty.Path) error { | ||
112 | switch target.Kind() { | ||
113 | |||
114 | case reflect.Bool: | ||
115 | if val.True() { | ||
116 | target.Set(reflect.ValueOf(true)) | ||
117 | } else { | ||
118 | target.Set(reflect.ValueOf(false)) | ||
119 | } | ||
120 | return nil | ||
121 | |||
122 | default: | ||
123 | return likelyRequiredTypesError(path, target) | ||
124 | |||
125 | } | ||
126 | } | ||
127 | |||
128 | func fromCtyNumber(val cty.Value, target reflect.Value, path cty.Path) error { | ||
129 | bf := val.AsBigFloat() | ||
130 | |||
131 | switch target.Kind() { | ||
132 | |||
133 | case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: | ||
134 | return fromCtyNumberInt(bf, target, path) | ||
135 | |||
136 | case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: | ||
137 | return fromCtyNumberUInt(bf, target, path) | ||
138 | |||
139 | case reflect.Float32, reflect.Float64: | ||
140 | return fromCtyNumberFloat(bf, target, path) | ||
141 | |||
142 | case reflect.Struct: | ||
143 | return fromCtyNumberBig(bf, target, path) | ||
144 | |||
145 | default: | ||
146 | return likelyRequiredTypesError(path, target) | ||
147 | |||
148 | } | ||
149 | } | ||
150 | |||
151 | func fromCtyNumberInt(bf *big.Float, target reflect.Value, path cty.Path) error { | ||
152 | // Doing this with switch rather than << arithmetic because << with | ||
153 | // result >32-bits is not portable to 32-bit systems. | ||
154 | var min int64 | ||
155 | var max int64 | ||
156 | switch target.Type().Bits() { | ||
157 | case 8: | ||
158 | min = math.MinInt8 | ||
159 | max = math.MaxInt8 | ||
160 | case 16: | ||
161 | min = math.MinInt16 | ||
162 | max = math.MaxInt16 | ||
163 | case 32: | ||
164 | min = math.MinInt32 | ||
165 | max = math.MaxInt32 | ||
166 | case 64: | ||
167 | min = math.MinInt64 | ||
168 | max = math.MaxInt64 | ||
169 | default: | ||
170 | panic("weird number of bits in target int") | ||
171 | } | ||
172 | |||
173 | iv, accuracy := bf.Int64() | ||
174 | if accuracy != big.Exact || iv < min || iv > max { | ||
175 | return path.NewErrorf("value must be a whole number, between %d and %d", min, max) | ||
176 | } | ||
177 | |||
178 | target.Set(reflect.ValueOf(iv).Convert(target.Type())) | ||
179 | |||
180 | return nil | ||
181 | } | ||
182 | |||
183 | func fromCtyNumberUInt(bf *big.Float, target reflect.Value, path cty.Path) error { | ||
184 | // Doing this with switch rather than << arithmetic because << with | ||
185 | // result >32-bits is not portable to 32-bit systems. | ||
186 | var max uint64 | ||
187 | switch target.Type().Bits() { | ||
188 | case 8: | ||
189 | max = math.MaxUint8 | ||
190 | case 16: | ||
191 | max = math.MaxUint16 | ||
192 | case 32: | ||
193 | max = math.MaxUint32 | ||
194 | case 64: | ||
195 | max = math.MaxUint64 | ||
196 | default: | ||
197 | panic("weird number of bits in target uint") | ||
198 | } | ||
199 | |||
200 | iv, accuracy := bf.Uint64() | ||
201 | if accuracy != big.Exact || iv > max { | ||
202 | return path.NewErrorf("value must be a whole number, between 0 and %d inclusive", max) | ||
203 | } | ||
204 | |||
205 | target.Set(reflect.ValueOf(iv).Convert(target.Type())) | ||
206 | |||
207 | return nil | ||
208 | } | ||
209 | |||
210 | func fromCtyNumberFloat(bf *big.Float, target reflect.Value, path cty.Path) error { | ||
211 | switch target.Kind() { | ||
212 | case reflect.Float32: | ||
213 | fv, accuracy := bf.Float32() | ||
214 | if accuracy != big.Exact { | ||
215 | // We allow the precision to be truncated as part of our conversion, | ||
216 | // but we don't want to silently introduce infinities. | ||
217 | if math.IsInf(float64(fv), 0) { | ||
218 | return path.NewErrorf("value must be between %f and %f inclusive", -math.MaxFloat32, math.MaxFloat32) | ||
219 | } | ||
220 | } | ||
221 | target.Set(reflect.ValueOf(fv)) | ||
222 | return nil | ||
223 | case reflect.Float64: | ||
224 | fv, accuracy := bf.Float64() | ||
225 | if accuracy != big.Exact { | ||
226 | // We allow the precision to be truncated as part of our conversion, | ||
227 | // but we don't want to silently introduce infinities. | ||
228 | if math.IsInf(fv, 0) { | ||
229 | return path.NewErrorf("value must be between %f and %f inclusive", -math.MaxFloat64, math.MaxFloat64) | ||
230 | } | ||
231 | } | ||
232 | target.Set(reflect.ValueOf(fv)) | ||
233 | return nil | ||
234 | default: | ||
235 | panic("unsupported kind of float") | ||
236 | } | ||
237 | } | ||
238 | |||
239 | func fromCtyNumberBig(bf *big.Float, target reflect.Value, path cty.Path) error { | ||
240 | switch { | ||
241 | |||
242 | case bigFloatType.AssignableTo(target.Type()): | ||
243 | // Easy! | ||
244 | target.Set(reflect.ValueOf(bf).Elem()) | ||
245 | return nil | ||
246 | |||
247 | case bigIntType.AssignableTo(target.Type()): | ||
248 | bi, accuracy := bf.Int(nil) | ||
249 | if accuracy != big.Exact { | ||
250 | return path.NewErrorf("value must be a whole number") | ||
251 | } | ||
252 | target.Set(reflect.ValueOf(bi).Elem()) | ||
253 | return nil | ||
254 | |||
255 | default: | ||
256 | return likelyRequiredTypesError(path, target) | ||
257 | } | ||
258 | } | ||
259 | |||
260 | func fromCtyString(val cty.Value, target reflect.Value, path cty.Path) error { | ||
261 | switch target.Kind() { | ||
262 | |||
263 | case reflect.String: | ||
264 | target.Set(reflect.ValueOf(val.AsString())) | ||
265 | return nil | ||
266 | |||
267 | default: | ||
268 | return likelyRequiredTypesError(path, target) | ||
269 | |||
270 | } | ||
271 | } | ||
272 | |||
273 | func fromCtyList(val cty.Value, target reflect.Value, path cty.Path) error { | ||
274 | switch target.Kind() { | ||
275 | |||
276 | case reflect.Slice: | ||
277 | if val.IsNull() { | ||
278 | target.Set(reflect.Zero(target.Type())) | ||
279 | return nil | ||
280 | } | ||
281 | |||
282 | length := val.LengthInt() | ||
283 | tv := reflect.MakeSlice(target.Type(), length, length) | ||
284 | |||
285 | path = append(path, nil) | ||
286 | |||
287 | i := 0 | ||
288 | var err error | ||
289 | val.ForEachElement(func(key cty.Value, val cty.Value) bool { | ||
290 | path[len(path)-1] = cty.IndexStep{ | ||
291 | Key: cty.NumberIntVal(int64(i)), | ||
292 | } | ||
293 | |||
294 | targetElem := tv.Index(i) | ||
295 | err = fromCtyValue(val, targetElem, path) | ||
296 | if err != nil { | ||
297 | return true | ||
298 | } | ||
299 | |||
300 | i++ | ||
301 | return false | ||
302 | }) | ||
303 | if err != nil { | ||
304 | return err | ||
305 | } | ||
306 | |||
307 | path = path[:len(path)-1] | ||
308 | |||
309 | target.Set(tv) | ||
310 | return nil | ||
311 | |||
312 | case reflect.Array: | ||
313 | if val.IsNull() { | ||
314 | return path.NewErrorf("null value is not allowed") | ||
315 | } | ||
316 | |||
317 | length := val.LengthInt() | ||
318 | if length != target.Len() { | ||
319 | return path.NewErrorf("must be a list of length %d", target.Len()) | ||
320 | } | ||
321 | |||
322 | path = append(path, nil) | ||
323 | |||
324 | i := 0 | ||
325 | var err error | ||
326 | val.ForEachElement(func(key cty.Value, val cty.Value) bool { | ||
327 | path[len(path)-1] = cty.IndexStep{ | ||
328 | Key: cty.NumberIntVal(int64(i)), | ||
329 | } | ||
330 | |||
331 | targetElem := target.Index(i) | ||
332 | err = fromCtyValue(val, targetElem, path) | ||
333 | if err != nil { | ||
334 | return true | ||
335 | } | ||
336 | |||
337 | i++ | ||
338 | return false | ||
339 | }) | ||
340 | if err != nil { | ||
341 | return err | ||
342 | } | ||
343 | |||
344 | path = path[:len(path)-1] | ||
345 | |||
346 | return nil | ||
347 | |||
348 | default: | ||
349 | return likelyRequiredTypesError(path, target) | ||
350 | |||
351 | } | ||
352 | } | ||
353 | |||
354 | func fromCtyMap(val cty.Value, target reflect.Value, path cty.Path) error { | ||
355 | |||
356 | switch target.Kind() { | ||
357 | |||
358 | case reflect.Map: | ||
359 | if val.IsNull() { | ||
360 | target.Set(reflect.Zero(target.Type())) | ||
361 | return nil | ||
362 | } | ||
363 | |||
364 | tv := reflect.MakeMap(target.Type()) | ||
365 | et := target.Type().Elem() | ||
366 | |||
367 | path = append(path, nil) | ||
368 | |||
369 | var err error | ||
370 | val.ForEachElement(func(key cty.Value, val cty.Value) bool { | ||
371 | path[len(path)-1] = cty.IndexStep{ | ||
372 | Key: key, | ||
373 | } | ||
374 | |||
375 | ks := key.AsString() | ||
376 | |||
377 | targetElem := reflect.New(et) | ||
378 | err = fromCtyValue(val, targetElem, path) | ||
379 | |||
380 | tv.SetMapIndex(reflect.ValueOf(ks), targetElem.Elem()) | ||
381 | |||
382 | return err != nil | ||
383 | }) | ||
384 | if err != nil { | ||
385 | return err | ||
386 | } | ||
387 | |||
388 | path = path[:len(path)-1] | ||
389 | |||
390 | target.Set(tv) | ||
391 | return nil | ||
392 | |||
393 | default: | ||
394 | return likelyRequiredTypesError(path, target) | ||
395 | |||
396 | } | ||
397 | } | ||
398 | |||
399 | func fromCtySet(val cty.Value, target reflect.Value, path cty.Path) error { | ||
400 | switch target.Kind() { | ||
401 | |||
402 | case reflect.Slice: | ||
403 | if val.IsNull() { | ||
404 | target.Set(reflect.Zero(target.Type())) | ||
405 | return nil | ||
406 | } | ||
407 | |||
408 | length := val.LengthInt() | ||
409 | tv := reflect.MakeSlice(target.Type(), length, length) | ||
410 | |||
411 | i := 0 | ||
412 | var err error | ||
413 | val.ForEachElement(func(key cty.Value, val cty.Value) bool { | ||
414 | targetElem := tv.Index(i) | ||
415 | err = fromCtyValue(val, targetElem, path) | ||
416 | if err != nil { | ||
417 | return true | ||
418 | } | ||
419 | |||
420 | i++ | ||
421 | return false | ||
422 | }) | ||
423 | if err != nil { | ||
424 | return err | ||
425 | } | ||
426 | |||
427 | target.Set(tv) | ||
428 | return nil | ||
429 | |||
430 | case reflect.Array: | ||
431 | if val.IsNull() { | ||
432 | return path.NewErrorf("null value is not allowed") | ||
433 | } | ||
434 | |||
435 | length := val.LengthInt() | ||
436 | if length != target.Len() { | ||
437 | return path.NewErrorf("must be a set of length %d", target.Len()) | ||
438 | } | ||
439 | |||
440 | i := 0 | ||
441 | var err error | ||
442 | val.ForEachElement(func(key cty.Value, val cty.Value) bool { | ||
443 | targetElem := target.Index(i) | ||
444 | err = fromCtyValue(val, targetElem, path) | ||
445 | if err != nil { | ||
446 | return true | ||
447 | } | ||
448 | |||
449 | i++ | ||
450 | return false | ||
451 | }) | ||
452 | if err != nil { | ||
453 | return err | ||
454 | } | ||
455 | |||
456 | return nil | ||
457 | |||
458 | // TODO: decode into set.Set instance | ||
459 | |||
460 | default: | ||
461 | return likelyRequiredTypesError(path, target) | ||
462 | |||
463 | } | ||
464 | } | ||
465 | |||
466 | func fromCtyObject(val cty.Value, target reflect.Value, path cty.Path) error { | ||
467 | |||
468 | switch target.Kind() { | ||
469 | |||
470 | case reflect.Struct: | ||
471 | |||
472 | attrTypes := val.Type().AttributeTypes() | ||
473 | targetFields := structTagIndices(target.Type()) | ||
474 | |||
475 | path = append(path, nil) | ||
476 | |||
477 | for k, i := range targetFields { | ||
478 | if _, exists := attrTypes[k]; !exists { | ||
479 | // If the field in question isn't able to represent nil, | ||
480 | // that's an error. | ||
481 | fk := target.Field(i).Kind() | ||
482 | switch fk { | ||
483 | case reflect.Ptr, reflect.Slice, reflect.Map, reflect.Interface: | ||
484 | // okay | ||
485 | default: | ||
486 | return path.NewErrorf("missing required attribute %q", k) | ||
487 | } | ||
488 | } | ||
489 | } | ||
490 | |||
491 | for k := range attrTypes { | ||
492 | path[len(path)-1] = cty.GetAttrStep{ | ||
493 | Name: k, | ||
494 | } | ||
495 | |||
496 | fieldIdx, exists := targetFields[k] | ||
497 | if !exists { | ||
498 | return path.NewErrorf("unsupported attribute %q", k) | ||
499 | } | ||
500 | |||
501 | ev := val.GetAttr(k) | ||
502 | |||
503 | targetField := target.Field(fieldIdx) | ||
504 | err := fromCtyValue(ev, targetField, path) | ||
505 | if err != nil { | ||
506 | return err | ||
507 | } | ||
508 | } | ||
509 | |||
510 | path = path[:len(path)-1] | ||
511 | |||
512 | return nil | ||
513 | |||
514 | default: | ||
515 | return likelyRequiredTypesError(path, target) | ||
516 | |||
517 | } | ||
518 | } | ||
519 | |||
520 | func fromCtyTuple(val cty.Value, target reflect.Value, path cty.Path) error { | ||
521 | |||
522 | switch target.Kind() { | ||
523 | |||
524 | case reflect.Struct: | ||
525 | |||
526 | elemTypes := val.Type().TupleElementTypes() | ||
527 | fieldCount := target.Type().NumField() | ||
528 | |||
529 | if fieldCount != len(elemTypes) { | ||
530 | return path.NewErrorf("a tuple of %d elements is required", fieldCount) | ||
531 | } | ||
532 | |||
533 | path = append(path, nil) | ||
534 | |||
535 | for i := range elemTypes { | ||
536 | path[len(path)-1] = cty.IndexStep{ | ||
537 | Key: cty.NumberIntVal(int64(i)), | ||
538 | } | ||
539 | |||
540 | ev := val.Index(cty.NumberIntVal(int64(i))) | ||
541 | |||
542 | targetField := target.Field(i) | ||
543 | err := fromCtyValue(ev, targetField, path) | ||
544 | if err != nil { | ||
545 | return err | ||
546 | } | ||
547 | } | ||
548 | |||
549 | path = path[:len(path)-1] | ||
550 | |||
551 | return nil | ||
552 | |||
553 | default: | ||
554 | return likelyRequiredTypesError(path, target) | ||
555 | |||
556 | } | ||
557 | } | ||
558 | |||
559 | func fromCtyCapsule(val cty.Value, target reflect.Value, path cty.Path) error { | ||
560 | |||
561 | if target.Kind() == reflect.Ptr { | ||
562 | // Walk through indirection until we get to the last pointer, | ||
563 | // which we might set to null below. | ||
564 | target = fromCtyPopulatePtr(target, true) | ||
565 | |||
566 | if val.IsNull() { | ||
567 | target.Set(reflect.Zero(target.Type())) | ||
568 | return nil | ||
569 | } | ||
570 | |||
571 | // Since a capsule contains a pointer to an object, we'll preserve | ||
572 | // that pointer on the way out and thus allow the caller to recover | ||
573 | // the original object, rather than a copy of it. | ||
574 | |||
575 | eType := val.Type().EncapsulatedType() | ||
576 | |||
577 | if !eType.AssignableTo(target.Elem().Type()) { | ||
578 | // Our interface contract promises that we won't expose Go | ||
579 | // implementation details in error messages, so we need to keep | ||
580 | // this vague. This can only arise if a calling application has | ||
581 | // more than one capsule type in play and a user mixes them up. | ||
582 | return path.NewErrorf("incorrect type %s", val.Type().FriendlyName()) | ||
583 | } | ||
584 | |||
585 | target.Set(reflect.ValueOf(val.EncapsulatedValue())) | ||
586 | |||
587 | return nil | ||
588 | } else { | ||
589 | if val.IsNull() { | ||
590 | return path.NewErrorf("null value is not allowed") | ||
591 | } | ||
592 | |||
593 | // If our target isn't a pointer then we will attempt to copy | ||
594 | // the encapsulated value into it. | ||
595 | |||
596 | eType := val.Type().EncapsulatedType() | ||
597 | |||
598 | if !eType.AssignableTo(target.Type()) { | ||
599 | // Our interface contract promises that we won't expose Go | ||
600 | // implementation details in error messages, so we need to keep | ||
601 | // this vague. This can only arise if a calling application has | ||
602 | // more than one capsule type in play and a user mixes them up. | ||
603 | return path.NewErrorf("incorrect type %s", val.Type().FriendlyName()) | ||
604 | } | ||
605 | |||
606 | // We know that EncapsulatedValue is always a pointer, so we | ||
607 | // can safely call .Elem on its reflect.Value. | ||
608 | target.Set(reflect.ValueOf(val.EncapsulatedValue()).Elem()) | ||
609 | |||
610 | return nil | ||
611 | } | ||
612 | |||
613 | } | ||
614 | |||
615 | // fromCtyPopulatePtr recognizes when target is a pointer type and allocates | ||
616 | // a value to assign to that pointer, which it returns. | ||
617 | // | ||
618 | // If the given value has multiple levels of indirection, like **int, these | ||
619 | // will be processed in turn so that the return value is guaranteed to be | ||
620 | // a non-pointer. | ||
621 | // | ||
622 | // As an exception, if decodingNull is true then the returned value will be | ||
623 | // the final level of pointer, if any, so that the caller can assign it | ||
624 | // as nil to represent a null value. If the given target value is not a pointer | ||
625 | // at all then the returned value will be just the given target, so the caller | ||
626 | // must test if the returned value is a pointer before trying to assign nil | ||
627 | // to it. | ||
628 | func fromCtyPopulatePtr(target reflect.Value, decodingNull bool) reflect.Value { | ||
629 | for { | ||
630 | if target.Kind() == reflect.Interface && !target.IsNil() { | ||
631 | e := target.Elem() | ||
632 | if e.Kind() == reflect.Ptr && !e.IsNil() && (!decodingNull || e.Elem().Kind() == reflect.Ptr) { | ||
633 | target = e | ||
634 | } | ||
635 | } | ||
636 | |||
637 | if target.Kind() != reflect.Ptr { | ||
638 | break | ||
639 | } | ||
640 | |||
641 | // Stop early if we're decodingNull and we've found our last indirection | ||
642 | if target.Elem().Kind() != reflect.Ptr && decodingNull && target.CanSet() { | ||
643 | break | ||
644 | } | ||
645 | |||
646 | if target.IsNil() { | ||
647 | target.Set(reflect.New(target.Type().Elem())) | ||
648 | } | ||
649 | |||
650 | target = target.Elem() | ||
651 | } | ||
652 | return target | ||
653 | } | ||
654 | |||
655 | // likelyRequiredTypesError returns an error that states which types are | ||
656 | // acceptable by making some assumptions about what types we support for | ||
657 | // each target Go kind. It's not a precise science but it allows us to return | ||
658 | // an error message that is cty-user-oriented rather than Go-oriented. | ||
659 | // | ||
660 | // Generally these error messages should be a matter of last resort, since | ||
661 | // the calling application should be validating user-provided value types | ||
662 | // before decoding anyway. | ||
663 | func likelyRequiredTypesError(path cty.Path, target reflect.Value) error { | ||
664 | switch target.Kind() { | ||
665 | |||
666 | case reflect.Bool: | ||
667 | return path.NewErrorf("bool value is required") | ||
668 | |||
669 | case reflect.String: | ||
670 | return path.NewErrorf("string value is required") | ||
671 | |||
672 | case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: | ||
673 | fallthrough | ||
674 | case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: | ||
675 | fallthrough | ||
676 | case reflect.Float32, reflect.Float64: | ||
677 | return path.NewErrorf("number value is required") | ||
678 | |||
679 | case reflect.Slice, reflect.Array: | ||
680 | return path.NewErrorf("list or set value is required") | ||
681 | |||
682 | case reflect.Map: | ||
683 | return path.NewErrorf("map or object value is required") | ||
684 | |||
685 | case reflect.Struct: | ||
686 | switch { | ||
687 | |||
688 | case target.Type().AssignableTo(bigFloatType) || target.Type().AssignableTo(bigIntType): | ||
689 | return path.NewErrorf("number value is required") | ||
690 | |||
691 | case target.Type().AssignableTo(setType): | ||
692 | return path.NewErrorf("set or list value is required") | ||
693 | |||
694 | default: | ||
695 | return path.NewErrorf("object or tuple value is required") | ||
696 | |||
697 | } | ||
698 | |||
699 | default: | ||
700 | // We should avoid getting into this path, since this error | ||
701 | // message is rather useless. | ||
702 | return path.NewErrorf("incorrect type") | ||
703 | |||
704 | } | ||
705 | } | ||
diff --git a/vendor/github.com/zclconf/go-cty/cty/gocty/type_implied.go b/vendor/github.com/zclconf/go-cty/cty/gocty/type_implied.go new file mode 100644 index 0000000..ce4c8f1 --- /dev/null +++ b/vendor/github.com/zclconf/go-cty/cty/gocty/type_implied.go | |||
@@ -0,0 +1,108 @@ | |||
1 | package gocty | ||
2 | |||
3 | import ( | ||
4 | "reflect" | ||
5 | |||
6 | "github.com/zclconf/go-cty/cty" | ||
7 | ) | ||
8 | |||
9 | // ImpliedType takes an arbitrary Go value (as an interface{}) and attempts | ||
10 | // to find a suitable cty.Type instance that could be used for a conversion | ||
11 | // with ToCtyValue. | ||
12 | // | ||
13 | // This allows -- for simple situations at least -- types to be defined just | ||
14 | // once in Go and the cty types derived from the Go types, but in the process | ||
15 | // it makes some assumptions that may be undesirable so applications are | ||
16 | // encouraged to build their cty types directly if exacting control is | ||
17 | // required. | ||
18 | // | ||
19 | // Not all Go types can be represented as cty types, so an error may be | ||
20 | // returned which is usually considered to be a bug in the calling program. | ||
21 | // In particular, ImpliedType will never use capsule types in its returned | ||
22 | // type, because it cannot know the capsule types supported by the calling | ||
23 | // program. | ||
24 | func ImpliedType(gv interface{}) (cty.Type, error) { | ||
25 | rt := reflect.TypeOf(gv) | ||
26 | var path cty.Path | ||
27 | return impliedType(rt, path) | ||
28 | } | ||
29 | |||
30 | func impliedType(rt reflect.Type, path cty.Path) (cty.Type, error) { | ||
31 | switch rt.Kind() { | ||
32 | |||
33 | case reflect.Ptr: | ||
34 | return impliedType(rt.Elem(), path) | ||
35 | |||
36 | // Primitive types | ||
37 | case reflect.Bool: | ||
38 | return cty.Bool, nil | ||
39 | case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: | ||
40 | return cty.Number, nil | ||
41 | case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: | ||
42 | return cty.Number, nil | ||
43 | case reflect.Float32, reflect.Float64: | ||
44 | return cty.Number, nil | ||
45 | case reflect.String: | ||
46 | return cty.String, nil | ||
47 | |||
48 | // Collection types | ||
49 | case reflect.Slice: | ||
50 | path := append(path, cty.IndexStep{Key: cty.UnknownVal(cty.Number)}) | ||
51 | ety, err := impliedType(rt.Elem(), path) | ||
52 | if err != nil { | ||
53 | return cty.NilType, err | ||
54 | } | ||
55 | return cty.List(ety), nil | ||
56 | case reflect.Map: | ||
57 | if !stringType.AssignableTo(rt.Key()) { | ||
58 | return cty.NilType, path.NewErrorf("no cty.Type for %s (must have string keys)", rt) | ||
59 | } | ||
60 | path := append(path, cty.IndexStep{Key: cty.UnknownVal(cty.String)}) | ||
61 | ety, err := impliedType(rt.Elem(), path) | ||
62 | if err != nil { | ||
63 | return cty.NilType, err | ||
64 | } | ||
65 | return cty.Map(ety), nil | ||
66 | |||
67 | // Structural types | ||
68 | case reflect.Struct: | ||
69 | return impliedStructType(rt, path) | ||
70 | |||
71 | default: | ||
72 | return cty.NilType, path.NewErrorf("no cty.Type for %s", rt) | ||
73 | } | ||
74 | } | ||
75 | |||
76 | func impliedStructType(rt reflect.Type, path cty.Path) (cty.Type, error) { | ||
77 | if valueType.AssignableTo(rt) { | ||
78 | // Special case: cty.Value represents cty.DynamicPseudoType, for | ||
79 | // type conformance checking. | ||
80 | return cty.DynamicPseudoType, nil | ||
81 | } | ||
82 | |||
83 | fieldIdxs := structTagIndices(rt) | ||
84 | if len(fieldIdxs) == 0 { | ||
85 | return cty.NilType, path.NewErrorf("no cty.Type for %s (no cty field tags)", rt) | ||
86 | } | ||
87 | |||
88 | atys := make(map[string]cty.Type, len(fieldIdxs)) | ||
89 | |||
90 | { | ||
91 | // Temporary extension of path for attributes | ||
92 | path := append(path, nil) | ||
93 | |||
94 | for k, fi := range fieldIdxs { | ||
95 | path[len(path)-1] = cty.GetAttrStep{Name: k} | ||
96 | |||
97 | ft := rt.Field(fi).Type | ||
98 | aty, err := impliedType(ft, path) | ||
99 | if err != nil { | ||
100 | return cty.NilType, err | ||
101 | } | ||
102 | |||
103 | atys[k] = aty | ||
104 | } | ||
105 | } | ||
106 | |||
107 | return cty.Object(atys), nil | ||
108 | } | ||
diff --git a/vendor/github.com/zclconf/go-cty/cty/helper.go b/vendor/github.com/zclconf/go-cty/cty/helper.go new file mode 100644 index 0000000..1b88e9f --- /dev/null +++ b/vendor/github.com/zclconf/go-cty/cty/helper.go | |||
@@ -0,0 +1,99 @@ | |||
1 | package cty | ||
2 | |||
3 | import ( | ||
4 | "fmt" | ||
5 | ) | ||
6 | |||
7 | // anyUnknown is a helper to easily check if a set of values contains any | ||
8 | // unknowns, for operations that short-circuit to return unknown in that case. | ||
9 | func anyUnknown(values ...Value) bool { | ||
10 | for _, val := range values { | ||
11 | if val.v == unknown { | ||
12 | return true | ||
13 | } | ||
14 | } | ||
15 | return false | ||
16 | } | ||
17 | |||
18 | // typeCheck tests whether all of the given values belong to the given type. | ||
19 | // If the given types are a mixture of the given type and the dynamic | ||
20 | // pseudo-type then a short-circuit dynamic value is returned. If the given | ||
21 | // values are all of the correct type but at least one is unknown then | ||
22 | // a short-circuit unknown value is returned. If any other types appear then | ||
23 | // an error is returned. Otherwise (finally!) the result is nil, nil. | ||
24 | func typeCheck(required Type, ret Type, values ...Value) (shortCircuit *Value, err error) { | ||
25 | hasDynamic := false | ||
26 | hasUnknown := false | ||
27 | |||
28 | for i, val := range values { | ||
29 | if val.ty == DynamicPseudoType { | ||
30 | hasDynamic = true | ||
31 | continue | ||
32 | } | ||
33 | |||
34 | if !val.Type().Equals(required) { | ||
35 | return nil, fmt.Errorf( | ||
36 | "type mismatch: want %s but value %d is %s", | ||
37 | required.FriendlyName(), | ||
38 | i, val.ty.FriendlyName(), | ||
39 | ) | ||
40 | } | ||
41 | |||
42 | if val.v == unknown { | ||
43 | hasUnknown = true | ||
44 | } | ||
45 | } | ||
46 | |||
47 | if hasDynamic { | ||
48 | return &DynamicVal, nil | ||
49 | } | ||
50 | |||
51 | if hasUnknown { | ||
52 | ret := UnknownVal(ret) | ||
53 | return &ret, nil | ||
54 | } | ||
55 | |||
56 | return nil, nil | ||
57 | } | ||
58 | |||
59 | // mustTypeCheck is a wrapper around typeCheck that immediately panics if | ||
60 | // any error is returned. | ||
61 | func mustTypeCheck(required Type, ret Type, values ...Value) *Value { | ||
62 | shortCircuit, err := typeCheck(required, ret, values...) | ||
63 | if err != nil { | ||
64 | panic(err) | ||
65 | } | ||
66 | return shortCircuit | ||
67 | } | ||
68 | |||
69 | // shortCircuitForceType takes the return value from mustTypeCheck and | ||
70 | // replaces it with an unknown of the given type if the original value was | ||
71 | // DynamicVal. | ||
72 | // | ||
73 | // This is useful for operations that are specified to always return a | ||
74 | // particular type, since then a dynamic result can safely be "upgrade" to | ||
75 | // a strongly-typed unknown, which then allows subsequent operations to | ||
76 | // be actually type-checked. | ||
77 | // | ||
78 | // It is safe to use this only if the operation in question is defined as | ||
79 | // returning either a value of the given type or panicking, since we know | ||
80 | // then that subsequent operations won't run if the operation panics. | ||
81 | // | ||
82 | // If the given short-circuit value is *not* DynamicVal then it must be | ||
83 | // of the given type, or this function will panic. | ||
84 | func forceShortCircuitType(shortCircuit *Value, ty Type) *Value { | ||
85 | if shortCircuit == nil { | ||
86 | return nil | ||
87 | } | ||
88 | |||
89 | if shortCircuit.ty == DynamicPseudoType { | ||
90 | ret := UnknownVal(ty) | ||
91 | return &ret | ||
92 | } | ||
93 | |||
94 | if !shortCircuit.ty.Equals(ty) { | ||
95 | panic("forceShortCircuitType got value of wrong type") | ||
96 | } | ||
97 | |||
98 | return shortCircuit | ||
99 | } | ||
diff --git a/vendor/github.com/zclconf/go-cty/cty/json.go b/vendor/github.com/zclconf/go-cty/cty/json.go new file mode 100644 index 0000000..c421a62 --- /dev/null +++ b/vendor/github.com/zclconf/go-cty/cty/json.go | |||
@@ -0,0 +1,176 @@ | |||
1 | package cty | ||
2 | |||
3 | import ( | ||
4 | "bytes" | ||
5 | "encoding/json" | ||
6 | "fmt" | ||
7 | ) | ||
8 | |||
9 | // MarshalJSON is an implementation of json.Marshaler that allows Type | ||
10 | // instances to be serialized as JSON. | ||
11 | // | ||
12 | // All standard types can be serialized, but capsule types cannot since there | ||
13 | // is no way to automatically recover the original pointer and capsule types | ||
14 | // compare by equality. | ||
15 | func (t Type) MarshalJSON() ([]byte, error) { | ||
16 | switch impl := t.typeImpl.(type) { | ||
17 | case primitiveType: | ||
18 | switch impl.Kind { | ||
19 | case primitiveTypeBool: | ||
20 | return []byte{'"', 'b', 'o', 'o', 'l', '"'}, nil | ||
21 | case primitiveTypeNumber: | ||
22 | return []byte{'"', 'n', 'u', 'm', 'b', 'e', 'r', '"'}, nil | ||
23 | case primitiveTypeString: | ||
24 | return []byte{'"', 's', 't', 'r', 'i', 'n', 'g', '"'}, nil | ||
25 | default: | ||
26 | panic("unknown primitive type kind") | ||
27 | } | ||
28 | case typeList, typeMap, typeSet: | ||
29 | buf := &bytes.Buffer{} | ||
30 | etyJSON, err := t.ElementType().MarshalJSON() | ||
31 | if err != nil { | ||
32 | return nil, err | ||
33 | } | ||
34 | buf.WriteRune('[') | ||
35 | switch impl.(type) { | ||
36 | case typeList: | ||
37 | buf.WriteString(`"list"`) | ||
38 | case typeMap: | ||
39 | buf.WriteString(`"map"`) | ||
40 | case typeSet: | ||
41 | buf.WriteString(`"set"`) | ||
42 | } | ||
43 | buf.WriteRune(',') | ||
44 | buf.Write(etyJSON) | ||
45 | buf.WriteRune(']') | ||
46 | return buf.Bytes(), nil | ||
47 | case typeObject: | ||
48 | buf := &bytes.Buffer{} | ||
49 | atysJSON, err := json.Marshal(t.AttributeTypes()) | ||
50 | if err != nil { | ||
51 | return nil, err | ||
52 | } | ||
53 | buf.WriteString(`["object",`) | ||
54 | buf.Write(atysJSON) | ||
55 | buf.WriteRune(']') | ||
56 | return buf.Bytes(), nil | ||
57 | case typeTuple: | ||
58 | buf := &bytes.Buffer{} | ||
59 | etysJSON, err := json.Marshal(t.TupleElementTypes()) | ||
60 | if err != nil { | ||
61 | return nil, err | ||
62 | } | ||
63 | buf.WriteString(`["tuple",`) | ||
64 | buf.Write(etysJSON) | ||
65 | buf.WriteRune(']') | ||
66 | return buf.Bytes(), nil | ||
67 | case pseudoTypeDynamic: | ||
68 | return []byte{'"', 'd', 'y', 'n', 'a', 'm', 'i', 'c', '"'}, nil | ||
69 | case *capsuleType: | ||
70 | return nil, fmt.Errorf("type not allowed: %s", t.FriendlyName()) | ||
71 | default: | ||
72 | // should never happen | ||
73 | panic("unknown type implementation") | ||
74 | } | ||
75 | } | ||
76 | |||
77 | // UnmarshalJSON is the opposite of MarshalJSON. See the documentation of | ||
78 | // MarshalJSON for information on the limitations of JSON serialization of | ||
79 | // types. | ||
80 | func (t *Type) UnmarshalJSON(buf []byte) error { | ||
81 | r := bytes.NewReader(buf) | ||
82 | dec := json.NewDecoder(r) | ||
83 | |||
84 | tok, err := dec.Token() | ||
85 | if err != nil { | ||
86 | return err | ||
87 | } | ||
88 | |||
89 | switch v := tok.(type) { | ||
90 | case string: | ||
91 | switch v { | ||
92 | case "bool": | ||
93 | *t = Bool | ||
94 | case "number": | ||
95 | *t = Number | ||
96 | case "string": | ||
97 | *t = String | ||
98 | case "dynamic": | ||
99 | *t = DynamicPseudoType | ||
100 | default: | ||
101 | return fmt.Errorf("invalid primitive type name %q", v) | ||
102 | } | ||
103 | |||
104 | if dec.More() { | ||
105 | return fmt.Errorf("extraneous data after type description") | ||
106 | } | ||
107 | return nil | ||
108 | case json.Delim: | ||
109 | if rune(v) != '[' { | ||
110 | return fmt.Errorf("invalid complex type description") | ||
111 | } | ||
112 | |||
113 | tok, err = dec.Token() | ||
114 | if err != nil { | ||
115 | return err | ||
116 | } | ||
117 | |||
118 | kind, ok := tok.(string) | ||
119 | if !ok { | ||
120 | return fmt.Errorf("invalid complex type kind name") | ||
121 | } | ||
122 | |||
123 | switch kind { | ||
124 | case "list": | ||
125 | var ety Type | ||
126 | err = dec.Decode(&ety) | ||
127 | if err != nil { | ||
128 | return err | ||
129 | } | ||
130 | *t = List(ety) | ||
131 | case "map": | ||
132 | var ety Type | ||
133 | err = dec.Decode(&ety) | ||
134 | if err != nil { | ||
135 | return err | ||
136 | } | ||
137 | *t = Map(ety) | ||
138 | case "set": | ||
139 | var ety Type | ||
140 | err = dec.Decode(&ety) | ||
141 | if err != nil { | ||
142 | return err | ||
143 | } | ||
144 | *t = Set(ety) | ||
145 | case "object": | ||
146 | var atys map[string]Type | ||
147 | err = dec.Decode(&atys) | ||
148 | if err != nil { | ||
149 | return err | ||
150 | } | ||
151 | *t = Object(atys) | ||
152 | case "tuple": | ||
153 | var etys []Type | ||
154 | err = dec.Decode(&etys) | ||
155 | if err != nil { | ||
156 | return err | ||
157 | } | ||
158 | *t = Tuple(etys) | ||
159 | default: | ||
160 | return fmt.Errorf("invalid complex type kind name") | ||
161 | } | ||
162 | |||
163 | tok, err = dec.Token() | ||
164 | if err != nil { | ||
165 | return err | ||
166 | } | ||
167 | if delim, ok := tok.(json.Delim); !ok || rune(delim) != ']' || dec.More() { | ||
168 | return fmt.Errorf("unexpected extra data in type description") | ||
169 | } | ||
170 | |||
171 | return nil | ||
172 | |||
173 | default: | ||
174 | return fmt.Errorf("invalid type description") | ||
175 | } | ||
176 | } | ||
diff --git a/vendor/github.com/zclconf/go-cty/cty/json/doc.go b/vendor/github.com/zclconf/go-cty/cty/json/doc.go new file mode 100644 index 0000000..8916513 --- /dev/null +++ b/vendor/github.com/zclconf/go-cty/cty/json/doc.go | |||
@@ -0,0 +1,11 @@ | |||
1 | // Package json provides functions for serializing cty types and values in | ||
2 | // JSON format, and for decoding them again. | ||
3 | // | ||
4 | // Since the cty type system is a superset of the JSON type system, | ||
5 | // round-tripping through JSON is lossy unless type information is provided | ||
6 | // both at encoding time and decoding time. Callers of this package are | ||
7 | // therefore suggested to define their expected structure as a cty.Type | ||
8 | // and pass it in consistently both when encoding and when decoding, though | ||
9 | // default (type-lossy) behavior is provided for situations where the precise | ||
10 | // representation of the data is not significant. | ||
11 | package json | ||
diff --git a/vendor/github.com/zclconf/go-cty/cty/json/marshal.go b/vendor/github.com/zclconf/go-cty/cty/json/marshal.go new file mode 100644 index 0000000..f7bea1a --- /dev/null +++ b/vendor/github.com/zclconf/go-cty/cty/json/marshal.go | |||
@@ -0,0 +1,189 @@ | |||
1 | package json | ||
2 | |||
3 | import ( | ||
4 | "bytes" | ||
5 | "encoding/json" | ||
6 | "sort" | ||
7 | |||
8 | "github.com/zclconf/go-cty/cty" | ||
9 | ) | ||
10 | |||
11 | func marshal(val cty.Value, t cty.Type, path cty.Path, b *bytes.Buffer) error { | ||
12 | // If we're going to decode as DynamicPseudoType then we need to save | ||
13 | // dynamic type information to recover the real type. | ||
14 | if t == cty.DynamicPseudoType && val.Type() != cty.DynamicPseudoType { | ||
15 | return marshalDynamic(val, path, b) | ||
16 | } | ||
17 | |||
18 | if val.IsNull() { | ||
19 | b.WriteString("null") | ||
20 | return nil | ||
21 | } | ||
22 | |||
23 | if !val.IsKnown() { | ||
24 | return path.NewErrorf("value is not known") | ||
25 | } | ||
26 | |||
27 | // The caller should've guaranteed that the given val is conformant with | ||
28 | // the given type t, so we'll proceed under that assumption here. | ||
29 | |||
30 | switch { | ||
31 | case t.IsPrimitiveType(): | ||
32 | switch t { | ||
33 | case cty.String: | ||
34 | json, err := json.Marshal(val.AsString()) | ||
35 | if err != nil { | ||
36 | return path.NewErrorf("failed to serialize value: %s", err) | ||
37 | } | ||
38 | b.Write(json) | ||
39 | return nil | ||
40 | case cty.Number: | ||
41 | if val.RawEquals(cty.PositiveInfinity) || val.RawEquals(cty.NegativeInfinity) { | ||
42 | return path.NewErrorf("cannot serialize infinity as JSON") | ||
43 | } | ||
44 | b.WriteString(val.AsBigFloat().Text('f', -1)) | ||
45 | return nil | ||
46 | case cty.Bool: | ||
47 | if val.True() { | ||
48 | b.WriteString("true") | ||
49 | } else { | ||
50 | b.WriteString("false") | ||
51 | } | ||
52 | return nil | ||
53 | default: | ||
54 | panic("unsupported primitive type") | ||
55 | } | ||
56 | case t.IsListType(), t.IsSetType(): | ||
57 | b.WriteRune('[') | ||
58 | first := true | ||
59 | ety := t.ElementType() | ||
60 | it := val.ElementIterator() | ||
61 | path := append(path, nil) // local override of 'path' with extra element | ||
62 | for it.Next() { | ||
63 | if !first { | ||
64 | b.WriteRune(',') | ||
65 | } | ||
66 | ek, ev := it.Element() | ||
67 | path[len(path)-1] = cty.IndexStep{ | ||
68 | Key: ek, | ||
69 | } | ||
70 | err := marshal(ev, ety, path, b) | ||
71 | if err != nil { | ||
72 | return err | ||
73 | } | ||
74 | first = false | ||
75 | } | ||
76 | b.WriteRune(']') | ||
77 | return nil | ||
78 | case t.IsMapType(): | ||
79 | b.WriteRune('{') | ||
80 | first := true | ||
81 | ety := t.ElementType() | ||
82 | it := val.ElementIterator() | ||
83 | path := append(path, nil) // local override of 'path' with extra element | ||
84 | for it.Next() { | ||
85 | if !first { | ||
86 | b.WriteRune(',') | ||
87 | } | ||
88 | ek, ev := it.Element() | ||
89 | path[len(path)-1] = cty.IndexStep{ | ||
90 | Key: ek, | ||
91 | } | ||
92 | var err error | ||
93 | err = marshal(ek, ek.Type(), path, b) | ||
94 | if err != nil { | ||
95 | return err | ||
96 | } | ||
97 | b.WriteRune(':') | ||
98 | err = marshal(ev, ety, path, b) | ||
99 | if err != nil { | ||
100 | return err | ||
101 | } | ||
102 | first = false | ||
103 | } | ||
104 | b.WriteRune('}') | ||
105 | return nil | ||
106 | case t.IsTupleType(): | ||
107 | b.WriteRune('[') | ||
108 | etys := t.TupleElementTypes() | ||
109 | it := val.ElementIterator() | ||
110 | path := append(path, nil) // local override of 'path' with extra element | ||
111 | i := 0 | ||
112 | for it.Next() { | ||
113 | if i > 0 { | ||
114 | b.WriteRune(',') | ||
115 | } | ||
116 | ety := etys[i] | ||
117 | ek, ev := it.Element() | ||
118 | path[len(path)-1] = cty.IndexStep{ | ||
119 | Key: ek, | ||
120 | } | ||
121 | err := marshal(ev, ety, path, b) | ||
122 | if err != nil { | ||
123 | return err | ||
124 | } | ||
125 | i++ | ||
126 | } | ||
127 | b.WriteRune(']') | ||
128 | return nil | ||
129 | case t.IsObjectType(): | ||
130 | b.WriteRune('{') | ||
131 | atys := t.AttributeTypes() | ||
132 | path := append(path, nil) // local override of 'path' with extra element | ||
133 | |||
134 | names := make([]string, 0, len(atys)) | ||
135 | for k := range atys { | ||
136 | names = append(names, k) | ||
137 | } | ||
138 | sort.Strings(names) | ||
139 | |||
140 | for i, k := range names { | ||
141 | aty := atys[k] | ||
142 | if i > 0 { | ||
143 | b.WriteRune(',') | ||
144 | } | ||
145 | av := val.GetAttr(k) | ||
146 | path[len(path)-1] = cty.GetAttrStep{ | ||
147 | Name: k, | ||
148 | } | ||
149 | var err error | ||
150 | err = marshal(cty.StringVal(k), cty.String, path, b) | ||
151 | if err != nil { | ||
152 | return err | ||
153 | } | ||
154 | b.WriteRune(':') | ||
155 | err = marshal(av, aty, path, b) | ||
156 | if err != nil { | ||
157 | return err | ||
158 | } | ||
159 | } | ||
160 | b.WriteRune('}') | ||
161 | return nil | ||
162 | case t.IsCapsuleType(): | ||
163 | rawVal := val.EncapsulatedValue() | ||
164 | jsonVal, err := json.Marshal(rawVal) | ||
165 | if err != nil { | ||
166 | return path.NewError(err) | ||
167 | } | ||
168 | b.Write(jsonVal) | ||
169 | return nil | ||
170 | default: | ||
171 | // should never happen | ||
172 | return path.NewErrorf("cannot JSON-serialize %s", t.FriendlyName()) | ||
173 | } | ||
174 | } | ||
175 | |||
176 | // marshalDynamic adds an extra wrapping object containing dynamic type | ||
177 | // information for the given value. | ||
178 | func marshalDynamic(val cty.Value, path cty.Path, b *bytes.Buffer) error { | ||
179 | typeJSON, err := MarshalType(val.Type()) | ||
180 | if err != nil { | ||
181 | return path.NewErrorf("failed to serialize type: %s", err) | ||
182 | } | ||
183 | b.WriteString(`{"value":`) | ||
184 | marshal(val, val.Type(), path, b) | ||
185 | b.WriteString(`,"type":`) | ||
186 | b.Write(typeJSON) | ||
187 | b.WriteRune('}') | ||
188 | return nil | ||
189 | } | ||
diff --git a/vendor/github.com/zclconf/go-cty/cty/json/simple.go b/vendor/github.com/zclconf/go-cty/cty/json/simple.go new file mode 100644 index 0000000..507c9cc --- /dev/null +++ b/vendor/github.com/zclconf/go-cty/cty/json/simple.go | |||
@@ -0,0 +1,41 @@ | |||
1 | package json | ||
2 | |||
3 | import ( | ||
4 | "github.com/zclconf/go-cty/cty" | ||
5 | ) | ||
6 | |||
7 | // SimpleJSONValue is a wrapper around cty.Value that adds implementations of | ||
8 | // json.Marshaler and json.Unmarshaler for simple-but-type-lossy automatic | ||
9 | // encoding and decoding of values. | ||
10 | // | ||
11 | // The couplet Marshal and Unmarshal both take extra type information to | ||
12 | // inform the encoding and decoding process so that all of the cty types | ||
13 | // can be represented even though JSON's type system is a subset. | ||
14 | // | ||
15 | // SimpleJSONValue instead takes the approach of discarding the value's type | ||
16 | // information and then deriving a new type from the stored structure when | ||
17 | // decoding. This results in the same data being returned but not necessarily | ||
18 | // with exactly the same type. | ||
19 | // | ||
20 | // For information on how types are inferred when decoding, see the | ||
21 | // documentation of the function ImpliedType. | ||
22 | type SimpleJSONValue struct { | ||
23 | cty.Value | ||
24 | } | ||
25 | |||
26 | // MarshalJSON is an implementation of json.Marshaler. See the documentation | ||
27 | // of SimpleJSONValue for more information. | ||
28 | func (v SimpleJSONValue) MarshalJSON() ([]byte, error) { | ||
29 | return Marshal(v.Value, v.Type()) | ||
30 | } | ||
31 | |||
32 | // UnmarshalJSON is an implementation of json.Unmarshaler. See the | ||
33 | // documentation of SimpleJSONValue for more information. | ||
34 | func (v *SimpleJSONValue) UnmarshalJSON(buf []byte) error { | ||
35 | t, err := ImpliedType(buf) | ||
36 | if err != nil { | ||
37 | return err | ||
38 | } | ||
39 | v.Value, err = Unmarshal(buf, t) | ||
40 | return err | ||
41 | } | ||
diff --git a/vendor/github.com/zclconf/go-cty/cty/json/type.go b/vendor/github.com/zclconf/go-cty/cty/json/type.go new file mode 100644 index 0000000..9131c6c --- /dev/null +++ b/vendor/github.com/zclconf/go-cty/cty/json/type.go | |||
@@ -0,0 +1,23 @@ | |||
1 | package json | ||
2 | |||
3 | import ( | ||
4 | "github.com/zclconf/go-cty/cty" | ||
5 | ) | ||
6 | |||
7 | // MarshalType returns a JSON serialization of the given type. | ||
8 | // | ||
9 | // This is just a thin wrapper around t.MarshalJSON, for symmetry with | ||
10 | // UnmarshalType. | ||
11 | func MarshalType(t cty.Type) ([]byte, error) { | ||
12 | return t.MarshalJSON() | ||
13 | } | ||
14 | |||
15 | // UnmarshalType decodes a JSON serialization of the given type as produced | ||
16 | // by either Type.MarshalJSON or MarshalType. | ||
17 | // | ||
18 | // This is a convenience wrapper around Type.UnmarshalJSON. | ||
19 | func UnmarshalType(buf []byte) (cty.Type, error) { | ||
20 | var t cty.Type | ||
21 | err := t.UnmarshalJSON(buf) | ||
22 | return t, err | ||
23 | } | ||
diff --git a/vendor/github.com/zclconf/go-cty/cty/json/type_implied.go b/vendor/github.com/zclconf/go-cty/cty/json/type_implied.go new file mode 100644 index 0000000..1a97306 --- /dev/null +++ b/vendor/github.com/zclconf/go-cty/cty/json/type_implied.go | |||
@@ -0,0 +1,171 @@ | |||
1 | package json | ||
2 | |||
3 | import ( | ||
4 | "bytes" | ||
5 | "encoding/json" | ||
6 | "fmt" | ||
7 | |||
8 | "github.com/zclconf/go-cty/cty" | ||
9 | ) | ||
10 | |||
11 | // ImpliedType returns the cty Type implied by the structure of the given | ||
12 | // JSON-compliant buffer. This function implements the default type mapping | ||
13 | // behavior used when decoding arbitrary JSON without explicit cty Type | ||
14 | // information. | ||
15 | // | ||
16 | // The rules are as follows: | ||
17 | // | ||
18 | // JSON strings, numbers and bools map to their equivalent primitive type in | ||
19 | // cty. | ||
20 | // | ||
21 | // JSON objects map to cty object types, with the attributes defined by the | ||
22 | // object keys and the types of their values. | ||
23 | // | ||
24 | // JSON arrays map to cty tuple types, with the elements defined by the | ||
25 | // types of the array members. | ||
26 | // | ||
27 | // Any nulls are typed as DynamicPseudoType, so callers of this function | ||
28 | // must be prepared to deal with this. Callers that do not wish to deal with | ||
29 | // dynamic typing should not use this function and should instead describe | ||
30 | // their required types explicitly with a cty.Type instance when decoding. | ||
31 | // | ||
32 | // Any JSON syntax errors will be returned as an error, and the type will | ||
33 | // be the invalid value cty.NilType. | ||
34 | func ImpliedType(buf []byte) (cty.Type, error) { | ||
35 | r := bytes.NewReader(buf) | ||
36 | dec := json.NewDecoder(r) | ||
37 | dec.UseNumber() | ||
38 | |||
39 | ty, err := impliedType(dec) | ||
40 | if err != nil { | ||
41 | return cty.NilType, err | ||
42 | } | ||
43 | |||
44 | if dec.More() { | ||
45 | return cty.NilType, fmt.Errorf("extraneous data after JSON object") | ||
46 | } | ||
47 | |||
48 | return ty, nil | ||
49 | } | ||
50 | |||
51 | func impliedType(dec *json.Decoder) (cty.Type, error) { | ||
52 | tok, err := dec.Token() | ||
53 | if err != nil { | ||
54 | return cty.NilType, err | ||
55 | } | ||
56 | |||
57 | return impliedTypeForTok(tok, dec) | ||
58 | } | ||
59 | |||
60 | func impliedTypeForTok(tok json.Token, dec *json.Decoder) (cty.Type, error) { | ||
61 | if tok == nil { | ||
62 | return cty.DynamicPseudoType, nil | ||
63 | } | ||
64 | |||
65 | switch ttok := tok.(type) { | ||
66 | case bool: | ||
67 | return cty.Bool, nil | ||
68 | |||
69 | case json.Number: | ||
70 | return cty.Number, nil | ||
71 | |||
72 | case string: | ||
73 | return cty.String, nil | ||
74 | |||
75 | case json.Delim: | ||
76 | |||
77 | switch rune(ttok) { | ||
78 | case '{': | ||
79 | return impliedObjectType(dec) | ||
80 | case '[': | ||
81 | return impliedTupleType(dec) | ||
82 | default: | ||
83 | return cty.NilType, fmt.Errorf("unexpected token %q", ttok) | ||
84 | } | ||
85 | |||
86 | default: | ||
87 | return cty.NilType, fmt.Errorf("unsupported JSON token %#v", tok) | ||
88 | } | ||
89 | } | ||
90 | |||
91 | func impliedObjectType(dec *json.Decoder) (cty.Type, error) { | ||
92 | // By the time we get in here, we've already consumed the { delimiter | ||
93 | // and so our next token should be the first object key. | ||
94 | |||
95 | var atys map[string]cty.Type | ||
96 | |||
97 | for { | ||
98 | // Read the object key first | ||
99 | tok, err := dec.Token() | ||
100 | if err != nil { | ||
101 | return cty.NilType, err | ||
102 | } | ||
103 | |||
104 | if ttok, ok := tok.(json.Delim); ok { | ||
105 | if rune(ttok) != '}' { | ||
106 | return cty.NilType, fmt.Errorf("unexpected delimiter %q", ttok) | ||
107 | } | ||
108 | break | ||
109 | } | ||
110 | |||
111 | key, ok := tok.(string) | ||
112 | if !ok { | ||
113 | return cty.NilType, fmt.Errorf("expected string but found %T", tok) | ||
114 | } | ||
115 | |||
116 | // Now read the value | ||
117 | tok, err = dec.Token() | ||
118 | if err != nil { | ||
119 | return cty.NilType, err | ||
120 | } | ||
121 | |||
122 | aty, err := impliedTypeForTok(tok, dec) | ||
123 | if err != nil { | ||
124 | return cty.NilType, err | ||
125 | } | ||
126 | |||
127 | if atys == nil { | ||
128 | atys = make(map[string]cty.Type) | ||
129 | } | ||
130 | atys[key] = aty | ||
131 | } | ||
132 | |||
133 | if len(atys) == 0 { | ||
134 | return cty.EmptyObject, nil | ||
135 | } | ||
136 | |||
137 | return cty.Object(atys), nil | ||
138 | } | ||
139 | |||
140 | func impliedTupleType(dec *json.Decoder) (cty.Type, error) { | ||
141 | // By the time we get in here, we've already consumed the { delimiter | ||
142 | // and so our next token should be the first value. | ||
143 | |||
144 | var etys []cty.Type | ||
145 | |||
146 | for { | ||
147 | tok, err := dec.Token() | ||
148 | if err != nil { | ||
149 | return cty.NilType, err | ||
150 | } | ||
151 | |||
152 | if ttok, ok := tok.(json.Delim); ok { | ||
153 | if rune(ttok) != ']' { | ||
154 | return cty.NilType, fmt.Errorf("unexpected delimiter %q", ttok) | ||
155 | } | ||
156 | break | ||
157 | } | ||
158 | |||
159 | ety, err := impliedTypeForTok(tok, dec) | ||
160 | if err != nil { | ||
161 | return cty.NilType, err | ||
162 | } | ||
163 | etys = append(etys, ety) | ||
164 | } | ||
165 | |||
166 | if len(etys) == 0 { | ||
167 | return cty.EmptyTuple, nil | ||
168 | } | ||
169 | |||
170 | return cty.Tuple(etys), nil | ||
171 | } | ||
diff --git a/vendor/github.com/zclconf/go-cty/cty/json/unmarshal.go b/vendor/github.com/zclconf/go-cty/cty/json/unmarshal.go new file mode 100644 index 0000000..155f0b8 --- /dev/null +++ b/vendor/github.com/zclconf/go-cty/cty/json/unmarshal.go | |||
@@ -0,0 +1,459 @@ | |||
1 | package json | ||
2 | |||
3 | import ( | ||
4 | "bytes" | ||
5 | "encoding/json" | ||
6 | "fmt" | ||
7 | "reflect" | ||
8 | |||
9 | "github.com/zclconf/go-cty/cty" | ||
10 | "github.com/zclconf/go-cty/cty/convert" | ||
11 | ) | ||
12 | |||
13 | func unmarshal(buf []byte, t cty.Type, path cty.Path) (cty.Value, error) { | ||
14 | dec := bufDecoder(buf) | ||
15 | |||
16 | tok, err := dec.Token() | ||
17 | if err != nil { | ||
18 | return cty.NilVal, path.NewError(err) | ||
19 | } | ||
20 | |||
21 | if tok == nil { | ||
22 | return cty.NullVal(t), nil | ||
23 | } | ||
24 | |||
25 | if t == cty.DynamicPseudoType { | ||
26 | return unmarshalDynamic(buf, path) | ||
27 | } | ||
28 | |||
29 | switch { | ||
30 | case t.IsPrimitiveType(): | ||
31 | val, err := unmarshalPrimitive(tok, t, path) | ||
32 | if err != nil { | ||
33 | return cty.NilVal, err | ||
34 | } | ||
35 | return val, nil | ||
36 | case t.IsListType(): | ||
37 | return unmarshalList(buf, t.ElementType(), path) | ||
38 | case t.IsSetType(): | ||
39 | return unmarshalSet(buf, t.ElementType(), path) | ||
40 | case t.IsMapType(): | ||
41 | return unmarshalMap(buf, t.ElementType(), path) | ||
42 | case t.IsTupleType(): | ||
43 | return unmarshalTuple(buf, t.TupleElementTypes(), path) | ||
44 | case t.IsObjectType(): | ||
45 | return unmarshalObject(buf, t.AttributeTypes(), path) | ||
46 | case t.IsCapsuleType(): | ||
47 | return unmarshalCapsule(buf, t, path) | ||
48 | default: | ||
49 | return cty.NilVal, path.NewErrorf("unsupported type %s", t.FriendlyName()) | ||
50 | } | ||
51 | } | ||
52 | |||
53 | func unmarshalPrimitive(tok json.Token, t cty.Type, path cty.Path) (cty.Value, error) { | ||
54 | |||
55 | switch t { | ||
56 | case cty.Bool: | ||
57 | switch v := tok.(type) { | ||
58 | case bool: | ||
59 | return cty.BoolVal(v), nil | ||
60 | case string: | ||
61 | val, err := convert.Convert(cty.StringVal(v), t) | ||
62 | if err != nil { | ||
63 | return cty.NilVal, path.NewError(err) | ||
64 | } | ||
65 | return val, nil | ||
66 | default: | ||
67 | return cty.NilVal, path.NewErrorf("bool is required") | ||
68 | } | ||
69 | case cty.Number: | ||
70 | if v, ok := tok.(json.Number); ok { | ||
71 | tok = string(v) | ||
72 | } | ||
73 | switch v := tok.(type) { | ||
74 | case string: | ||
75 | val, err := convert.Convert(cty.StringVal(v), t) | ||
76 | if err != nil { | ||
77 | return cty.NilVal, path.NewError(err) | ||
78 | } | ||
79 | return val, nil | ||
80 | default: | ||
81 | return cty.NilVal, path.NewErrorf("number is required") | ||
82 | } | ||
83 | case cty.String: | ||
84 | switch v := tok.(type) { | ||
85 | case string: | ||
86 | return cty.StringVal(v), nil | ||
87 | case json.Number: | ||
88 | return cty.StringVal(string(v)), nil | ||
89 | case bool: | ||
90 | val, err := convert.Convert(cty.BoolVal(v), t) | ||
91 | if err != nil { | ||
92 | return cty.NilVal, path.NewError(err) | ||
93 | } | ||
94 | return val, nil | ||
95 | default: | ||
96 | return cty.NilVal, path.NewErrorf("string is required") | ||
97 | } | ||
98 | default: | ||
99 | // should never happen | ||
100 | panic("unsupported primitive type") | ||
101 | } | ||
102 | } | ||
103 | |||
104 | func unmarshalList(buf []byte, ety cty.Type, path cty.Path) (cty.Value, error) { | ||
105 | dec := bufDecoder(buf) | ||
106 | if err := requireDelim(dec, '['); err != nil { | ||
107 | return cty.NilVal, path.NewError(err) | ||
108 | } | ||
109 | |||
110 | var vals []cty.Value | ||
111 | |||
112 | { | ||
113 | path := append(path, nil) | ||
114 | var idx int64 | ||
115 | |||
116 | for dec.More() { | ||
117 | path[len(path)-1] = cty.IndexStep{ | ||
118 | Key: cty.NumberIntVal(idx), | ||
119 | } | ||
120 | idx++ | ||
121 | |||
122 | rawVal, err := readRawValue(dec) | ||
123 | if err != nil { | ||
124 | return cty.NilVal, path.NewErrorf("failed to read list value: %s", err) | ||
125 | } | ||
126 | |||
127 | el, err := unmarshal(rawVal, ety, path) | ||
128 | if err != nil { | ||
129 | return cty.NilVal, err | ||
130 | } | ||
131 | |||
132 | vals = append(vals, el) | ||
133 | } | ||
134 | } | ||
135 | |||
136 | if err := requireDelim(dec, ']'); err != nil { | ||
137 | return cty.NilVal, path.NewError(err) | ||
138 | } | ||
139 | |||
140 | if len(vals) == 0 { | ||
141 | return cty.ListValEmpty(ety), nil | ||
142 | } | ||
143 | |||
144 | return cty.ListVal(vals), nil | ||
145 | } | ||
146 | |||
147 | func unmarshalSet(buf []byte, ety cty.Type, path cty.Path) (cty.Value, error) { | ||
148 | dec := bufDecoder(buf) | ||
149 | if err := requireDelim(dec, '['); err != nil { | ||
150 | return cty.NilVal, path.NewError(err) | ||
151 | } | ||
152 | |||
153 | var vals []cty.Value | ||
154 | |||
155 | { | ||
156 | path := append(path, nil) | ||
157 | |||
158 | for dec.More() { | ||
159 | path[len(path)-1] = cty.IndexStep{ | ||
160 | Key: cty.UnknownVal(ety), | ||
161 | } | ||
162 | |||
163 | rawVal, err := readRawValue(dec) | ||
164 | if err != nil { | ||
165 | return cty.NilVal, path.NewErrorf("failed to read set value: %s", err) | ||
166 | } | ||
167 | |||
168 | el, err := unmarshal(rawVal, ety, path) | ||
169 | if err != nil { | ||
170 | return cty.NilVal, err | ||
171 | } | ||
172 | |||
173 | vals = append(vals, el) | ||
174 | } | ||
175 | } | ||
176 | |||
177 | if err := requireDelim(dec, ']'); err != nil { | ||
178 | return cty.NilVal, path.NewError(err) | ||
179 | } | ||
180 | |||
181 | if len(vals) == 0 { | ||
182 | return cty.SetValEmpty(ety), nil | ||
183 | } | ||
184 | |||
185 | return cty.SetVal(vals), nil | ||
186 | } | ||
187 | |||
188 | func unmarshalMap(buf []byte, ety cty.Type, path cty.Path) (cty.Value, error) { | ||
189 | dec := bufDecoder(buf) | ||
190 | if err := requireDelim(dec, '{'); err != nil { | ||
191 | return cty.NilVal, path.NewError(err) | ||
192 | } | ||
193 | |||
194 | vals := make(map[string]cty.Value) | ||
195 | |||
196 | { | ||
197 | path := append(path, nil) | ||
198 | |||
199 | for dec.More() { | ||
200 | path[len(path)-1] = cty.IndexStep{ | ||
201 | Key: cty.UnknownVal(cty.String), | ||
202 | } | ||
203 | |||
204 | var err error | ||
205 | |||
206 | k, err := requireObjectKey(dec) | ||
207 | if err != nil { | ||
208 | return cty.NilVal, path.NewErrorf("failed to read map key: %s", err) | ||
209 | } | ||
210 | |||
211 | path[len(path)-1] = cty.IndexStep{ | ||
212 | Key: cty.StringVal(k), | ||
213 | } | ||
214 | |||
215 | rawVal, err := readRawValue(dec) | ||
216 | if err != nil { | ||
217 | return cty.NilVal, path.NewErrorf("failed to read map value: %s", err) | ||
218 | } | ||
219 | |||
220 | el, err := unmarshal(rawVal, ety, path) | ||
221 | if err != nil { | ||
222 | return cty.NilVal, err | ||
223 | } | ||
224 | |||
225 | vals[k] = el | ||
226 | } | ||
227 | } | ||
228 | |||
229 | if err := requireDelim(dec, '}'); err != nil { | ||
230 | return cty.NilVal, path.NewError(err) | ||
231 | } | ||
232 | |||
233 | if len(vals) == 0 { | ||
234 | return cty.MapValEmpty(ety), nil | ||
235 | } | ||
236 | |||
237 | return cty.MapVal(vals), nil | ||
238 | } | ||
239 | |||
240 | func unmarshalTuple(buf []byte, etys []cty.Type, path cty.Path) (cty.Value, error) { | ||
241 | dec := bufDecoder(buf) | ||
242 | if err := requireDelim(dec, '['); err != nil { | ||
243 | return cty.NilVal, path.NewError(err) | ||
244 | } | ||
245 | |||
246 | var vals []cty.Value | ||
247 | |||
248 | { | ||
249 | path := append(path, nil) | ||
250 | var idx int | ||
251 | |||
252 | for dec.More() { | ||
253 | if idx >= len(etys) { | ||
254 | return cty.NilVal, path[:len(path)-1].NewErrorf("too many tuple elements (need %d)", len(etys)) | ||
255 | } | ||
256 | |||
257 | path[len(path)-1] = cty.IndexStep{ | ||
258 | Key: cty.NumberIntVal(int64(idx)), | ||
259 | } | ||
260 | ety := etys[idx] | ||
261 | idx++ | ||
262 | |||
263 | rawVal, err := readRawValue(dec) | ||
264 | if err != nil { | ||
265 | return cty.NilVal, path.NewErrorf("failed to read tuple value: %s", err) | ||
266 | } | ||
267 | |||
268 | el, err := unmarshal(rawVal, ety, path) | ||
269 | if err != nil { | ||
270 | return cty.NilVal, err | ||
271 | } | ||
272 | |||
273 | vals = append(vals, el) | ||
274 | } | ||
275 | } | ||
276 | |||
277 | if err := requireDelim(dec, ']'); err != nil { | ||
278 | return cty.NilVal, path.NewError(err) | ||
279 | } | ||
280 | |||
281 | if len(vals) != len(etys) { | ||
282 | return cty.NilVal, path[:len(path)-1].NewErrorf("not enough tuple elements (need %d)", len(etys)) | ||
283 | } | ||
284 | |||
285 | if len(vals) == 0 { | ||
286 | return cty.EmptyTupleVal, nil | ||
287 | } | ||
288 | |||
289 | return cty.TupleVal(vals), nil | ||
290 | } | ||
291 | |||
292 | func unmarshalObject(buf []byte, atys map[string]cty.Type, path cty.Path) (cty.Value, error) { | ||
293 | dec := bufDecoder(buf) | ||
294 | if err := requireDelim(dec, '{'); err != nil { | ||
295 | return cty.NilVal, path.NewError(err) | ||
296 | } | ||
297 | |||
298 | vals := make(map[string]cty.Value) | ||
299 | |||
300 | { | ||
301 | objPath := path // some errors report from the object's perspective | ||
302 | path := append(path, nil) // path to a specific attribute | ||
303 | |||
304 | for dec.More() { | ||
305 | |||
306 | var err error | ||
307 | |||
308 | k, err := requireObjectKey(dec) | ||
309 | if err != nil { | ||
310 | return cty.NilVal, path.NewErrorf("failed to read object key: %s", err) | ||
311 | } | ||
312 | |||
313 | aty, ok := atys[k] | ||
314 | if !ok { | ||
315 | return cty.NilVal, objPath.NewErrorf("unsupported attribute %q", k) | ||
316 | } | ||
317 | |||
318 | path[len(path)-1] = cty.GetAttrStep{ | ||
319 | Name: k, | ||
320 | } | ||
321 | |||
322 | rawVal, err := readRawValue(dec) | ||
323 | if err != nil { | ||
324 | return cty.NilVal, path.NewErrorf("failed to read object value: %s", err) | ||
325 | } | ||
326 | |||
327 | el, err := unmarshal(rawVal, aty, path) | ||
328 | if err != nil { | ||
329 | return cty.NilVal, err | ||
330 | } | ||
331 | |||
332 | vals[k] = el | ||
333 | } | ||
334 | } | ||
335 | |||
336 | if err := requireDelim(dec, '}'); err != nil { | ||
337 | return cty.NilVal, path.NewError(err) | ||
338 | } | ||
339 | |||
340 | // Make sure we have a value for every attribute | ||
341 | for k, aty := range atys { | ||
342 | if _, exists := vals[k]; !exists { | ||
343 | vals[k] = cty.NullVal(aty) | ||
344 | } | ||
345 | } | ||
346 | |||
347 | if len(vals) == 0 { | ||
348 | return cty.EmptyObjectVal, nil | ||
349 | } | ||
350 | |||
351 | return cty.ObjectVal(vals), nil | ||
352 | } | ||
353 | |||
354 | func unmarshalCapsule(buf []byte, t cty.Type, path cty.Path) (cty.Value, error) { | ||
355 | rawType := t.EncapsulatedType() | ||
356 | ptrPtr := reflect.New(reflect.PtrTo(rawType)) | ||
357 | ptrPtr.Elem().Set(reflect.New(rawType)) | ||
358 | ptr := ptrPtr.Elem().Interface() | ||
359 | err := json.Unmarshal(buf, ptr) | ||
360 | if err != nil { | ||
361 | return cty.NilVal, path.NewError(err) | ||
362 | } | ||
363 | |||
364 | return cty.CapsuleVal(t, ptr), nil | ||
365 | } | ||
366 | |||
367 | func unmarshalDynamic(buf []byte, path cty.Path) (cty.Value, error) { | ||
368 | dec := bufDecoder(buf) | ||
369 | if err := requireDelim(dec, '{'); err != nil { | ||
370 | return cty.NilVal, path.NewError(err) | ||
371 | } | ||
372 | |||
373 | var t cty.Type | ||
374 | var valBody []byte // defer actual decoding until we know the type | ||
375 | |||
376 | for dec.More() { | ||
377 | var err error | ||
378 | |||
379 | key, err := requireObjectKey(dec) | ||
380 | if err != nil { | ||
381 | return cty.NilVal, path.NewErrorf("failed to read dynamic type descriptor key: %s", err) | ||
382 | } | ||
383 | |||
384 | rawVal, err := readRawValue(dec) | ||
385 | if err != nil { | ||
386 | return cty.NilVal, path.NewErrorf("failed to read dynamic type descriptor value: %s", err) | ||
387 | } | ||
388 | |||
389 | switch key { | ||
390 | case "type": | ||
391 | err := json.Unmarshal(rawVal, &t) | ||
392 | if err != nil { | ||
393 | return cty.NilVal, path.NewErrorf("failed to decode type for dynamic value: %s", err) | ||
394 | } | ||
395 | case "value": | ||
396 | valBody = rawVal | ||
397 | default: | ||
398 | return cty.NilVal, path.NewErrorf("invalid key %q in dynamically-typed value", key) | ||
399 | } | ||
400 | |||
401 | } | ||
402 | |||
403 | if err := requireDelim(dec, '}'); err != nil { | ||
404 | return cty.NilVal, path.NewError(err) | ||
405 | } | ||
406 | |||
407 | if t == cty.NilType { | ||
408 | return cty.NilVal, path.NewErrorf("missing type in dynamically-typed value") | ||
409 | } | ||
410 | if valBody == nil { | ||
411 | return cty.NilVal, path.NewErrorf("missing value in dynamically-typed value") | ||
412 | } | ||
413 | |||
414 | val, err := Unmarshal([]byte(valBody), t) | ||
415 | if err != nil { | ||
416 | return cty.NilVal, path.NewError(err) | ||
417 | } | ||
418 | return val, nil | ||
419 | } | ||
420 | |||
421 | func requireDelim(dec *json.Decoder, d rune) error { | ||
422 | tok, err := dec.Token() | ||
423 | if err != nil { | ||
424 | return err | ||
425 | } | ||
426 | |||
427 | if tok != json.Delim(d) { | ||
428 | return fmt.Errorf("missing expected %c", d) | ||
429 | } | ||
430 | |||
431 | return nil | ||
432 | } | ||
433 | |||
434 | func requireObjectKey(dec *json.Decoder) (string, error) { | ||
435 | tok, err := dec.Token() | ||
436 | if err != nil { | ||
437 | return "", err | ||
438 | } | ||
439 | if s, ok := tok.(string); ok { | ||
440 | return s, nil | ||
441 | } | ||
442 | return "", fmt.Errorf("missing expected object key") | ||
443 | } | ||
444 | |||
445 | func readRawValue(dec *json.Decoder) ([]byte, error) { | ||
446 | var rawVal json.RawMessage | ||
447 | err := dec.Decode(&rawVal) | ||
448 | if err != nil { | ||
449 | return nil, err | ||
450 | } | ||
451 | return []byte(rawVal), nil | ||
452 | } | ||
453 | |||
454 | func bufDecoder(buf []byte) *json.Decoder { | ||
455 | r := bytes.NewReader(buf) | ||
456 | dec := json.NewDecoder(r) | ||
457 | dec.UseNumber() | ||
458 | return dec | ||
459 | } | ||
diff --git a/vendor/github.com/zclconf/go-cty/cty/json/value.go b/vendor/github.com/zclconf/go-cty/cty/json/value.go new file mode 100644 index 0000000..f2f7dd5 --- /dev/null +++ b/vendor/github.com/zclconf/go-cty/cty/json/value.go | |||
@@ -0,0 +1,65 @@ | |||
1 | package json | ||
2 | |||
3 | import ( | ||
4 | "bytes" | ||
5 | |||
6 | "github.com/zclconf/go-cty/cty" | ||
7 | "github.com/zclconf/go-cty/cty/convert" | ||
8 | ) | ||
9 | |||
10 | // Marshal produces a JSON representation of the given value that can later | ||
11 | // be decoded into a value of the given type. | ||
12 | // | ||
13 | // A type is specified separately to allow for the given type to include | ||
14 | // cty.DynamicPseudoType to represent situations where any type is permitted | ||
15 | // and so type information must be included to allow recovery of the stored | ||
16 | // structure when decoding. | ||
17 | // | ||
18 | // The given type will also be used to attempt automatic conversions of any | ||
19 | // non-conformant types in the given value, although this will not always | ||
20 | // be possible. If the value cannot be made to be conformant then an error is | ||
21 | // returned, which may be a cty.PathError. | ||
22 | // | ||
23 | // Capsule-typed values can be marshalled, but with some caveats. Since | ||
24 | // capsule values are compared by pointer equality, it is impossible to recover | ||
25 | // a value that will compare equal to the original value. Additionally, | ||
26 | // it's not possible to JSON-serialize the capsule type itself, so it's not | ||
27 | // valid to use capsule types within parts of the value that are conformed to | ||
28 | // cty.DynamicPseudoType. Otherwise, a capsule value can be used as long as | ||
29 | // the encapsulated type itself is serializable with the Marshal function | ||
30 | // in encoding/json. | ||
31 | func Marshal(val cty.Value, t cty.Type) ([]byte, error) { | ||
32 | errs := val.Type().TestConformance(t) | ||
33 | if errs != nil { | ||
34 | // Attempt a conversion | ||
35 | var err error | ||
36 | val, err = convert.Convert(val, t) | ||
37 | if err != nil { | ||
38 | return nil, err | ||
39 | } | ||
40 | } | ||
41 | |||
42 | // From this point onward, val can be assumed to be conforming to t. | ||
43 | |||
44 | buf := &bytes.Buffer{} | ||
45 | var path cty.Path | ||
46 | err := marshal(val, t, path, buf) | ||
47 | |||
48 | if err != nil { | ||
49 | return nil, err | ||
50 | } | ||
51 | |||
52 | return buf.Bytes(), nil | ||
53 | } | ||
54 | |||
55 | // Unmarshal decodes a JSON representation of the given value into a cty Value | ||
56 | // conforming to the given type. | ||
57 | // | ||
58 | // While decoding, type conversions will be done where possible to make | ||
59 | // the result conformant even if the types given in JSON are not exactly | ||
60 | // correct. If conversion isn't possible then an error is returned, which | ||
61 | // may be a cty.PathError. | ||
62 | func Unmarshal(buf []byte, t cty.Type) (cty.Value, error) { | ||
63 | var path cty.Path | ||
64 | return unmarshal(buf, t, path) | ||
65 | } | ||
diff --git a/vendor/github.com/zclconf/go-cty/cty/list_type.go b/vendor/github.com/zclconf/go-cty/cty/list_type.go new file mode 100644 index 0000000..eadc865 --- /dev/null +++ b/vendor/github.com/zclconf/go-cty/cty/list_type.go | |||
@@ -0,0 +1,68 @@ | |||
1 | package cty | ||
2 | |||
3 | import ( | ||
4 | "fmt" | ||
5 | ) | ||
6 | |||
7 | // TypeList instances represent specific list types. Each distinct ElementType | ||
8 | // creates a distinct, non-equal list type. | ||
9 | type typeList struct { | ||
10 | typeImplSigil | ||
11 | ElementTypeT Type | ||
12 | } | ||
13 | |||
14 | // List creates a map type with the given element Type. | ||
15 | // | ||
16 | // List types are CollectionType implementations. | ||
17 | func List(elem Type) Type { | ||
18 | return Type{ | ||
19 | typeList{ | ||
20 | ElementTypeT: elem, | ||
21 | }, | ||
22 | } | ||
23 | } | ||
24 | |||
25 | // Equals returns true if the other Type is a list whose element type is | ||
26 | // equal to that of the receiver. | ||
27 | func (t typeList) Equals(other Type) bool { | ||
28 | ot, isList := other.typeImpl.(typeList) | ||
29 | if !isList { | ||
30 | return false | ||
31 | } | ||
32 | |||
33 | return t.ElementTypeT.Equals(ot.ElementTypeT) | ||
34 | } | ||
35 | |||
36 | func (t typeList) FriendlyName() string { | ||
37 | return "list of " + t.ElementTypeT.FriendlyName() | ||
38 | } | ||
39 | |||
40 | func (t typeList) ElementType() Type { | ||
41 | return t.ElementTypeT | ||
42 | } | ||
43 | |||
44 | func (t typeList) GoString() string { | ||
45 | return fmt.Sprintf("cty.List(%#v)", t.ElementTypeT) | ||
46 | } | ||
47 | |||
48 | // IsListType returns true if the given type is a list type, regardless of its | ||
49 | // element type. | ||
50 | func (t Type) IsListType() bool { | ||
51 | _, ok := t.typeImpl.(typeList) | ||
52 | return ok | ||
53 | } | ||
54 | |||
55 | // ListElementType is a convenience method that checks if the given type is | ||
56 | // a list type, returning a pointer to its element type if so and nil | ||
57 | // otherwise. This is intended to allow convenient conditional branches, | ||
58 | // like so: | ||
59 | // | ||
60 | // if et := t.ListElementType(); et != nil { | ||
61 | // // Do something with *et | ||
62 | // } | ||
63 | func (t Type) ListElementType() *Type { | ||
64 | if lt, ok := t.typeImpl.(typeList); ok { | ||
65 | return <.ElementTypeT | ||
66 | } | ||
67 | return nil | ||
68 | } | ||
diff --git a/vendor/github.com/zclconf/go-cty/cty/map_type.go b/vendor/github.com/zclconf/go-cty/cty/map_type.go new file mode 100644 index 0000000..ae9abae --- /dev/null +++ b/vendor/github.com/zclconf/go-cty/cty/map_type.go | |||
@@ -0,0 +1,68 @@ | |||
1 | package cty | ||
2 | |||
3 | import ( | ||
4 | "fmt" | ||
5 | ) | ||
6 | |||
7 | // TypeList instances represent specific list types. Each distinct ElementType | ||
8 | // creates a distinct, non-equal list type. | ||
9 | type typeMap struct { | ||
10 | typeImplSigil | ||
11 | ElementTypeT Type | ||
12 | } | ||
13 | |||
14 | // Map creates a map type with the given element Type. | ||
15 | // | ||
16 | // Map types are CollectionType implementations. | ||
17 | func Map(elem Type) Type { | ||
18 | return Type{ | ||
19 | typeMap{ | ||
20 | ElementTypeT: elem, | ||
21 | }, | ||
22 | } | ||
23 | } | ||
24 | |||
25 | // Equals returns true if the other Type is a map whose element type is | ||
26 | // equal to that of the receiver. | ||
27 | func (t typeMap) Equals(other Type) bool { | ||
28 | ot, isMap := other.typeImpl.(typeMap) | ||
29 | if !isMap { | ||
30 | return false | ||
31 | } | ||
32 | |||
33 | return t.ElementTypeT.Equals(ot.ElementTypeT) | ||
34 | } | ||
35 | |||
36 | func (t typeMap) FriendlyName() string { | ||
37 | return "map of " + t.ElementTypeT.FriendlyName() | ||
38 | } | ||
39 | |||
40 | func (t typeMap) ElementType() Type { | ||
41 | return t.ElementTypeT | ||
42 | } | ||
43 | |||
44 | func (t typeMap) GoString() string { | ||
45 | return fmt.Sprintf("cty.Map(%#v)", t.ElementTypeT) | ||
46 | } | ||
47 | |||
48 | // IsMapType returns true if the given type is a list type, regardless of its | ||
49 | // element type. | ||
50 | func (t Type) IsMapType() bool { | ||
51 | _, ok := t.typeImpl.(typeMap) | ||
52 | return ok | ||
53 | } | ||
54 | |||
55 | // MapElementType is a convenience method that checks if the given type is | ||
56 | // a map type, returning a pointer to its element type if so and nil | ||
57 | // otherwise. This is intended to allow convenient conditional branches, | ||
58 | // like so: | ||
59 | // | ||
60 | // if et := t.MapElementType(); et != nil { | ||
61 | // // Do something with *et | ||
62 | // } | ||
63 | func (t Type) MapElementType() *Type { | ||
64 | if lt, ok := t.typeImpl.(typeMap); ok { | ||
65 | return <.ElementTypeT | ||
66 | } | ||
67 | return nil | ||
68 | } | ||
diff --git a/vendor/github.com/zclconf/go-cty/cty/null.go b/vendor/github.com/zclconf/go-cty/cty/null.go new file mode 100644 index 0000000..d58d028 --- /dev/null +++ b/vendor/github.com/zclconf/go-cty/cty/null.go | |||
@@ -0,0 +1,14 @@ | |||
1 | package cty | ||
2 | |||
3 | // NullVal returns a null value of the given type. A null can be created of any | ||
4 | // type, but operations on such values will always panic. Calling applications | ||
5 | // are encouraged to use nulls only sparingly, particularly when user-provided | ||
6 | // expressions are to be evaluated, since the precence of nulls creates a | ||
7 | // much higher chance of evaluation errors that can't be caught by a type | ||
8 | // checker. | ||
9 | func NullVal(t Type) Value { | ||
10 | return Value{ | ||
11 | ty: t, | ||
12 | v: nil, | ||
13 | } | ||
14 | } | ||
diff --git a/vendor/github.com/zclconf/go-cty/cty/object_type.go b/vendor/github.com/zclconf/go-cty/cty/object_type.go new file mode 100644 index 0000000..2540883 --- /dev/null +++ b/vendor/github.com/zclconf/go-cty/cty/object_type.go | |||
@@ -0,0 +1,135 @@ | |||
1 | package cty | ||
2 | |||
3 | import ( | ||
4 | "fmt" | ||
5 | ) | ||
6 | |||
7 | type typeObject struct { | ||
8 | typeImplSigil | ||
9 | AttrTypes map[string]Type | ||
10 | } | ||
11 | |||
12 | // Object creates an object type with the given attribute types. | ||
13 | // | ||
14 | // After a map is passed to this function the caller must no longer access it, | ||
15 | // since ownership is transferred to this library. | ||
16 | func Object(attrTypes map[string]Type) Type { | ||
17 | attrTypesNorm := make(map[string]Type, len(attrTypes)) | ||
18 | for k, v := range attrTypes { | ||
19 | attrTypesNorm[NormalizeString(k)] = v | ||
20 | } | ||
21 | |||
22 | return Type{ | ||
23 | typeObject{ | ||
24 | AttrTypes: attrTypesNorm, | ||
25 | }, | ||
26 | } | ||
27 | } | ||
28 | |||
29 | func (t typeObject) Equals(other Type) bool { | ||
30 | if ot, ok := other.typeImpl.(typeObject); ok { | ||
31 | if len(t.AttrTypes) != len(ot.AttrTypes) { | ||
32 | // Fast path: if we don't have the same number of attributes | ||
33 | // then we can't possibly be equal. This also avoids the need | ||
34 | // to test attributes in both directions below, since we know | ||
35 | // there can't be extras in "other". | ||
36 | return false | ||
37 | } | ||
38 | |||
39 | for attr, ty := range t.AttrTypes { | ||
40 | oty, ok := ot.AttrTypes[attr] | ||
41 | if !ok { | ||
42 | return false | ||
43 | } | ||
44 | if !oty.Equals(ty) { | ||
45 | return false | ||
46 | } | ||
47 | } | ||
48 | |||
49 | return true | ||
50 | } | ||
51 | return false | ||
52 | } | ||
53 | |||
54 | func (t typeObject) FriendlyName() string { | ||
55 | // There isn't really a friendly way to write an object type due to its | ||
56 | // complexity, so we'll just do something English-ish. Callers will | ||
57 | // probably want to make some extra effort to avoid ever printing out | ||
58 | // an object type FriendlyName in its entirety. For example, could | ||
59 | // produce an error message by diffing two object types and saying | ||
60 | // something like "Expected attribute foo to be string, but got number". | ||
61 | // TODO: Finish this | ||
62 | return "object" | ||
63 | } | ||
64 | |||
65 | func (t typeObject) GoString() string { | ||
66 | if len(t.AttrTypes) == 0 { | ||
67 | return "cty.EmptyObject" | ||
68 | } | ||
69 | return fmt.Sprintf("cty.Object(%#v)", t.AttrTypes) | ||
70 | } | ||
71 | |||
72 | // EmptyObject is a shorthand for Object(map[string]Type{}), to more | ||
73 | // easily talk about the empty object type. | ||
74 | var EmptyObject Type | ||
75 | |||
76 | // EmptyObjectVal is the only possible non-null, non-unknown value of type | ||
77 | // EmptyObject. | ||
78 | var EmptyObjectVal Value | ||
79 | |||
80 | func init() { | ||
81 | EmptyObject = Object(map[string]Type{}) | ||
82 | EmptyObjectVal = Value{ | ||
83 | ty: EmptyObject, | ||
84 | v: map[string]interface{}{}, | ||
85 | } | ||
86 | } | ||
87 | |||
88 | // IsObjectType returns true if the given type is an object type, regardless | ||
89 | // of its element type. | ||
90 | func (t Type) IsObjectType() bool { | ||
91 | _, ok := t.typeImpl.(typeObject) | ||
92 | return ok | ||
93 | } | ||
94 | |||
95 | // HasAttribute returns true if the receiver has an attribute with the given | ||
96 | // name, regardless of its type. Will panic if the reciever isn't an object | ||
97 | // type; use IsObjectType to determine whether this operation will succeed. | ||
98 | func (t Type) HasAttribute(name string) bool { | ||
99 | name = NormalizeString(name) | ||
100 | if ot, ok := t.typeImpl.(typeObject); ok { | ||
101 | _, hasAttr := ot.AttrTypes[name] | ||
102 | return hasAttr | ||
103 | } | ||
104 | panic("HasAttribute on non-object Type") | ||
105 | } | ||
106 | |||
107 | // AttributeType returns the type of the attribute with the given name. Will | ||
108 | // panic if the receiver is not an object type (use IsObjectType to confirm) | ||
109 | // or if the object type has no such attribute (use HasAttribute to confirm). | ||
110 | func (t Type) AttributeType(name string) Type { | ||
111 | name = NormalizeString(name) | ||
112 | if ot, ok := t.typeImpl.(typeObject); ok { | ||
113 | aty, hasAttr := ot.AttrTypes[name] | ||
114 | if !hasAttr { | ||
115 | panic("no such attribute") | ||
116 | } | ||
117 | return aty | ||
118 | } | ||
119 | panic("AttributeType on non-object Type") | ||
120 | } | ||
121 | |||
122 | // AttributeTypes returns a map from attribute names to their associated | ||
123 | // types. Will panic if the receiver is not an object type (use IsObjectType | ||
124 | // to confirm). | ||
125 | // | ||
126 | // The returned map is part of the internal state of the type, and is provided | ||
127 | // for read access only. It is forbidden for any caller to modify the returned | ||
128 | // map. For many purposes the attribute-related methods of Value are more | ||
129 | // appropriate and more convenient to use. | ||
130 | func (t Type) AttributeTypes() map[string]Type { | ||
131 | if ot, ok := t.typeImpl.(typeObject); ok { | ||
132 | return ot.AttrTypes | ||
133 | } | ||
134 | panic("AttributeTypes on non-object Type") | ||
135 | } | ||
diff --git a/vendor/github.com/zclconf/go-cty/cty/path.go b/vendor/github.com/zclconf/go-cty/cty/path.go new file mode 100644 index 0000000..84a9de0 --- /dev/null +++ b/vendor/github.com/zclconf/go-cty/cty/path.go | |||
@@ -0,0 +1,186 @@ | |||
1 | package cty | ||
2 | |||
3 | import ( | ||
4 | "errors" | ||
5 | "fmt" | ||
6 | ) | ||
7 | |||
8 | // A Path is a sequence of operations to locate a nested value within a | ||
9 | // data structure. | ||
10 | // | ||
11 | // The empty Path represents the given item. Any PathSteps within represent | ||
12 | // taking a single step down into a data structure. | ||
13 | // | ||
14 | // Path has some convenience methods for gradually constructing a path, | ||
15 | // but callers can also feel free to just produce a slice of PathStep manually | ||
16 | // and convert to this type, which may be more appropriate in environments | ||
17 | // where memory pressure is a concern. | ||
18 | type Path []PathStep | ||
19 | |||
20 | // PathStep represents a single step down into a data structure, as part | ||
21 | // of a Path. PathStep is a closed interface, meaning that the only | ||
22 | // permitted implementations are those within this package. | ||
23 | type PathStep interface { | ||
24 | pathStepSigil() pathStepImpl | ||
25 | Apply(Value) (Value, error) | ||
26 | } | ||
27 | |||
28 | // embed pathImpl into a struct to declare it a PathStep implementation | ||
29 | type pathStepImpl struct{} | ||
30 | |||
31 | func (p pathStepImpl) pathStepSigil() pathStepImpl { | ||
32 | return p | ||
33 | } | ||
34 | |||
35 | // Index returns a new Path that is the reciever with an IndexStep appended | ||
36 | // to the end. | ||
37 | // | ||
38 | // This is provided as a convenient way to construct paths, but each call | ||
39 | // will create garbage so it should not be used where memory pressure is a | ||
40 | // concern. | ||
41 | func (p Path) Index(v Value) Path { | ||
42 | ret := make(Path, len(p)+1) | ||
43 | copy(ret, p) | ||
44 | ret[len(p)] = IndexStep{ | ||
45 | Key: v, | ||
46 | } | ||
47 | return ret | ||
48 | } | ||
49 | |||
50 | // GetAttr returns a new Path that is the reciever with a GetAttrStep appended | ||
51 | // to the end. | ||
52 | // | ||
53 | // This is provided as a convenient way to construct paths, but each call | ||
54 | // will create garbage so it should not be used where memory pressure is a | ||
55 | // concern. | ||
56 | func (p Path) GetAttr(name string) Path { | ||
57 | ret := make(Path, len(p)+1) | ||
58 | copy(ret, p) | ||
59 | ret[len(p)] = GetAttrStep{ | ||
60 | Name: name, | ||
61 | } | ||
62 | return ret | ||
63 | } | ||
64 | |||
65 | // Apply applies each of the steps in turn to successive values starting with | ||
66 | // the given value, and returns the result. If any step returns an error, | ||
67 | // the whole operation returns an error. | ||
68 | func (p Path) Apply(val Value) (Value, error) { | ||
69 | var err error | ||
70 | for i, step := range p { | ||
71 | val, err = step.Apply(val) | ||
72 | if err != nil { | ||
73 | return NilVal, fmt.Errorf("at step %d: %s", i, err) | ||
74 | } | ||
75 | } | ||
76 | return val, nil | ||
77 | } | ||
78 | |||
79 | // LastStep applies the given path up to the last step and then returns | ||
80 | // the resulting value and the final step. | ||
81 | // | ||
82 | // This is useful when dealing with assignment operations, since in that | ||
83 | // case the *value* of the last step is not important (and may not, in fact, | ||
84 | // present at all) and we care only about its location. | ||
85 | // | ||
86 | // Since LastStep applies all steps except the last, it will return errors | ||
87 | // for those steps in the same way as Apply does. | ||
88 | // | ||
89 | // If the path has *no* steps then the returned PathStep will be nil, | ||
90 | // representing that any operation should be applied directly to the | ||
91 | // given value. | ||
92 | func (p Path) LastStep(val Value) (Value, PathStep, error) { | ||
93 | var err error | ||
94 | |||
95 | if len(p) == 0 { | ||
96 | return val, nil, nil | ||
97 | } | ||
98 | |||
99 | journey := p[:len(p)-1] | ||
100 | val, err = journey.Apply(val) | ||
101 | if err != nil { | ||
102 | return NilVal, nil, err | ||
103 | } | ||
104 | return val, p[len(p)-1], nil | ||
105 | } | ||
106 | |||
107 | // Copy makes a shallow copy of the receiver. Often when paths are passed to | ||
108 | // caller code they come with the constraint that they are valid only until | ||
109 | // the caller returns, due to how they are constructed internally. Callers | ||
110 | // can use Copy to conveniently produce a copy of the value that _they_ control | ||
111 | // the validity of. | ||
112 | func (p Path) Copy() Path { | ||
113 | ret := make(Path, len(p)) | ||
114 | copy(ret, p) | ||
115 | return ret | ||
116 | } | ||
117 | |||
118 | // IndexStep is a Step implementation representing applying the index operation | ||
119 | // to a value, which must be of either a list, map, or set type. | ||
120 | // | ||
121 | // When describing a path through a *type* rather than a concrete value, | ||
122 | // the Key may be an unknown value, indicating that the step applies to | ||
123 | // *any* key of the given type. | ||
124 | // | ||
125 | // When indexing into a set, the Key is actually the element being accessed | ||
126 | // itself, since in sets elements are their own identity. | ||
127 | type IndexStep struct { | ||
128 | pathStepImpl | ||
129 | Key Value | ||
130 | } | ||
131 | |||
132 | // Apply returns the value resulting from indexing the given value with | ||
133 | // our key value. | ||
134 | func (s IndexStep) Apply(val Value) (Value, error) { | ||
135 | switch s.Key.Type() { | ||
136 | case Number: | ||
137 | if !val.Type().IsListType() { | ||
138 | return NilVal, errors.New("not a list type") | ||
139 | } | ||
140 | case String: | ||
141 | if !val.Type().IsMapType() { | ||
142 | return NilVal, errors.New("not a map type") | ||
143 | } | ||
144 | default: | ||
145 | return NilVal, errors.New("key value not number or string") | ||
146 | } | ||
147 | |||
148 | has := val.HasIndex(s.Key) | ||
149 | if !has.IsKnown() { | ||
150 | return UnknownVal(val.Type().ElementType()), nil | ||
151 | } | ||
152 | if !has.True() { | ||
153 | return NilVal, errors.New("value does not have given index key") | ||
154 | } | ||
155 | |||
156 | return val.Index(s.Key), nil | ||
157 | } | ||
158 | |||
159 | func (s IndexStep) GoString() string { | ||
160 | return fmt.Sprintf("cty.IndexStep{Key:%#v}", s.Key) | ||
161 | } | ||
162 | |||
163 | // GetAttrStep is a Step implementation representing retrieving an attribute | ||
164 | // from a value, which must be of an object type. | ||
165 | type GetAttrStep struct { | ||
166 | pathStepImpl | ||
167 | Name string | ||
168 | } | ||
169 | |||
170 | // Apply returns the value of our named attribute from the given value, which | ||
171 | // must be of an object type that has a value of that name. | ||
172 | func (s GetAttrStep) Apply(val Value) (Value, error) { | ||
173 | if !val.Type().IsObjectType() { | ||
174 | return NilVal, errors.New("not an object type") | ||
175 | } | ||
176 | |||
177 | if !val.Type().HasAttribute(s.Name) { | ||
178 | return NilVal, fmt.Errorf("object has no attribute %q", s.Name) | ||
179 | } | ||
180 | |||
181 | return val.GetAttr(s.Name), nil | ||
182 | } | ||
183 | |||
184 | func (s GetAttrStep) GoString() string { | ||
185 | return fmt.Sprintf("cty.GetAttrStep{Name:%q}", s.Name) | ||
186 | } | ||
diff --git a/vendor/github.com/zclconf/go-cty/cty/primitive_type.go b/vendor/github.com/zclconf/go-cty/cty/primitive_type.go new file mode 100644 index 0000000..b8682dd --- /dev/null +++ b/vendor/github.com/zclconf/go-cty/cty/primitive_type.go | |||
@@ -0,0 +1,122 @@ | |||
1 | package cty | ||
2 | |||
3 | import "math/big" | ||
4 | |||
5 | // primitiveType is the hidden implementation of the various primitive types | ||
6 | // that are exposed as variables in this package. | ||
7 | type primitiveType struct { | ||
8 | typeImplSigil | ||
9 | Kind primitiveTypeKind | ||
10 | } | ||
11 | |||
12 | type primitiveTypeKind byte | ||
13 | |||
14 | const ( | ||
15 | primitiveTypeBool primitiveTypeKind = 'B' | ||
16 | primitiveTypeNumber primitiveTypeKind = 'N' | ||
17 | primitiveTypeString primitiveTypeKind = 'S' | ||
18 | ) | ||
19 | |||
20 | func (t primitiveType) Equals(other Type) bool { | ||
21 | if otherP, ok := other.typeImpl.(primitiveType); ok { | ||
22 | return otherP.Kind == t.Kind | ||
23 | } | ||
24 | return false | ||
25 | } | ||
26 | |||
27 | func (t primitiveType) FriendlyName() string { | ||
28 | switch t.Kind { | ||
29 | case primitiveTypeBool: | ||
30 | return "bool" | ||
31 | case primitiveTypeNumber: | ||
32 | return "number" | ||
33 | case primitiveTypeString: | ||
34 | return "string" | ||
35 | default: | ||
36 | // should never happen | ||
37 | panic("invalid primitive type") | ||
38 | } | ||
39 | } | ||
40 | |||
41 | func (t primitiveType) GoString() string { | ||
42 | switch t.Kind { | ||
43 | case primitiveTypeBool: | ||
44 | return "cty.Bool" | ||
45 | case primitiveTypeNumber: | ||
46 | return "cty.Number" | ||
47 | case primitiveTypeString: | ||
48 | return "cty.String" | ||
49 | default: | ||
50 | // should never happen | ||
51 | panic("invalid primitive type") | ||
52 | } | ||
53 | } | ||
54 | |||
55 | // Number is the numeric type. Number values are arbitrary-precision | ||
56 | // decimal numbers, which can then be converted into Go's various numeric | ||
57 | // types only if they are in the appropriate range. | ||
58 | var Number Type | ||
59 | |||
60 | // String is the string type. String values are sequences of unicode codepoints | ||
61 | // encoded internally as UTF-8. | ||
62 | var String Type | ||
63 | |||
64 | // Bool is the boolean type. The two values of this type are True and False. | ||
65 | var Bool Type | ||
66 | |||
67 | // True is the truthy value of type Bool | ||
68 | var True Value | ||
69 | |||
70 | // False is the falsey value of type Bool | ||
71 | var False Value | ||
72 | |||
73 | // Zero is a number value representing exactly zero. | ||
74 | var Zero Value | ||
75 | |||
76 | // PositiveInfinity is a Number value representing positive infinity | ||
77 | var PositiveInfinity Value | ||
78 | |||
79 | // NegativeInfinity is a Number value representing negative infinity | ||
80 | var NegativeInfinity Value | ||
81 | |||
82 | func init() { | ||
83 | Number = Type{ | ||
84 | primitiveType{Kind: primitiveTypeNumber}, | ||
85 | } | ||
86 | String = Type{ | ||
87 | primitiveType{Kind: primitiveTypeString}, | ||
88 | } | ||
89 | Bool = Type{ | ||
90 | primitiveType{Kind: primitiveTypeBool}, | ||
91 | } | ||
92 | True = Value{ | ||
93 | ty: Bool, | ||
94 | v: true, | ||
95 | } | ||
96 | False = Value{ | ||
97 | ty: Bool, | ||
98 | v: false, | ||
99 | } | ||
100 | Zero = Value{ | ||
101 | ty: Number, | ||
102 | v: big.NewFloat(0), | ||
103 | } | ||
104 | PositiveInfinity = Value{ | ||
105 | ty: Number, | ||
106 | v: (&big.Float{}).SetInf(false), | ||
107 | } | ||
108 | NegativeInfinity = Value{ | ||
109 | ty: Number, | ||
110 | v: (&big.Float{}).SetInf(true), | ||
111 | } | ||
112 | } | ||
113 | |||
114 | // IsPrimitiveType returns true if and only if the reciever is a primitive | ||
115 | // type, which means it's either number, string, or bool. Any two primitive | ||
116 | // types can be safely compared for equality using the standard == operator | ||
117 | // without panic, which is not a guarantee that holds for all types. Primitive | ||
118 | // types can therefore also be used in switch statements. | ||
119 | func (t Type) IsPrimitiveType() bool { | ||
120 | _, ok := t.typeImpl.(primitiveType) | ||
121 | return ok | ||
122 | } | ||
diff --git a/vendor/github.com/zclconf/go-cty/cty/set/gob.go b/vendor/github.com/zclconf/go-cty/cty/set/gob.go new file mode 100644 index 0000000..da2978f --- /dev/null +++ b/vendor/github.com/zclconf/go-cty/cty/set/gob.go | |||
@@ -0,0 +1,76 @@ | |||
1 | package set | ||
2 | |||
3 | import ( | ||
4 | "bytes" | ||
5 | "encoding/gob" | ||
6 | "fmt" | ||
7 | ) | ||
8 | |||
9 | // GobEncode is an implementation of the interface gob.GobEncoder, allowing | ||
10 | // sets to be included in structures encoded via gob. | ||
11 | // | ||
12 | // The set rules are included in the serialized value, so the caller must | ||
13 | // register its concrete rules type with gob.Register before using a | ||
14 | // set in a gob, and possibly also implement GobEncode/GobDecode to customize | ||
15 | // how any parameters are persisted. | ||
16 | // | ||
17 | // The set elements are also included, so if they are of non-primitive types | ||
18 | // they too must be registered with gob. | ||
19 | // | ||
20 | // If the produced gob values will persist for a long time, the caller must | ||
21 | // ensure compatibility of the rules implementation. In particular, if the | ||
22 | // definition of element equivalence changes between encoding and decoding | ||
23 | // then two distinct stored elements may be considered equivalent on decoding, | ||
24 | // causing the recovered set to have fewer elements than when it was stored. | ||
25 | func (s Set) GobEncode() ([]byte, error) { | ||
26 | gs := gobSet{ | ||
27 | Version: 0, | ||
28 | Rules: s.rules, | ||
29 | Values: s.Values(), | ||
30 | } | ||
31 | |||
32 | buf := &bytes.Buffer{} | ||
33 | enc := gob.NewEncoder(buf) | ||
34 | err := enc.Encode(gs) | ||
35 | if err != nil { | ||
36 | return nil, fmt.Errorf("error encoding set.Set: %s", err) | ||
37 | } | ||
38 | |||
39 | return buf.Bytes(), nil | ||
40 | } | ||
41 | |||
42 | // GobDecode is the opposite of GobEncode. See GobEncode for information | ||
43 | // on the requirements for and caveats of including set values in gobs. | ||
44 | func (s *Set) GobDecode(buf []byte) error { | ||
45 | r := bytes.NewReader(buf) | ||
46 | dec := gob.NewDecoder(r) | ||
47 | |||
48 | var gs gobSet | ||
49 | err := dec.Decode(&gs) | ||
50 | if err != nil { | ||
51 | return fmt.Errorf("error decoding set.Set: %s", err) | ||
52 | } | ||
53 | if gs.Version != 0 { | ||
54 | return fmt.Errorf("unsupported set.Set encoding version %d; need 0", gs.Version) | ||
55 | } | ||
56 | |||
57 | victim := NewSetFromSlice(gs.Rules, gs.Values) | ||
58 | s.vals = victim.vals | ||
59 | s.rules = victim.rules | ||
60 | return nil | ||
61 | } | ||
62 | |||
63 | type gobSet struct { | ||
64 | Version int | ||
65 | Rules Rules | ||
66 | |||
67 | // The bucket-based representation is for efficient in-memory access, but | ||
68 | // for serialization it's enough to just retain the values themselves, | ||
69 | // which we can re-bucket using the rules (which may have changed!) when | ||
70 | // we re-inflate. | ||
71 | Values []interface{} | ||
72 | } | ||
73 | |||
74 | func init() { | ||
75 | gob.Register([]interface{}(nil)) | ||
76 | } | ||
diff --git a/vendor/github.com/zclconf/go-cty/cty/set/iterator.go b/vendor/github.com/zclconf/go-cty/cty/set/iterator.go new file mode 100644 index 0000000..f15498e --- /dev/null +++ b/vendor/github.com/zclconf/go-cty/cty/set/iterator.go | |||
@@ -0,0 +1,36 @@ | |||
1 | package set | ||
2 | |||
3 | type Iterator struct { | ||
4 | bucketIds []int | ||
5 | vals map[int][]interface{} | ||
6 | bucketIdx int | ||
7 | valIdx int | ||
8 | } | ||
9 | |||
10 | func (it *Iterator) Value() interface{} { | ||
11 | return it.currentBucket()[it.valIdx] | ||
12 | } | ||
13 | |||
14 | func (it *Iterator) Next() bool { | ||
15 | if it.bucketIdx == -1 { | ||
16 | // init | ||
17 | if len(it.bucketIds) == 0 { | ||
18 | return false | ||
19 | } | ||
20 | |||
21 | it.valIdx = 0 | ||
22 | it.bucketIdx = 0 | ||
23 | return true | ||
24 | } | ||
25 | |||
26 | it.valIdx++ | ||
27 | if it.valIdx >= len(it.currentBucket()) { | ||
28 | it.valIdx = 0 | ||
29 | it.bucketIdx++ | ||
30 | } | ||
31 | return it.bucketIdx < len(it.bucketIds) | ||
32 | } | ||
33 | |||
34 | func (it *Iterator) currentBucket() []interface{} { | ||
35 | return it.vals[it.bucketIds[it.bucketIdx]] | ||
36 | } | ||
diff --git a/vendor/github.com/zclconf/go-cty/cty/set/ops.go b/vendor/github.com/zclconf/go-cty/cty/set/ops.go new file mode 100644 index 0000000..726e707 --- /dev/null +++ b/vendor/github.com/zclconf/go-cty/cty/set/ops.go | |||
@@ -0,0 +1,199 @@ | |||
1 | package set | ||
2 | |||
3 | import ( | ||
4 | "sort" | ||
5 | ) | ||
6 | |||
7 | // Add inserts the given value into the receiving Set. | ||
8 | // | ||
9 | // This mutates the set in-place. This operation is not thread-safe. | ||
10 | func (s Set) Add(val interface{}) { | ||
11 | hv := s.rules.Hash(val) | ||
12 | if _, ok := s.vals[hv]; !ok { | ||
13 | s.vals[hv] = make([]interface{}, 0, 1) | ||
14 | } | ||
15 | bucket := s.vals[hv] | ||
16 | |||
17 | // See if an equivalent value is already present | ||
18 | for _, ev := range bucket { | ||
19 | if s.rules.Equivalent(val, ev) { | ||
20 | return | ||
21 | } | ||
22 | } | ||
23 | |||
24 | s.vals[hv] = append(bucket, val) | ||
25 | } | ||
26 | |||
27 | // Remove deletes the given value from the receiving set, if indeed it was | ||
28 | // there in the first place. If the value is not present, this is a no-op. | ||
29 | func (s Set) Remove(val interface{}) { | ||
30 | hv := s.rules.Hash(val) | ||
31 | bucket, ok := s.vals[hv] | ||
32 | if !ok { | ||
33 | return | ||
34 | } | ||
35 | |||
36 | for i, ev := range bucket { | ||
37 | if s.rules.Equivalent(val, ev) { | ||
38 | newBucket := make([]interface{}, 0, len(bucket)-1) | ||
39 | newBucket = append(newBucket, bucket[:i]...) | ||
40 | newBucket = append(newBucket, bucket[i+1:]...) | ||
41 | if len(newBucket) > 0 { | ||
42 | s.vals[hv] = newBucket | ||
43 | } else { | ||
44 | delete(s.vals, hv) | ||
45 | } | ||
46 | return | ||
47 | } | ||
48 | } | ||
49 | } | ||
50 | |||
51 | // Has returns true if the given value is in the receiving set, or false if | ||
52 | // it is not. | ||
53 | func (s Set) Has(val interface{}) bool { | ||
54 | hv := s.rules.Hash(val) | ||
55 | bucket, ok := s.vals[hv] | ||
56 | if !ok { | ||
57 | return false | ||
58 | } | ||
59 | |||
60 | for _, ev := range bucket { | ||
61 | if s.rules.Equivalent(val, ev) { | ||
62 | return true | ||
63 | } | ||
64 | } | ||
65 | return false | ||
66 | } | ||
67 | |||
68 | // Copy performs a shallow copy of the receiving set, returning a new set | ||
69 | // with the same rules and elements. | ||
70 | func (s Set) Copy() Set { | ||
71 | ret := NewSet(s.rules) | ||
72 | for k, v := range s.vals { | ||
73 | ret.vals[k] = v | ||
74 | } | ||
75 | return ret | ||
76 | } | ||
77 | |||
78 | // Iterator returns an iterator over values in the set, in an undefined order | ||
79 | // that callers should not depend on. | ||
80 | // | ||
81 | // The pattern for using the returned iterator is: | ||
82 | // | ||
83 | // it := set.Iterator() | ||
84 | // for it.Next() { | ||
85 | // val := it.Value() | ||
86 | // // ... | ||
87 | // } | ||
88 | // | ||
89 | // Once an iterator has been created for a set, the set *must not* be mutated | ||
90 | // until the iterator is no longer in use. | ||
91 | func (s Set) Iterator() *Iterator { | ||
92 | // Sort the bucketIds to ensure that we always traverse in a | ||
93 | // consistent order. | ||
94 | bucketIds := make([]int, 0, len(s.vals)) | ||
95 | for id := range s.vals { | ||
96 | bucketIds = append(bucketIds, id) | ||
97 | } | ||
98 | sort.Ints(bucketIds) | ||
99 | |||
100 | return &Iterator{ | ||
101 | bucketIds: bucketIds, | ||
102 | vals: s.vals, | ||
103 | bucketIdx: -1, | ||
104 | } | ||
105 | } | ||
106 | |||
107 | // EachValue calls the given callback once for each value in the set, in an | ||
108 | // undefined order that callers should not depend on. | ||
109 | func (s Set) EachValue(cb func(interface{})) { | ||
110 | it := s.Iterator() | ||
111 | for it.Next() { | ||
112 | cb(it.Value()) | ||
113 | } | ||
114 | } | ||
115 | |||
116 | // Values returns a slice of all of the values in the set in no particular | ||
117 | // order. This is just a wrapper around EachValue that accumulates the results | ||
118 | // in a slice for caller convenience. | ||
119 | // | ||
120 | // The returned slice will be nil if there are no values in the set. | ||
121 | func (s Set) Values() []interface{} { | ||
122 | var ret []interface{} | ||
123 | s.EachValue(func(v interface{}) { | ||
124 | ret = append(ret, v) | ||
125 | }) | ||
126 | return ret | ||
127 | } | ||
128 | |||
129 | // Length returns the number of values in the set. | ||
130 | func (s Set) Length() int { | ||
131 | var count int | ||
132 | for _, bucket := range s.vals { | ||
133 | count = count + len(bucket) | ||
134 | } | ||
135 | return count | ||
136 | } | ||
137 | |||
138 | // Union returns a new set that contains all of the members of both the | ||
139 | // receiving set and the given set. Both sets must have the same rules, or | ||
140 | // else this function will panic. | ||
141 | func (s1 Set) Union(s2 Set) Set { | ||
142 | mustHaveSameRules(s1, s2) | ||
143 | rs := NewSet(s1.rules) | ||
144 | s1.EachValue(func(v interface{}) { | ||
145 | rs.Add(v) | ||
146 | }) | ||
147 | s2.EachValue(func(v interface{}) { | ||
148 | rs.Add(v) | ||
149 | }) | ||
150 | return rs | ||
151 | } | ||
152 | |||
153 | // Intersection returns a new set that contains the values that both the | ||
154 | // receiver and given sets have in common. Both sets must have the same rules, | ||
155 | // or else this function will panic. | ||
156 | func (s1 Set) Intersection(s2 Set) Set { | ||
157 | mustHaveSameRules(s1, s2) | ||
158 | rs := NewSet(s1.rules) | ||
159 | s1.EachValue(func(v interface{}) { | ||
160 | if s2.Has(v) { | ||
161 | rs.Add(v) | ||
162 | } | ||
163 | }) | ||
164 | return rs | ||
165 | } | ||
166 | |||
167 | // Subtract returns a new set that contains all of the values from the receiver | ||
168 | // that are not also in the given set. Both sets must have the same rules, | ||
169 | // or else this function will panic. | ||
170 | func (s1 Set) Subtract(s2 Set) Set { | ||
171 | mustHaveSameRules(s1, s2) | ||
172 | rs := NewSet(s1.rules) | ||
173 | s1.EachValue(func(v interface{}) { | ||
174 | if !s2.Has(v) { | ||
175 | rs.Add(v) | ||
176 | } | ||
177 | }) | ||
178 | return rs | ||
179 | } | ||
180 | |||
181 | // SymmetricDifference returns a new set that contains all of the values from | ||
182 | // both the receiver and given sets, except those that both sets have in | ||
183 | // common. Both sets must have the same rules, or else this function will | ||
184 | // panic. | ||
185 | func (s1 Set) SymmetricDifference(s2 Set) Set { | ||
186 | mustHaveSameRules(s1, s2) | ||
187 | rs := NewSet(s1.rules) | ||
188 | s1.EachValue(func(v interface{}) { | ||
189 | if !s2.Has(v) { | ||
190 | rs.Add(v) | ||
191 | } | ||
192 | }) | ||
193 | s2.EachValue(func(v interface{}) { | ||
194 | if !s1.Has(v) { | ||
195 | rs.Add(v) | ||
196 | } | ||
197 | }) | ||
198 | return rs | ||
199 | } | ||
diff --git a/vendor/github.com/zclconf/go-cty/cty/set/rules.go b/vendor/github.com/zclconf/go-cty/cty/set/rules.go new file mode 100644 index 0000000..7200184 --- /dev/null +++ b/vendor/github.com/zclconf/go-cty/cty/set/rules.go | |||
@@ -0,0 +1,25 @@ | |||
1 | package set | ||
2 | |||
3 | // Rules represents the operations that define membership for a Set. | ||
4 | // | ||
5 | // Each Set has a Rules instance, whose methods must satisfy the interface | ||
6 | // contracts given below for any value that will be added to the set. | ||
7 | type Rules interface { | ||
8 | // Hash returns an int that somewhat-uniquely identifies the given value. | ||
9 | // | ||
10 | // A good hash function will minimize collisions for values that will be | ||
11 | // added to the set, though collisions *are* permitted. Collisions will | ||
12 | // simply reduce the efficiency of operations on the set. | ||
13 | Hash(interface{}) int | ||
14 | |||
15 | // Equivalent returns true if and only if the two values are considered | ||
16 | // equivalent for the sake of set membership. Two values that are | ||
17 | // equivalent cannot exist in the set at the same time, and if two | ||
18 | // equivalent values are added it is undefined which one will be | ||
19 | // returned when enumerating all of the set members. | ||
20 | // | ||
21 | // Two values that are equivalent *must* result in the same hash value, | ||
22 | // though it is *not* required that two values with the same hash value | ||
23 | // be equivalent. | ||
24 | Equivalent(interface{}, interface{}) bool | ||
25 | } | ||
diff --git a/vendor/github.com/zclconf/go-cty/cty/set/set.go b/vendor/github.com/zclconf/go-cty/cty/set/set.go new file mode 100644 index 0000000..b4fb316 --- /dev/null +++ b/vendor/github.com/zclconf/go-cty/cty/set/set.go | |||
@@ -0,0 +1,62 @@ | |||
1 | package set | ||
2 | |||
3 | import ( | ||
4 | "fmt" | ||
5 | ) | ||
6 | |||
7 | // Set is an implementation of the concept of a set: a collection where all | ||
8 | // values are conceptually either in or out of the set, but the members are | ||
9 | // not ordered. | ||
10 | // | ||
11 | // This type primarily exists to be the internal type of sets in cty, but | ||
12 | // it is considered to be at the same level of abstraction as Go's built in | ||
13 | // slice and map collection types, and so should make no cty-specific | ||
14 | // assumptions. | ||
15 | // | ||
16 | // Set operations are not thread safe. It is the caller's responsibility to | ||
17 | // provide mutex guarantees where necessary. | ||
18 | // | ||
19 | // Set operations are not optimized to minimize memory pressure. Mutating | ||
20 | // a set will generally create garbage and so should perhaps be avoided in | ||
21 | // tight loops where memory pressure is a concern. | ||
22 | type Set struct { | ||
23 | vals map[int][]interface{} | ||
24 | rules Rules | ||
25 | } | ||
26 | |||
27 | // NewSet returns an empty set with the membership rules given. | ||
28 | func NewSet(rules Rules) Set { | ||
29 | return Set{ | ||
30 | vals: map[int][]interface{}{}, | ||
31 | rules: rules, | ||
32 | } | ||
33 | } | ||
34 | |||
35 | func NewSetFromSlice(rules Rules, vals []interface{}) Set { | ||
36 | s := NewSet(rules) | ||
37 | for _, v := range vals { | ||
38 | s.Add(v) | ||
39 | } | ||
40 | return s | ||
41 | } | ||
42 | |||
43 | func sameRules(s1 Set, s2 Set) bool { | ||
44 | return s1.rules == s2.rules | ||
45 | } | ||
46 | |||
47 | func mustHaveSameRules(s1 Set, s2 Set) { | ||
48 | if !sameRules(s1, s2) { | ||
49 | panic(fmt.Errorf("incompatible set rules: %#v, %#v", s1.rules, s2.rules)) | ||
50 | } | ||
51 | } | ||
52 | |||
53 | // HasRules returns true if and only if the receiving set has the given rules | ||
54 | // instance as its rules. | ||
55 | func (s Set) HasRules(rules Rules) bool { | ||
56 | return s.rules == rules | ||
57 | } | ||
58 | |||
59 | // Rules returns the receiving set's rules instance. | ||
60 | func (s Set) Rules() Rules { | ||
61 | return s.rules | ||
62 | } | ||
diff --git a/vendor/github.com/zclconf/go-cty/cty/set_helper.go b/vendor/github.com/zclconf/go-cty/cty/set_helper.go new file mode 100644 index 0000000..a88ddaf --- /dev/null +++ b/vendor/github.com/zclconf/go-cty/cty/set_helper.go | |||
@@ -0,0 +1,126 @@ | |||
1 | package cty | ||
2 | |||
3 | import ( | ||
4 | "fmt" | ||
5 | |||
6 | "github.com/zclconf/go-cty/cty/set" | ||
7 | ) | ||
8 | |||
9 | // ValueSet is to cty.Set what []cty.Value is to cty.List and | ||
10 | // map[string]cty.Value is to cty.Map. It's provided to allow callers a | ||
11 | // convenient interface for manipulating sets before wrapping them in cty.Set | ||
12 | // values using cty.SetValFromValueSet. | ||
13 | // | ||
14 | // Unlike value slices and value maps, ValueSet instances have a single | ||
15 | // homogenous element type because that is a requirement of the underlying | ||
16 | // set implementation, which uses the element type to select a suitable | ||
17 | // hashing function. | ||
18 | // | ||
19 | // Set mutations are not concurrency-safe. | ||
20 | type ValueSet struct { | ||
21 | // ValueSet is just a thin wrapper around a set.Set with our value-oriented | ||
22 | // "rules" applied. We do this so that the caller can work in terms of | ||
23 | // cty.Value objects even though the set internals use the raw values. | ||
24 | s set.Set | ||
25 | } | ||
26 | |||
27 | // NewValueSet creates and returns a new ValueSet with the given element type. | ||
28 | func NewValueSet(ety Type) ValueSet { | ||
29 | return newValueSet(set.NewSet(setRules{Type: ety})) | ||
30 | } | ||
31 | |||
32 | func newValueSet(s set.Set) ValueSet { | ||
33 | return ValueSet{ | ||
34 | s: s, | ||
35 | } | ||
36 | } | ||
37 | |||
38 | // ElementType returns the element type for the receiving ValueSet. | ||
39 | func (s ValueSet) ElementType() Type { | ||
40 | return s.s.Rules().(setRules).Type | ||
41 | } | ||
42 | |||
43 | // Add inserts the given value into the receiving set. | ||
44 | func (s ValueSet) Add(v Value) { | ||
45 | s.requireElementType(v) | ||
46 | s.s.Add(v.v) | ||
47 | } | ||
48 | |||
49 | // Remove deletes the given value from the receiving set, if indeed it was | ||
50 | // there in the first place. If the value is not present, this is a no-op. | ||
51 | func (s ValueSet) Remove(v Value) { | ||
52 | s.requireElementType(v) | ||
53 | s.s.Remove(v.v) | ||
54 | } | ||
55 | |||
56 | // Has returns true if the given value is in the receiving set, or false if | ||
57 | // it is not. | ||
58 | func (s ValueSet) Has(v Value) bool { | ||
59 | s.requireElementType(v) | ||
60 | return s.s.Has(v.v) | ||
61 | } | ||
62 | |||
63 | // Copy performs a shallow copy of the receiving set, returning a new set | ||
64 | // with the same rules and elements. | ||
65 | func (s ValueSet) Copy() ValueSet { | ||
66 | return newValueSet(s.s.Copy()) | ||
67 | } | ||
68 | |||
69 | // Length returns the number of values in the set. | ||
70 | func (s ValueSet) Length() int { | ||
71 | return s.s.Length() | ||
72 | } | ||
73 | |||
74 | // Values returns a slice of all of the values in the set in no particular | ||
75 | // order. | ||
76 | func (s ValueSet) Values() []Value { | ||
77 | l := s.s.Length() | ||
78 | if l == 0 { | ||
79 | return nil | ||
80 | } | ||
81 | ret := make([]Value, 0, l) | ||
82 | ety := s.ElementType() | ||
83 | for it := s.s.Iterator(); it.Next(); { | ||
84 | ret = append(ret, Value{ | ||
85 | ty: ety, | ||
86 | v: it.Value(), | ||
87 | }) | ||
88 | } | ||
89 | return ret | ||
90 | } | ||
91 | |||
92 | // Union returns a new set that contains all of the members of both the | ||
93 | // receiving set and the given set. Both sets must have the same element type, | ||
94 | // or else this function will panic. | ||
95 | func (s ValueSet) Union(other ValueSet) ValueSet { | ||
96 | return newValueSet(s.s.Union(other.s)) | ||
97 | } | ||
98 | |||
99 | // Intersection returns a new set that contains the values that both the | ||
100 | // receiver and given sets have in common. Both sets must have the same element | ||
101 | // type, or else this function will panic. | ||
102 | func (s ValueSet) Intersection(other ValueSet) ValueSet { | ||
103 | return newValueSet(s.s.Intersection(other.s)) | ||
104 | } | ||
105 | |||
106 | // Subtract returns a new set that contains all of the values from the receiver | ||
107 | // that are not also in the given set. Both sets must have the same element | ||
108 | // type, or else this function will panic. | ||
109 | func (s ValueSet) Subtract(other ValueSet) ValueSet { | ||
110 | return newValueSet(s.s.Subtract(other.s)) | ||
111 | } | ||
112 | |||
113 | // SymmetricDifference returns a new set that contains all of the values from | ||
114 | // both the receiver and given sets, except those that both sets have in | ||
115 | // common. Both sets must have the same element type, or else this function | ||
116 | // will panic. | ||
117 | func (s ValueSet) SymmetricDifference(other ValueSet) ValueSet { | ||
118 | return newValueSet(s.s.SymmetricDifference(other.s)) | ||
119 | } | ||
120 | |||
121 | // requireElementType panics if the given value is not of the set's element type. | ||
122 | func (s ValueSet) requireElementType(v Value) { | ||
123 | if !v.Type().Equals(s.ElementType()) { | ||
124 | panic(fmt.Errorf("attempt to use %#v value with set of %#v", v.Type(), s.ElementType())) | ||
125 | } | ||
126 | } | ||
diff --git a/vendor/github.com/zclconf/go-cty/cty/set_internals.go b/vendor/github.com/zclconf/go-cty/cty/set_internals.go new file mode 100644 index 0000000..ce738db --- /dev/null +++ b/vendor/github.com/zclconf/go-cty/cty/set_internals.go | |||
@@ -0,0 +1,146 @@ | |||
1 | package cty | ||
2 | |||
3 | import ( | ||
4 | "bytes" | ||
5 | "fmt" | ||
6 | "hash/crc32" | ||
7 | "math/big" | ||
8 | "sort" | ||
9 | ) | ||
10 | |||
11 | // setRules provides a Rules implementation for the ./set package that | ||
12 | // respects the equality rules for cty values of the given type. | ||
13 | // | ||
14 | // This implementation expects that values added to the set will be | ||
15 | // valid internal values for the given Type, which is to say that wrapping | ||
16 | // the given value in a Value struct along with the ruleset's type should | ||
17 | // produce a valid, working Value. | ||
18 | type setRules struct { | ||
19 | Type Type | ||
20 | } | ||
21 | |||
22 | func (r setRules) Hash(v interface{}) int { | ||
23 | hashBytes := makeSetHashBytes(Value{ | ||
24 | ty: r.Type, | ||
25 | v: v, | ||
26 | }) | ||
27 | return int(crc32.ChecksumIEEE(hashBytes)) | ||
28 | } | ||
29 | |||
30 | func (r setRules) Equivalent(v1 interface{}, v2 interface{}) bool { | ||
31 | v1v := Value{ | ||
32 | ty: r.Type, | ||
33 | v: v1, | ||
34 | } | ||
35 | v2v := Value{ | ||
36 | ty: r.Type, | ||
37 | v: v2, | ||
38 | } | ||
39 | |||
40 | eqv := v1v.Equals(v2v) | ||
41 | |||
42 | // By comparing the result to true we ensure that an Unknown result, | ||
43 | // which will result if either value is unknown, will be considered | ||
44 | // as non-equivalent. Two unknown values are not equivalent for the | ||
45 | // sake of set membership. | ||
46 | return eqv.v == true | ||
47 | } | ||
48 | |||
49 | func makeSetHashBytes(val Value) []byte { | ||
50 | var buf bytes.Buffer | ||
51 | appendSetHashBytes(val, &buf) | ||
52 | return buf.Bytes() | ||
53 | } | ||
54 | |||
55 | func appendSetHashBytes(val Value, buf *bytes.Buffer) { | ||
56 | // Exactly what bytes we generate here don't matter as long as the following | ||
57 | // constraints hold: | ||
58 | // - Unknown and null values all generate distinct strings from | ||
59 | // each other and from any normal value of the given type. | ||
60 | // - The delimiter used to separate items in a compound structure can | ||
61 | // never appear literally in any of its elements. | ||
62 | // Since we don't support hetrogenous lists we don't need to worry about | ||
63 | // collisions between values of different types, apart from | ||
64 | // PseudoTypeDynamic. | ||
65 | // If in practice we *do* get a collision then it's not a big deal because | ||
66 | // the Equivalent function will still distinguish values, but set | ||
67 | // performance will be best if we are able to produce a distinct string | ||
68 | // for each distinct value, unknown values notwithstanding. | ||
69 | if !val.IsKnown() { | ||
70 | buf.WriteRune('?') | ||
71 | return | ||
72 | } | ||
73 | if val.IsNull() { | ||
74 | buf.WriteRune('~') | ||
75 | return | ||
76 | } | ||
77 | |||
78 | switch val.ty { | ||
79 | case Number: | ||
80 | buf.WriteString(val.v.(*big.Float).String()) | ||
81 | return | ||
82 | case Bool: | ||
83 | if val.v.(bool) { | ||
84 | buf.WriteRune('T') | ||
85 | } else { | ||
86 | buf.WriteRune('F') | ||
87 | } | ||
88 | return | ||
89 | case String: | ||
90 | buf.WriteString(fmt.Sprintf("%q", val.v.(string))) | ||
91 | return | ||
92 | } | ||
93 | |||
94 | if val.ty.IsMapType() { | ||
95 | buf.WriteRune('{') | ||
96 | val.ForEachElement(func(keyVal, elementVal Value) bool { | ||
97 | appendSetHashBytes(keyVal, buf) | ||
98 | buf.WriteRune(':') | ||
99 | appendSetHashBytes(elementVal, buf) | ||
100 | buf.WriteRune(';') | ||
101 | return false | ||
102 | }) | ||
103 | buf.WriteRune('}') | ||
104 | return | ||
105 | } | ||
106 | |||
107 | if val.ty.IsListType() || val.ty.IsSetType() { | ||
108 | buf.WriteRune('[') | ||
109 | val.ForEachElement(func(keyVal, elementVal Value) bool { | ||
110 | appendSetHashBytes(elementVal, buf) | ||
111 | buf.WriteRune(';') | ||
112 | return false | ||
113 | }) | ||
114 | buf.WriteRune(']') | ||
115 | return | ||
116 | } | ||
117 | |||
118 | if val.ty.IsObjectType() { | ||
119 | buf.WriteRune('<') | ||
120 | attrNames := make([]string, 0, len(val.ty.AttributeTypes())) | ||
121 | for attrName := range val.ty.AttributeTypes() { | ||
122 | attrNames = append(attrNames, attrName) | ||
123 | } | ||
124 | sort.Strings(attrNames) | ||
125 | for _, attrName := range attrNames { | ||
126 | appendSetHashBytes(val.GetAttr(attrName), buf) | ||
127 | buf.WriteRune(';') | ||
128 | } | ||
129 | buf.WriteRune('>') | ||
130 | return | ||
131 | } | ||
132 | |||
133 | if val.ty.IsTupleType() { | ||
134 | buf.WriteRune('<') | ||
135 | val.ForEachElement(func(keyVal, elementVal Value) bool { | ||
136 | appendSetHashBytes(elementVal, buf) | ||
137 | buf.WriteRune(';') | ||
138 | return false | ||
139 | }) | ||
140 | buf.WriteRune('>') | ||
141 | return | ||
142 | } | ||
143 | |||
144 | // should never get down here | ||
145 | panic("unsupported type in set hash") | ||
146 | } | ||
diff --git a/vendor/github.com/zclconf/go-cty/cty/set_type.go b/vendor/github.com/zclconf/go-cty/cty/set_type.go new file mode 100644 index 0000000..952a2d2 --- /dev/null +++ b/vendor/github.com/zclconf/go-cty/cty/set_type.go | |||
@@ -0,0 +1,66 @@ | |||
1 | package cty | ||
2 | |||
3 | import ( | ||
4 | "fmt" | ||
5 | ) | ||
6 | |||
7 | type typeSet struct { | ||
8 | typeImplSigil | ||
9 | ElementTypeT Type | ||
10 | } | ||
11 | |||
12 | // Set creates a set type with the given element Type. | ||
13 | // | ||
14 | // Set types are CollectionType implementations. | ||
15 | func Set(elem Type) Type { | ||
16 | return Type{ | ||
17 | typeSet{ | ||
18 | ElementTypeT: elem, | ||
19 | }, | ||
20 | } | ||
21 | } | ||
22 | |||
23 | // Equals returns true if the other Type is a set whose element type is | ||
24 | // equal to that of the receiver. | ||
25 | func (t typeSet) Equals(other Type) bool { | ||
26 | ot, isSet := other.typeImpl.(typeSet) | ||
27 | if !isSet { | ||
28 | return false | ||
29 | } | ||
30 | |||
31 | return t.ElementTypeT.Equals(ot.ElementTypeT) | ||
32 | } | ||
33 | |||
34 | func (t typeSet) FriendlyName() string { | ||
35 | return "set of " + t.ElementTypeT.FriendlyName() | ||
36 | } | ||
37 | |||
38 | func (t typeSet) ElementType() Type { | ||
39 | return t.ElementTypeT | ||
40 | } | ||
41 | |||
42 | func (t typeSet) GoString() string { | ||
43 | return fmt.Sprintf("cty.Set(%#v)", t.ElementTypeT) | ||
44 | } | ||
45 | |||
46 | // IsSetType returns true if the given type is a list type, regardless of its | ||
47 | // element type. | ||
48 | func (t Type) IsSetType() bool { | ||
49 | _, ok := t.typeImpl.(typeSet) | ||
50 | return ok | ||
51 | } | ||
52 | |||
53 | // SetElementType is a convenience method that checks if the given type is | ||
54 | // a set type, returning a pointer to its element type if so and nil | ||
55 | // otherwise. This is intended to allow convenient conditional branches, | ||
56 | // like so: | ||
57 | // | ||
58 | // if et := t.SetElementType(); et != nil { | ||
59 | // // Do something with *et | ||
60 | // } | ||
61 | func (t Type) SetElementType() *Type { | ||
62 | if lt, ok := t.typeImpl.(typeSet); ok { | ||
63 | return <.ElementTypeT | ||
64 | } | ||
65 | return nil | ||
66 | } | ||
diff --git a/vendor/github.com/zclconf/go-cty/cty/tuple_type.go b/vendor/github.com/zclconf/go-cty/cty/tuple_type.go new file mode 100644 index 0000000..b98349e --- /dev/null +++ b/vendor/github.com/zclconf/go-cty/cty/tuple_type.go | |||
@@ -0,0 +1,121 @@ | |||
1 | package cty | ||
2 | |||
3 | import ( | ||
4 | "fmt" | ||
5 | ) | ||
6 | |||
7 | type typeTuple struct { | ||
8 | typeImplSigil | ||
9 | ElemTypes []Type | ||
10 | } | ||
11 | |||
12 | // Tuple creates a tuple type with the given element types. | ||
13 | // | ||
14 | // After a slice is passed to this function the caller must no longer access | ||
15 | // the underlying array, since ownership is transferred to this library. | ||
16 | func Tuple(elemTypes []Type) Type { | ||
17 | return Type{ | ||
18 | typeTuple{ | ||
19 | ElemTypes: elemTypes, | ||
20 | }, | ||
21 | } | ||
22 | } | ||
23 | |||
24 | func (t typeTuple) Equals(other Type) bool { | ||
25 | if ot, ok := other.typeImpl.(typeTuple); ok { | ||
26 | if len(t.ElemTypes) != len(ot.ElemTypes) { | ||
27 | // Fast path: if we don't have the same number of elements | ||
28 | // then we can't possibly be equal. | ||
29 | return false | ||
30 | } | ||
31 | |||
32 | for i, ty := range t.ElemTypes { | ||
33 | oty := ot.ElemTypes[i] | ||
34 | if !ok { | ||
35 | return false | ||
36 | } | ||
37 | if !oty.Equals(ty) { | ||
38 | return false | ||
39 | } | ||
40 | } | ||
41 | |||
42 | return true | ||
43 | } | ||
44 | return false | ||
45 | } | ||
46 | |||
47 | func (t typeTuple) FriendlyName() string { | ||
48 | // There isn't really a friendly way to write a tuple type due to its | ||
49 | // complexity, so we'll just do something English-ish. Callers will | ||
50 | // probably want to make some extra effort to avoid ever printing out | ||
51 | // a tuple type FriendlyName in its entirety. For example, could | ||
52 | // produce an error message by diffing two object types and saying | ||
53 | // something like "Expected attribute foo to be string, but got number". | ||
54 | // TODO: Finish this | ||
55 | return "tuple" | ||
56 | } | ||
57 | |||
58 | func (t typeTuple) GoString() string { | ||
59 | if len(t.ElemTypes) == 0 { | ||
60 | return "cty.EmptyTuple" | ||
61 | } | ||
62 | return fmt.Sprintf("cty.Tuple(%#v)", t.ElemTypes) | ||
63 | } | ||
64 | |||
65 | // EmptyTuple is a shorthand for Tuple([]Type{}), to more easily talk about | ||
66 | // the empty tuple type. | ||
67 | var EmptyTuple Type | ||
68 | |||
69 | // EmptyTupleVal is the only possible non-null, non-unknown value of type | ||
70 | // EmptyTuple. | ||
71 | var EmptyTupleVal Value | ||
72 | |||
73 | func init() { | ||
74 | EmptyTuple = Tuple([]Type{}) | ||
75 | EmptyTupleVal = Value{ | ||
76 | ty: EmptyTuple, | ||
77 | v: []interface{}{}, | ||
78 | } | ||
79 | } | ||
80 | |||
81 | // IsTupleType returns true if the given type is an object type, regardless | ||
82 | // of its element type. | ||
83 | func (t Type) IsTupleType() bool { | ||
84 | _, ok := t.typeImpl.(typeTuple) | ||
85 | return ok | ||
86 | } | ||
87 | |||
88 | // Length returns the number of elements of the receiving tuple type. | ||
89 | // Will panic if the reciever isn't a tuple type; use IsTupleType to determine | ||
90 | // whether this operation will succeed. | ||
91 | func (t Type) Length() int { | ||
92 | if ot, ok := t.typeImpl.(typeTuple); ok { | ||
93 | return len(ot.ElemTypes) | ||
94 | } | ||
95 | panic("Length on non-tuple Type") | ||
96 | } | ||
97 | |||
98 | // TupleElementType returns the type of the element with the given index. Will | ||
99 | // panic if the receiver is not a tuple type (use IsTupleType to confirm) | ||
100 | // or if the index is out of range (use Length to confirm). | ||
101 | func (t Type) TupleElementType(idx int) Type { | ||
102 | if ot, ok := t.typeImpl.(typeTuple); ok { | ||
103 | return ot.ElemTypes[idx] | ||
104 | } | ||
105 | panic("TupleElementType on non-tuple Type") | ||
106 | } | ||
107 | |||
108 | // TupleElementTypes returns a slice of the recieving tuple type's element | ||
109 | // types. Will panic if the receiver is not a tuple type (use IsTupleType | ||
110 | // to confirm). | ||
111 | // | ||
112 | // The returned slice is part of the internal state of the type, and is provided | ||
113 | // for read access only. It is forbidden for any caller to modify the | ||
114 | // underlying array. For many purposes the element-related methods of Value | ||
115 | // are more appropriate and more convenient to use. | ||
116 | func (t Type) TupleElementTypes() []Type { | ||
117 | if ot, ok := t.typeImpl.(typeTuple); ok { | ||
118 | return ot.ElemTypes | ||
119 | } | ||
120 | panic("TupleElementTypes on non-tuple Type") | ||
121 | } | ||
diff --git a/vendor/github.com/zclconf/go-cty/cty/type.go b/vendor/github.com/zclconf/go-cty/cty/type.go new file mode 100644 index 0000000..ae5f1c8 --- /dev/null +++ b/vendor/github.com/zclconf/go-cty/cty/type.go | |||
@@ -0,0 +1,95 @@ | |||
1 | package cty | ||
2 | |||
3 | // Type represents value types within the type system. | ||
4 | // | ||
5 | // This is a closed interface type, meaning that only the concrete | ||
6 | // implementations provided within this package are considered valid. | ||
7 | type Type struct { | ||
8 | typeImpl | ||
9 | } | ||
10 | |||
11 | type typeImpl interface { | ||
12 | // isTypeImpl is a do-nothing method that exists only to express | ||
13 | // that a type is an implementation of typeImpl. | ||
14 | isTypeImpl() typeImplSigil | ||
15 | |||
16 | // Equals returns true if the other given Type exactly equals the | ||
17 | // receiver Type. | ||
18 | Equals(other Type) bool | ||
19 | |||
20 | // FriendlyName returns a human-friendly *English* name for the given | ||
21 | // type. | ||
22 | FriendlyName() string | ||
23 | |||
24 | // GoString implements the GoStringer interface from package fmt. | ||
25 | GoString() string | ||
26 | } | ||
27 | |||
28 | // Base implementation of Type to embed into concrete implementations | ||
29 | // to signal that they are implementations of Type. | ||
30 | type typeImplSigil struct{} | ||
31 | |||
32 | func (t typeImplSigil) isTypeImpl() typeImplSigil { | ||
33 | return typeImplSigil{} | ||
34 | } | ||
35 | |||
36 | // Equals returns true if the other given Type exactly equals the receiver | ||
37 | // type. | ||
38 | func (t Type) Equals(other Type) bool { | ||
39 | return t.typeImpl.Equals(other) | ||
40 | } | ||
41 | |||
42 | // FriendlyName returns a human-friendly *English* name for the given type. | ||
43 | func (t Type) FriendlyName() string { | ||
44 | return t.typeImpl.FriendlyName() | ||
45 | } | ||
46 | |||
47 | // GoString returns a string approximating how the receiver type would be | ||
48 | // expressed in Go source code. | ||
49 | func (t Type) GoString() string { | ||
50 | if t.typeImpl == nil { | ||
51 | return "cty.NilType" | ||
52 | } | ||
53 | |||
54 | return t.typeImpl.GoString() | ||
55 | } | ||
56 | |||
57 | // NilType is an invalid type used when a function is returning an error | ||
58 | // and has no useful type to return. It should not be used and any methods | ||
59 | // called on it will panic. | ||
60 | var NilType = Type{} | ||
61 | |||
62 | // HasDynamicTypes returns true either if the receiver is itself | ||
63 | // DynamicPseudoType or if it is a compound type whose descendent elements | ||
64 | // are DynamicPseudoType. | ||
65 | func (t Type) HasDynamicTypes() bool { | ||
66 | switch { | ||
67 | case t == DynamicPseudoType: | ||
68 | return true | ||
69 | case t.IsPrimitiveType(): | ||
70 | return false | ||
71 | case t.IsCollectionType(): | ||
72 | return false | ||
73 | case t.IsObjectType(): | ||
74 | attrTypes := t.AttributeTypes() | ||
75 | for _, at := range attrTypes { | ||
76 | if at.HasDynamicTypes() { | ||
77 | return true | ||
78 | } | ||
79 | } | ||
80 | return false | ||
81 | case t.IsTupleType(): | ||
82 | elemTypes := t.TupleElementTypes() | ||
83 | for _, et := range elemTypes { | ||
84 | if et.HasDynamicTypes() { | ||
85 | return true | ||
86 | } | ||
87 | } | ||
88 | return false | ||
89 | case t.IsCapsuleType(): | ||
90 | return false | ||
91 | default: | ||
92 | // Should never happen, since above should be exhaustive | ||
93 | panic("HasDynamicTypes does not support the given type") | ||
94 | } | ||
95 | } | ||
diff --git a/vendor/github.com/zclconf/go-cty/cty/type_conform.go b/vendor/github.com/zclconf/go-cty/cty/type_conform.go new file mode 100644 index 0000000..b417dc7 --- /dev/null +++ b/vendor/github.com/zclconf/go-cty/cty/type_conform.go | |||
@@ -0,0 +1,142 @@ | |||
1 | package cty | ||
2 | |||
3 | // TestConformance recursively walks the receiver and the given other type and | ||
4 | // returns nil if the receiver *conforms* to the given type. | ||
5 | // | ||
6 | // Type conformance is similar to type equality but has one crucial difference: | ||
7 | // PseudoTypeDynamic can be used within the given type to represent that | ||
8 | // *any* type is allowed. | ||
9 | // | ||
10 | // If any non-conformities are found, the returned slice will be non-nil and | ||
11 | // contain at least one error value. It will be nil if the type is entirely | ||
12 | // conformant. | ||
13 | // | ||
14 | // Note that the special behavior of PseudoTypeDynamic is the *only* exception | ||
15 | // to normal type equality. Calling applications may wish to apply their own | ||
16 | // automatic conversion logic to the given data structure to create a more | ||
17 | // liberal notion of conformance to a type. | ||
18 | // | ||
19 | // Returned errors are usually (but not always) PathError instances that | ||
20 | // indicate where in the structure the error was found. If a returned error | ||
21 | // is of that type then the error message is written for (English-speaking) | ||
22 | // end-users working within the cty type system, not mentioning any Go-oriented | ||
23 | // implementation details. | ||
24 | func (t Type) TestConformance(other Type) []error { | ||
25 | path := make(Path, 0) | ||
26 | var errs []error | ||
27 | testConformance(t, other, path, &errs) | ||
28 | return errs | ||
29 | } | ||
30 | |||
31 | func testConformance(given Type, want Type, path Path, errs *[]error) { | ||
32 | if want.Equals(DynamicPseudoType) { | ||
33 | // anything goes! | ||
34 | return | ||
35 | } | ||
36 | |||
37 | if given.Equals(want) { | ||
38 | // Any equal types are always conformant | ||
39 | return | ||
40 | } | ||
41 | |||
42 | // The remainder of this function is concerned with detecting | ||
43 | // and reporting the specific non-conformance, since we wouldn't | ||
44 | // have got here if the types were not divergent. | ||
45 | // We treat compound structures as special so that we can report | ||
46 | // specifically what is non-conforming, rather than simply returning | ||
47 | // the entire type names and letting the user puzzle it out. | ||
48 | |||
49 | if given.IsObjectType() && want.IsObjectType() { | ||
50 | givenAttrs := given.AttributeTypes() | ||
51 | wantAttrs := want.AttributeTypes() | ||
52 | |||
53 | if len(givenAttrs) != len(wantAttrs) { | ||
54 | // Something is missing from one of them. | ||
55 | for k := range givenAttrs { | ||
56 | if _, exists := wantAttrs[k]; !exists { | ||
57 | *errs = append( | ||
58 | *errs, | ||
59 | errorf(path, "unsupported attribute %q", k), | ||
60 | ) | ||
61 | } | ||
62 | } | ||
63 | for k := range wantAttrs { | ||
64 | if _, exists := givenAttrs[k]; !exists { | ||
65 | *errs = append( | ||
66 | *errs, | ||
67 | errorf(path, "missing required attribute %q", k), | ||
68 | ) | ||
69 | } | ||
70 | } | ||
71 | } | ||
72 | |||
73 | path = append(path, nil) | ||
74 | pathIdx := len(path) - 1 | ||
75 | |||
76 | for k, wantAttrType := range wantAttrs { | ||
77 | if givenAttrType, exists := givenAttrs[k]; exists { | ||
78 | path[pathIdx] = GetAttrStep{Name: k} | ||
79 | testConformance(givenAttrType, wantAttrType, path, errs) | ||
80 | } | ||
81 | } | ||
82 | |||
83 | path = path[0:pathIdx] | ||
84 | |||
85 | return | ||
86 | } | ||
87 | |||
88 | if given.IsTupleType() && want.IsTupleType() { | ||
89 | givenElems := given.TupleElementTypes() | ||
90 | wantElems := want.TupleElementTypes() | ||
91 | |||
92 | if len(givenElems) != len(wantElems) { | ||
93 | *errs = append( | ||
94 | *errs, | ||
95 | errorf(path, "%d elements are required, but got %d", len(wantElems), len(givenElems)), | ||
96 | ) | ||
97 | return | ||
98 | } | ||
99 | |||
100 | path = append(path, nil) | ||
101 | pathIdx := len(path) - 1 | ||
102 | |||
103 | for i, wantElemType := range wantElems { | ||
104 | givenElemType := givenElems[i] | ||
105 | path[pathIdx] = IndexStep{Key: NumberIntVal(int64(i))} | ||
106 | testConformance(givenElemType, wantElemType, path, errs) | ||
107 | } | ||
108 | |||
109 | path = path[0:pathIdx] | ||
110 | |||
111 | return | ||
112 | } | ||
113 | |||
114 | if given.IsListType() && want.IsListType() { | ||
115 | path = append(path, IndexStep{Key: UnknownVal(Number)}) | ||
116 | pathIdx := len(path) - 1 | ||
117 | testConformance(given.ElementType(), want.ElementType(), path, errs) | ||
118 | path = path[0:pathIdx] | ||
119 | return | ||
120 | } | ||
121 | |||
122 | if given.IsMapType() && want.IsMapType() { | ||
123 | path = append(path, IndexStep{Key: UnknownVal(String)}) | ||
124 | pathIdx := len(path) - 1 | ||
125 | testConformance(given.ElementType(), want.ElementType(), path, errs) | ||
126 | path = path[0:pathIdx] | ||
127 | return | ||
128 | } | ||
129 | |||
130 | if given.IsSetType() && want.IsSetType() { | ||
131 | path = append(path, IndexStep{Key: UnknownVal(given.ElementType())}) | ||
132 | pathIdx := len(path) - 1 | ||
133 | testConformance(given.ElementType(), want.ElementType(), path, errs) | ||
134 | path = path[0:pathIdx] | ||
135 | return | ||
136 | } | ||
137 | |||
138 | *errs = append( | ||
139 | *errs, | ||
140 | errorf(path, "%s required, but received %s", want.FriendlyName(), given.FriendlyName()), | ||
141 | ) | ||
142 | } | ||
diff --git a/vendor/github.com/zclconf/go-cty/cty/types_to_register.go b/vendor/github.com/zclconf/go-cty/cty/types_to_register.go new file mode 100644 index 0000000..e1e220a --- /dev/null +++ b/vendor/github.com/zclconf/go-cty/cty/types_to_register.go | |||
@@ -0,0 +1,57 @@ | |||
1 | package cty | ||
2 | |||
3 | import ( | ||
4 | "encoding/gob" | ||
5 | "fmt" | ||
6 | "math/big" | ||
7 | "strings" | ||
8 | |||
9 | "github.com/zclconf/go-cty/cty/set" | ||
10 | ) | ||
11 | |||
12 | // InternalTypesToRegister is a slice of values that covers all of the | ||
13 | // internal types used in the representation of cty.Type and cty.Value | ||
14 | // across all cty Types. | ||
15 | // | ||
16 | // This is intended to be used to register these types with encoding | ||
17 | // packages that require registration of types used in interfaces, such as | ||
18 | // encoding/gob, thus allowing cty types and values to be included in streams | ||
19 | // created from those packages. However, registering with gob is not necessary | ||
20 | // since that is done automatically as a side-effect of importing this package. | ||
21 | // | ||
22 | // Callers should not do anything with the values here except pass them on | ||
23 | // verbatim to a registration function. | ||
24 | // | ||
25 | // If the calling application uses Capsule types that wrap local structs either | ||
26 | // directly or indirectly, these structs may also need to be registered in | ||
27 | // order to support encoding and decoding of values of these types. That is the | ||
28 | // responsibility of the calling application. | ||
29 | var InternalTypesToRegister []interface{} | ||
30 | |||
31 | func init() { | ||
32 | InternalTypesToRegister = []interface{}{ | ||
33 | primitiveType{}, | ||
34 | typeList{}, | ||
35 | typeMap{}, | ||
36 | typeObject{}, | ||
37 | typeSet{}, | ||
38 | setRules{}, | ||
39 | set.Set{}, | ||
40 | typeTuple{}, | ||
41 | big.Float{}, | ||
42 | capsuleType{}, | ||
43 | []interface{}(nil), | ||
44 | map[string]interface{}(nil), | ||
45 | } | ||
46 | |||
47 | // Register these with gob here, rather than in gob.go, to ensure | ||
48 | // that this will always happen after we build the above. | ||
49 | for _, tv := range InternalTypesToRegister { | ||
50 | typeName := fmt.Sprintf("%T", tv) | ||
51 | if strings.HasPrefix(typeName, "cty.") { | ||
52 | gob.RegisterName(fmt.Sprintf("github.com/zclconf/go-cty/%s", typeName), tv) | ||
53 | } else { | ||
54 | gob.Register(tv) | ||
55 | } | ||
56 | } | ||
57 | } | ||
diff --git a/vendor/github.com/zclconf/go-cty/cty/unknown.go b/vendor/github.com/zclconf/go-cty/cty/unknown.go new file mode 100644 index 0000000..9f6fce9 --- /dev/null +++ b/vendor/github.com/zclconf/go-cty/cty/unknown.go | |||
@@ -0,0 +1,79 @@ | |||
1 | package cty | ||
2 | |||
3 | // unknownType is the placeholder type used for the sigil value representing | ||
4 | // "Unknown", to make it unambigiously distinct from any other possible value. | ||
5 | type unknownType struct { | ||
6 | } | ||
7 | |||
8 | // Unknown is a special value that can be | ||
9 | var unknown interface{} = &unknownType{} | ||
10 | |||
11 | // UnknownVal returns an Value that represents an unknown value of the given | ||
12 | // type. Unknown values can be used to represent a value that is | ||
13 | // not yet known. Its meaning is undefined in cty, but it could be used by | ||
14 | // an calling application to allow partial evaluation. | ||
15 | // | ||
16 | // Unknown values of any type can be created of any type. All operations on | ||
17 | // Unknown values themselves return Unknown. | ||
18 | func UnknownVal(t Type) Value { | ||
19 | return Value{ | ||
20 | ty: t, | ||
21 | v: unknown, | ||
22 | } | ||
23 | } | ||
24 | |||
25 | func (t unknownType) GoString() string { | ||
26 | // This is the stringification of our internal unknown marker. The | ||
27 | // stringification of the public representation of unknowns is in | ||
28 | // Value.GoString. | ||
29 | return "cty.unknown" | ||
30 | } | ||
31 | |||
32 | type pseudoTypeDynamic struct { | ||
33 | typeImplSigil | ||
34 | } | ||
35 | |||
36 | // DynamicPseudoType represents the dynamic pseudo-type. | ||
37 | // | ||
38 | // This type can represent situations where a type is not yet known. Its | ||
39 | // meaning is undefined in cty, but it could be used by a calling | ||
40 | // application to allow expression type checking with some types not yet known. | ||
41 | // For example, the application might optimistically permit any operation on | ||
42 | // values of this type in type checking, allowing a partial type-check result, | ||
43 | // and then repeat the check when more information is known to get the | ||
44 | // final, concrete type. | ||
45 | // | ||
46 | // It is a pseudo-type because it is used only as a sigil to the calling | ||
47 | // application. "Unknown" is the only valid value of this pseudo-type, so | ||
48 | // operations on values of this type will always short-circuit as per | ||
49 | // the rules for that special value. | ||
50 | var DynamicPseudoType Type | ||
51 | |||
52 | func (t pseudoTypeDynamic) Equals(other Type) bool { | ||
53 | _, ok := other.typeImpl.(pseudoTypeDynamic) | ||
54 | return ok | ||
55 | } | ||
56 | |||
57 | func (t pseudoTypeDynamic) FriendlyName() string { | ||
58 | return "dynamic" | ||
59 | } | ||
60 | |||
61 | func (t pseudoTypeDynamic) GoString() string { | ||
62 | return "cty.DynamicPseudoType" | ||
63 | } | ||
64 | |||
65 | // DynamicVal is the only valid value of the pseudo-type dynamic. | ||
66 | // This value can be used as a placeholder where a value or expression's | ||
67 | // type and value are both unknown, thus allowing partial evaluation. See | ||
68 | // the docs for DynamicPseudoType for more information. | ||
69 | var DynamicVal Value | ||
70 | |||
71 | func init() { | ||
72 | DynamicPseudoType = Type{ | ||
73 | pseudoTypeDynamic{}, | ||
74 | } | ||
75 | DynamicVal = Value{ | ||
76 | ty: DynamicPseudoType, | ||
77 | v: unknown, | ||
78 | } | ||
79 | } | ||
diff --git a/vendor/github.com/zclconf/go-cty/cty/value.go b/vendor/github.com/zclconf/go-cty/cty/value.go new file mode 100644 index 0000000..80cb8f7 --- /dev/null +++ b/vendor/github.com/zclconf/go-cty/cty/value.go | |||
@@ -0,0 +1,98 @@ | |||
1 | package cty | ||
2 | |||
3 | // Value represents a value of a particular type, and is the interface by | ||
4 | // which operations are executed on typed values. | ||
5 | // | ||
6 | // Value has two different classes of method. Operation methods stay entirely | ||
7 | // within the type system (methods accept and return Value instances) and | ||
8 | // are intended for use in implementing a language in terms of cty, while | ||
9 | // integration methods either enter or leave the type system, working with | ||
10 | // native Go values. Operation methods are guaranteed to support all of the | ||
11 | // expected short-circuit behavior for unknown and dynamic values, while | ||
12 | // integration methods may not. | ||
13 | // | ||
14 | // The philosophy for the operations API is that it's the caller's | ||
15 | // responsibility to ensure that the given types and values satisfy the | ||
16 | // specified invariants during a separate type check, so that the caller is | ||
17 | // able to return errors to its user from the application's own perspective. | ||
18 | // | ||
19 | // Consequently the design of these methods assumes such checks have already | ||
20 | // been done and panics if any invariants turn out not to be satisfied. These | ||
21 | // panic errors are not intended to be handled, but rather indicate a bug in | ||
22 | // the calling application that should be fixed with more checks prior to | ||
23 | // executing operations. | ||
24 | // | ||
25 | // A related consequence of this philosophy is that no automatic type | ||
26 | // conversions are done. If a method specifies that its argument must be | ||
27 | // number then it's the caller's responsibility to do that conversion before | ||
28 | // the call, thus allowing the application to have more constrained conversion | ||
29 | // rules than are offered by the built-in converter where necessary. | ||
30 | type Value struct { | ||
31 | ty Type | ||
32 | v interface{} | ||
33 | } | ||
34 | |||
35 | // Type returns the type of the value. | ||
36 | func (val Value) Type() Type { | ||
37 | return val.ty | ||
38 | } | ||
39 | |||
40 | // IsKnown returns true if the value is known. That is, if it is not | ||
41 | // the result of the unknown value constructor Unknown(...), and is not | ||
42 | // the result of an operation on another unknown value. | ||
43 | // | ||
44 | // Unknown values are only produced either directly or as a result of | ||
45 | // operating on other unknown values, and so an application that never | ||
46 | // introduces Unknown values can be guaranteed to never receive any either. | ||
47 | func (val Value) IsKnown() bool { | ||
48 | return val.v != unknown | ||
49 | } | ||
50 | |||
51 | // IsNull returns true if the value is null. Values of any type can be | ||
52 | // null, but any operations on a null value will panic. No operation ever | ||
53 | // produces null, so an application that never introduces Null values can | ||
54 | // be guaranteed to never receive any either. | ||
55 | func (val Value) IsNull() bool { | ||
56 | return val.v == nil | ||
57 | } | ||
58 | |||
59 | // NilVal is an invalid Value that can be used as a placeholder when returning | ||
60 | // with an error from a function that returns (Value, error). | ||
61 | // | ||
62 | // NilVal is *not* a valid error and so no operations may be performed on it. | ||
63 | // Any attempt to use it will result in a panic. | ||
64 | // | ||
65 | // This should not be confused with the idea of a Null value, as returned by | ||
66 | // NullVal. NilVal is a nil within the *Go* type system, and is invalid in | ||
67 | // the cty type system. Null values *do* exist in the cty type system. | ||
68 | var NilVal = Value{ | ||
69 | ty: Type{typeImpl: nil}, | ||
70 | v: nil, | ||
71 | } | ||
72 | |||
73 | // IsWhollyKnown is an extension of IsKnown that also recursively checks | ||
74 | // inside collections and structures to see if there are any nested unknown | ||
75 | // values. | ||
76 | func (val Value) IsWhollyKnown() bool { | ||
77 | if !val.IsKnown() { | ||
78 | return false | ||
79 | } | ||
80 | |||
81 | if val.IsNull() { | ||
82 | // Can't recurse into a null, so we're done | ||
83 | return true | ||
84 | } | ||
85 | |||
86 | switch { | ||
87 | case val.CanIterateElements(): | ||
88 | for it := val.ElementIterator(); it.Next(); { | ||
89 | _, ev := it.Element() | ||
90 | if !ev.IsWhollyKnown() { | ||
91 | return false | ||
92 | } | ||
93 | } | ||
94 | return true | ||
95 | default: | ||
96 | return true | ||
97 | } | ||
98 | } | ||
diff --git a/vendor/github.com/zclconf/go-cty/cty/value_init.go b/vendor/github.com/zclconf/go-cty/cty/value_init.go new file mode 100644 index 0000000..495a83e --- /dev/null +++ b/vendor/github.com/zclconf/go-cty/cty/value_init.go | |||
@@ -0,0 +1,276 @@ | |||
1 | package cty | ||
2 | |||
3 | import ( | ||
4 | "fmt" | ||
5 | "math/big" | ||
6 | "reflect" | ||
7 | |||
8 | "golang.org/x/text/unicode/norm" | ||
9 | |||
10 | "github.com/zclconf/go-cty/cty/set" | ||
11 | ) | ||
12 | |||
13 | // BoolVal returns a Value of type Number whose internal value is the given | ||
14 | // bool. | ||
15 | func BoolVal(v bool) Value { | ||
16 | return Value{ | ||
17 | ty: Bool, | ||
18 | v: v, | ||
19 | } | ||
20 | } | ||
21 | |||
22 | // NumberVal returns a Value of type Number whose internal value is the given | ||
23 | // big.Float. The returned value becomes the owner of the big.Float object, | ||
24 | // and so it's forbidden for the caller to mutate the object after it's | ||
25 | // wrapped in this way. | ||
26 | func NumberVal(v *big.Float) Value { | ||
27 | return Value{ | ||
28 | ty: Number, | ||
29 | v: v, | ||
30 | } | ||
31 | } | ||
32 | |||
33 | // NumberIntVal returns a Value of type Number whose internal value is equal | ||
34 | // to the given integer. | ||
35 | func NumberIntVal(v int64) Value { | ||
36 | return NumberVal(new(big.Float).SetInt64(v)) | ||
37 | } | ||
38 | |||
39 | // NumberUIntVal returns a Value of type Number whose internal value is equal | ||
40 | // to the given unsigned integer. | ||
41 | func NumberUIntVal(v uint64) Value { | ||
42 | return NumberVal(new(big.Float).SetUint64(v)) | ||
43 | } | ||
44 | |||
45 | // NumberFloatVal returns a Value of type Number whose internal value is | ||
46 | // equal to the given float. | ||
47 | func NumberFloatVal(v float64) Value { | ||
48 | return NumberVal(new(big.Float).SetFloat64(v)) | ||
49 | } | ||
50 | |||
51 | // StringVal returns a Value of type String whose internal value is the | ||
52 | // given string. | ||
53 | // | ||
54 | // Strings must be UTF-8 encoded sequences of valid unicode codepoints, and | ||
55 | // they are NFC-normalized on entry into the world of cty values. | ||
56 | // | ||
57 | // If the given string is not valid UTF-8 then behavior of string operations | ||
58 | // is undefined. | ||
59 | func StringVal(v string) Value { | ||
60 | return Value{ | ||
61 | ty: String, | ||
62 | v: NormalizeString(v), | ||
63 | } | ||
64 | } | ||
65 | |||
66 | // NormalizeString applies the same normalization that cty applies when | ||
67 | // constructing string values. | ||
68 | // | ||
69 | // A return value from this function can be meaningfully compared byte-for-byte | ||
70 | // with a Value.AsString result. | ||
71 | func NormalizeString(s string) string { | ||
72 | return norm.NFC.String(s) | ||
73 | } | ||
74 | |||
75 | // ObjectVal returns a Value of an object type whose structure is defined | ||
76 | // by the key names and value types in the given map. | ||
77 | func ObjectVal(attrs map[string]Value) Value { | ||
78 | attrTypes := make(map[string]Type, len(attrs)) | ||
79 | attrVals := make(map[string]interface{}, len(attrs)) | ||
80 | |||
81 | for attr, val := range attrs { | ||
82 | attr = NormalizeString(attr) | ||
83 | attrTypes[attr] = val.ty | ||
84 | attrVals[attr] = val.v | ||
85 | } | ||
86 | |||
87 | return Value{ | ||
88 | ty: Object(attrTypes), | ||
89 | v: attrVals, | ||
90 | } | ||
91 | } | ||
92 | |||
93 | // TupleVal returns a Value of a tuple type whose element types are | ||
94 | // defined by the value types in the given slice. | ||
95 | func TupleVal(elems []Value) Value { | ||
96 | elemTypes := make([]Type, len(elems)) | ||
97 | elemVals := make([]interface{}, len(elems)) | ||
98 | |||
99 | for i, val := range elems { | ||
100 | elemTypes[i] = val.ty | ||
101 | elemVals[i] = val.v | ||
102 | } | ||
103 | |||
104 | return Value{ | ||
105 | ty: Tuple(elemTypes), | ||
106 | v: elemVals, | ||
107 | } | ||
108 | } | ||
109 | |||
110 | // ListVal returns a Value of list type whose element type is defined by | ||
111 | // the types of the given values, which must be homogenous. | ||
112 | // | ||
113 | // If the types are not all consistent (aside from elements that are of the | ||
114 | // dynamic pseudo-type) then this function will panic. It will panic also | ||
115 | // if the given list is empty, since then the element type cannot be inferred. | ||
116 | // (See also ListValEmpty.) | ||
117 | func ListVal(vals []Value) Value { | ||
118 | if len(vals) == 0 { | ||
119 | panic("must not call ListVal with empty slice") | ||
120 | } | ||
121 | elementType := DynamicPseudoType | ||
122 | rawList := make([]interface{}, len(vals)) | ||
123 | |||
124 | for i, val := range vals { | ||
125 | if elementType == DynamicPseudoType { | ||
126 | elementType = val.ty | ||
127 | } else if val.ty != DynamicPseudoType && !elementType.Equals(val.ty) { | ||
128 | panic(fmt.Errorf( | ||
129 | "inconsistent list element types (%#v then %#v)", | ||
130 | elementType, val.ty, | ||
131 | )) | ||
132 | } | ||
133 | |||
134 | rawList[i] = val.v | ||
135 | } | ||
136 | |||
137 | return Value{ | ||
138 | ty: List(elementType), | ||
139 | v: rawList, | ||
140 | } | ||
141 | } | ||
142 | |||
143 | // ListValEmpty returns an empty list of the given element type. | ||
144 | func ListValEmpty(element Type) Value { | ||
145 | return Value{ | ||
146 | ty: List(element), | ||
147 | v: []interface{}{}, | ||
148 | } | ||
149 | } | ||
150 | |||
151 | // MapVal returns a Value of a map type whose element type is defined by | ||
152 | // the types of the given values, which must be homogenous. | ||
153 | // | ||
154 | // If the types are not all consistent (aside from elements that are of the | ||
155 | // dynamic pseudo-type) then this function will panic. It will panic also | ||
156 | // if the given map is empty, since then the element type cannot be inferred. | ||
157 | // (See also MapValEmpty.) | ||
158 | func MapVal(vals map[string]Value) Value { | ||
159 | if len(vals) == 0 { | ||
160 | panic("must not call MapVal with empty map") | ||
161 | } | ||
162 | elementType := DynamicPseudoType | ||
163 | rawMap := make(map[string]interface{}, len(vals)) | ||
164 | |||
165 | for key, val := range vals { | ||
166 | if elementType == DynamicPseudoType { | ||
167 | elementType = val.ty | ||
168 | } else if val.ty != DynamicPseudoType && !elementType.Equals(val.ty) { | ||
169 | panic(fmt.Errorf( | ||
170 | "inconsistent map element types (%#v then %#v)", | ||
171 | elementType, val.ty, | ||
172 | )) | ||
173 | } | ||
174 | |||
175 | rawMap[NormalizeString(key)] = val.v | ||
176 | } | ||
177 | |||
178 | return Value{ | ||
179 | ty: Map(elementType), | ||
180 | v: rawMap, | ||
181 | } | ||
182 | } | ||
183 | |||
184 | // MapValEmpty returns an empty map of the given element type. | ||
185 | func MapValEmpty(element Type) Value { | ||
186 | return Value{ | ||
187 | ty: Map(element), | ||
188 | v: map[string]interface{}{}, | ||
189 | } | ||
190 | } | ||
191 | |||
192 | // SetVal returns a Value of set type whose element type is defined by | ||
193 | // the types of the given values, which must be homogenous. | ||
194 | // | ||
195 | // If the types are not all consistent (aside from elements that are of the | ||
196 | // dynamic pseudo-type) then this function will panic. It will panic also | ||
197 | // if the given list is empty, since then the element type cannot be inferred. | ||
198 | // (See also SetValEmpty.) | ||
199 | func SetVal(vals []Value) Value { | ||
200 | if len(vals) == 0 { | ||
201 | panic("must not call SetVal with empty slice") | ||
202 | } | ||
203 | elementType := DynamicPseudoType | ||
204 | rawList := make([]interface{}, len(vals)) | ||
205 | |||
206 | for i, val := range vals { | ||
207 | if elementType == DynamicPseudoType { | ||
208 | elementType = val.ty | ||
209 | } else if val.ty != DynamicPseudoType && !elementType.Equals(val.ty) { | ||
210 | panic(fmt.Errorf( | ||
211 | "inconsistent set element types (%#v then %#v)", | ||
212 | elementType, val.ty, | ||
213 | )) | ||
214 | } | ||
215 | |||
216 | rawList[i] = val.v | ||
217 | } | ||
218 | |||
219 | rawVal := set.NewSetFromSlice(setRules{elementType}, rawList) | ||
220 | |||
221 | return Value{ | ||
222 | ty: Set(elementType), | ||
223 | v: rawVal, | ||
224 | } | ||
225 | } | ||
226 | |||
227 | // SetValFromValueSet returns a Value of set type based on an already-constructed | ||
228 | // ValueSet. | ||
229 | // | ||
230 | // The element type of the returned value is the element type of the given | ||
231 | // set. | ||
232 | func SetValFromValueSet(s ValueSet) Value { | ||
233 | ety := s.ElementType() | ||
234 | rawVal := s.s.Copy() // copy so caller can't mutate what we wrap | ||
235 | |||
236 | return Value{ | ||
237 | ty: Set(ety), | ||
238 | v: rawVal, | ||
239 | } | ||
240 | } | ||
241 | |||
242 | // SetValEmpty returns an empty set of the given element type. | ||
243 | func SetValEmpty(element Type) Value { | ||
244 | return Value{ | ||
245 | ty: Set(element), | ||
246 | v: set.NewSet(setRules{element}), | ||
247 | } | ||
248 | } | ||
249 | |||
250 | // CapsuleVal creates a value of the given capsule type using the given | ||
251 | // wrapVal, which must be a pointer to a value of the capsule type's native | ||
252 | // type. | ||
253 | // | ||
254 | // This function will panic if the given type is not a capsule type, if | ||
255 | // the given wrapVal is not compatible with the given capsule type, or if | ||
256 | // wrapVal is not a pointer. | ||
257 | func CapsuleVal(ty Type, wrapVal interface{}) Value { | ||
258 | if !ty.IsCapsuleType() { | ||
259 | panic("not a capsule type") | ||
260 | } | ||
261 | |||
262 | wv := reflect.ValueOf(wrapVal) | ||
263 | if wv.Kind() != reflect.Ptr { | ||
264 | panic("wrapVal is not a pointer") | ||
265 | } | ||
266 | |||
267 | it := ty.typeImpl.(*capsuleType).GoType | ||
268 | if !wv.Type().Elem().AssignableTo(it) { | ||
269 | panic("wrapVal target is not compatible with the given capsule type") | ||
270 | } | ||
271 | |||
272 | return Value{ | ||
273 | ty: ty, | ||
274 | v: wrapVal, | ||
275 | } | ||
276 | } | ||
diff --git a/vendor/github.com/zclconf/go-cty/cty/value_ops.go b/vendor/github.com/zclconf/go-cty/cty/value_ops.go new file mode 100644 index 0000000..967aa76 --- /dev/null +++ b/vendor/github.com/zclconf/go-cty/cty/value_ops.go | |||
@@ -0,0 +1,1071 @@ | |||
1 | package cty | ||
2 | |||
3 | import ( | ||
4 | "fmt" | ||
5 | "math/big" | ||
6 | |||
7 | "reflect" | ||
8 | |||
9 | "github.com/zclconf/go-cty/cty/set" | ||
10 | ) | ||
11 | |||
12 | func (val Value) GoString() string { | ||
13 | if val == NilVal { | ||
14 | return "cty.NilVal" | ||
15 | } | ||
16 | |||
17 | if val.ty == DynamicPseudoType { | ||
18 | return "cty.DynamicVal" | ||
19 | } | ||
20 | |||
21 | if !val.IsKnown() { | ||
22 | return fmt.Sprintf("cty.UnknownVal(%#v)", val.ty) | ||
23 | } | ||
24 | if val.IsNull() { | ||
25 | return fmt.Sprintf("cty.NullVal(%#v)", val.ty) | ||
26 | } | ||
27 | |||
28 | // By the time we reach here we've dealt with all of the exceptions around | ||
29 | // unknowns and nulls, so we're guaranteed that the values are the | ||
30 | // canonical internal representation of the given type. | ||
31 | |||
32 | switch val.ty { | ||
33 | case Bool: | ||
34 | if val.v.(bool) { | ||
35 | return "cty.True" | ||
36 | } else { | ||
37 | return "cty.False" | ||
38 | } | ||
39 | case Number: | ||
40 | fv := val.v.(*big.Float) | ||
41 | // We'll try to use NumberIntVal or NumberFloatVal if we can, since | ||
42 | // the fully-general initializer call is pretty ugly-looking. | ||
43 | if fv.IsInt() { | ||
44 | return fmt.Sprintf("cty.NumberIntVal(%#v)", fv) | ||
45 | } | ||
46 | if rfv, accuracy := fv.Float64(); accuracy == big.Exact { | ||
47 | return fmt.Sprintf("cty.NumberFloatVal(%#v)", rfv) | ||
48 | } | ||
49 | return fmt.Sprintf("cty.NumberVal(new(big.Float).Parse(\"%#v\", 10))", fv) | ||
50 | case String: | ||
51 | return fmt.Sprintf("cty.StringVal(%#v)", val.v) | ||
52 | } | ||
53 | |||
54 | switch { | ||
55 | case val.ty.IsSetType(): | ||
56 | vals := val.v.(set.Set).Values() | ||
57 | if vals == nil || len(vals) == 0 { | ||
58 | return fmt.Sprintf("cty.SetValEmpty()") | ||
59 | } else { | ||
60 | return fmt.Sprintf("cty.SetVal(%#v)", vals) | ||
61 | } | ||
62 | case val.ty.IsCapsuleType(): | ||
63 | return fmt.Sprintf("cty.CapsuleVal(%#v, %#v)", val.ty, val.v) | ||
64 | } | ||
65 | |||
66 | // Default exposes implementation details, so should actually cover | ||
67 | // all of the cases above for good caller UX. | ||
68 | return fmt.Sprintf("cty.Value{ty: %#v, v: %#v}", val.ty, val.v) | ||
69 | } | ||
70 | |||
71 | // Equals returns True if the receiver and the given other value have the | ||
72 | // same type and are exactly equal in value. | ||
73 | // | ||
74 | // The usual short-circuit rules apply, so the result can be unknown or typed | ||
75 | // as dynamic if either of the given values are. Use RawEquals to compare | ||
76 | // if two values are equal *ignoring* the short-circuit rules. | ||
77 | func (val Value) Equals(other Value) Value { | ||
78 | if val.ty.HasDynamicTypes() || other.ty.HasDynamicTypes() { | ||
79 | return UnknownVal(Bool) | ||
80 | } | ||
81 | |||
82 | if !val.ty.Equals(other.ty) { | ||
83 | return BoolVal(false) | ||
84 | } | ||
85 | |||
86 | if !(val.IsKnown() && other.IsKnown()) { | ||
87 | return UnknownVal(Bool) | ||
88 | } | ||
89 | |||
90 | if val.IsNull() || other.IsNull() { | ||
91 | if val.IsNull() && other.IsNull() { | ||
92 | return BoolVal(true) | ||
93 | } | ||
94 | return BoolVal(false) | ||
95 | } | ||
96 | |||
97 | ty := val.ty | ||
98 | result := false | ||
99 | |||
100 | switch { | ||
101 | case ty == Number: | ||
102 | result = val.v.(*big.Float).Cmp(other.v.(*big.Float)) == 0 | ||
103 | case ty == Bool: | ||
104 | result = val.v.(bool) == other.v.(bool) | ||
105 | case ty == String: | ||
106 | // Simple equality is safe because we NFC-normalize strings as they | ||
107 | // enter our world from StringVal, and so we can assume strings are | ||
108 | // always in normal form. | ||
109 | result = val.v.(string) == other.v.(string) | ||
110 | case ty.IsObjectType(): | ||
111 | oty := ty.typeImpl.(typeObject) | ||
112 | result = true | ||
113 | for attr, aty := range oty.AttrTypes { | ||
114 | lhs := Value{ | ||
115 | ty: aty, | ||
116 | v: val.v.(map[string]interface{})[attr], | ||
117 | } | ||
118 | rhs := Value{ | ||
119 | ty: aty, | ||
120 | v: other.v.(map[string]interface{})[attr], | ||
121 | } | ||
122 | eq := lhs.Equals(rhs) | ||
123 | if !eq.IsKnown() { | ||
124 | return UnknownVal(Bool) | ||
125 | } | ||
126 | if eq.False() { | ||
127 | result = false | ||
128 | break | ||
129 | } | ||
130 | } | ||
131 | case ty.IsTupleType(): | ||
132 | tty := ty.typeImpl.(typeTuple) | ||
133 | result = true | ||
134 | for i, ety := range tty.ElemTypes { | ||
135 | lhs := Value{ | ||
136 | ty: ety, | ||
137 | v: val.v.([]interface{})[i], | ||
138 | } | ||
139 | rhs := Value{ | ||
140 | ty: ety, | ||
141 | v: other.v.([]interface{})[i], | ||
142 | } | ||
143 | eq := lhs.Equals(rhs) | ||
144 | if !eq.IsKnown() { | ||
145 | return UnknownVal(Bool) | ||
146 | } | ||
147 | if eq.False() { | ||
148 | result = false | ||
149 | break | ||
150 | } | ||
151 | } | ||
152 | case ty.IsListType(): | ||
153 | ety := ty.typeImpl.(typeList).ElementTypeT | ||
154 | if len(val.v.([]interface{})) == len(other.v.([]interface{})) { | ||
155 | result = true | ||
156 | for i := range val.v.([]interface{}) { | ||
157 | lhs := Value{ | ||
158 | ty: ety, | ||
159 | v: val.v.([]interface{})[i], | ||
160 | } | ||
161 | rhs := Value{ | ||
162 | ty: ety, | ||
163 | v: other.v.([]interface{})[i], | ||
164 | } | ||
165 | eq := lhs.Equals(rhs) | ||
166 | if !eq.IsKnown() { | ||
167 | return UnknownVal(Bool) | ||
168 | } | ||
169 | if eq.False() { | ||
170 | result = false | ||
171 | break | ||
172 | } | ||
173 | } | ||
174 | } | ||
175 | case ty.IsSetType(): | ||
176 | s1 := val.v.(set.Set) | ||
177 | s2 := other.v.(set.Set) | ||
178 | equal := true | ||
179 | |||
180 | // Note that by our definition of sets it's never possible for two | ||
181 | // sets that contain unknown values (directly or indicrectly) to | ||
182 | // ever be equal, even if they are otherwise identical. | ||
183 | |||
184 | // FIXME: iterating both lists and checking each item is not the | ||
185 | // ideal implementation here, but it works with the primitives we | ||
186 | // have in the set implementation. Perhaps the set implementation | ||
187 | // can provide its own equality test later. | ||
188 | s1.EachValue(func(v interface{}) { | ||
189 | if !s2.Has(v) { | ||
190 | equal = false | ||
191 | } | ||
192 | }) | ||
193 | s2.EachValue(func(v interface{}) { | ||
194 | if !s1.Has(v) { | ||
195 | equal = false | ||
196 | } | ||
197 | }) | ||
198 | |||
199 | result = equal | ||
200 | case ty.IsMapType(): | ||
201 | ety := ty.typeImpl.(typeMap).ElementTypeT | ||
202 | if len(val.v.(map[string]interface{})) == len(other.v.(map[string]interface{})) { | ||
203 | result = true | ||
204 | for k := range val.v.(map[string]interface{}) { | ||
205 | if _, ok := other.v.(map[string]interface{})[k]; !ok { | ||
206 | result = false | ||
207 | break | ||
208 | } | ||
209 | lhs := Value{ | ||
210 | ty: ety, | ||
211 | v: val.v.(map[string]interface{})[k], | ||
212 | } | ||
213 | rhs := Value{ | ||
214 | ty: ety, | ||
215 | v: other.v.(map[string]interface{})[k], | ||
216 | } | ||
217 | eq := lhs.Equals(rhs) | ||
218 | if !eq.IsKnown() { | ||
219 | return UnknownVal(Bool) | ||
220 | } | ||
221 | if eq.False() { | ||
222 | result = false | ||
223 | break | ||
224 | } | ||
225 | } | ||
226 | } | ||
227 | case ty.IsCapsuleType(): | ||
228 | // A capsule type's encapsulated value is a pointer to a value of its | ||
229 | // native type, so we can just compare these to get the identity test | ||
230 | // we need. | ||
231 | return BoolVal(val.v == other.v) | ||
232 | |||
233 | default: | ||
234 | // should never happen | ||
235 | panic(fmt.Errorf("unsupported value type %#v in Equals", ty)) | ||
236 | } | ||
237 | |||
238 | return BoolVal(result) | ||
239 | } | ||
240 | |||
241 | // NotEqual is a shorthand for Equals followed by Not. | ||
242 | func (val Value) NotEqual(other Value) Value { | ||
243 | return val.Equals(other).Not() | ||
244 | } | ||
245 | |||
246 | // True returns true if the receiver is True, false if False, and panics if | ||
247 | // the receiver is not of type Bool. | ||
248 | // | ||
249 | // This is a helper function to help write application logic that works with | ||
250 | // values, rather than a first-class operation. It does not work with unknown | ||
251 | // or null values. For more robust handling with unknown value | ||
252 | // short-circuiting, use val.Equals(cty.True). | ||
253 | func (val Value) True() bool { | ||
254 | if val.ty != Bool { | ||
255 | panic("not bool") | ||
256 | } | ||
257 | return val.Equals(True).v.(bool) | ||
258 | } | ||
259 | |||
260 | // False is the opposite of True. | ||
261 | func (val Value) False() bool { | ||
262 | return !val.True() | ||
263 | } | ||
264 | |||
265 | // RawEquals returns true if and only if the two given values have the same | ||
266 | // type and equal value, ignoring the usual short-circuit rules about | ||
267 | // unknowns and dynamic types. | ||
268 | // | ||
269 | // This method is more appropriate for testing than for real use, since it | ||
270 | // skips over usual semantics around unknowns but as a consequence allows | ||
271 | // testing the result of another operation that is expected to return unknown. | ||
272 | // It returns a primitive Go bool rather than a Value to remind us that it | ||
273 | // is not a first-class value operation. | ||
274 | func (val Value) RawEquals(other Value) bool { | ||
275 | if !val.ty.Equals(other.ty) { | ||
276 | return false | ||
277 | } | ||
278 | if (!val.IsKnown()) && (!other.IsKnown()) { | ||
279 | return true | ||
280 | } | ||
281 | if (val.IsKnown() && !other.IsKnown()) || (other.IsKnown() && !val.IsKnown()) { | ||
282 | return false | ||
283 | } | ||
284 | if val.IsNull() && other.IsNull() { | ||
285 | return true | ||
286 | } | ||
287 | if (val.IsNull() && !other.IsNull()) || (other.IsNull() && !val.IsNull()) { | ||
288 | return false | ||
289 | } | ||
290 | if val.ty == DynamicPseudoType && other.ty == DynamicPseudoType { | ||
291 | return true | ||
292 | } | ||
293 | |||
294 | ty := val.ty | ||
295 | switch { | ||
296 | case ty == Number || ty == Bool || ty == String || ty == DynamicPseudoType: | ||
297 | return val.Equals(other).True() | ||
298 | case ty.IsObjectType(): | ||
299 | oty := ty.typeImpl.(typeObject) | ||
300 | for attr, aty := range oty.AttrTypes { | ||
301 | lhs := Value{ | ||
302 | ty: aty, | ||
303 | v: val.v.(map[string]interface{})[attr], | ||
304 | } | ||
305 | rhs := Value{ | ||
306 | ty: aty, | ||
307 | v: other.v.(map[string]interface{})[attr], | ||
308 | } | ||
309 | eq := lhs.RawEquals(rhs) | ||
310 | if !eq { | ||
311 | return false | ||
312 | } | ||
313 | } | ||
314 | return true | ||
315 | case ty.IsTupleType(): | ||
316 | tty := ty.typeImpl.(typeTuple) | ||
317 | for i, ety := range tty.ElemTypes { | ||
318 | lhs := Value{ | ||
319 | ty: ety, | ||
320 | v: val.v.([]interface{})[i], | ||
321 | } | ||
322 | rhs := Value{ | ||
323 | ty: ety, | ||
324 | v: other.v.([]interface{})[i], | ||
325 | } | ||
326 | eq := lhs.RawEquals(rhs) | ||
327 | if !eq { | ||
328 | return false | ||
329 | } | ||
330 | } | ||
331 | return true | ||
332 | case ty.IsListType(): | ||
333 | ety := ty.typeImpl.(typeList).ElementTypeT | ||
334 | if len(val.v.([]interface{})) == len(other.v.([]interface{})) { | ||
335 | for i := range val.v.([]interface{}) { | ||
336 | lhs := Value{ | ||
337 | ty: ety, | ||
338 | v: val.v.([]interface{})[i], | ||
339 | } | ||
340 | rhs := Value{ | ||
341 | ty: ety, | ||
342 | v: other.v.([]interface{})[i], | ||
343 | } | ||
344 | eq := lhs.RawEquals(rhs) | ||
345 | if !eq { | ||
346 | return false | ||
347 | } | ||
348 | } | ||
349 | return true | ||
350 | } | ||
351 | return false | ||
352 | case ty.IsSetType(): | ||
353 | s1 := val.v.(set.Set) | ||
354 | s2 := other.v.(set.Set) | ||
355 | |||
356 | // Since we're intentionally ignoring our rule that two unknowns | ||
357 | // are never equal, we can cheat here. | ||
358 | // (This isn't 100% right since e.g. it will fail if the set contains | ||
359 | // numbers that are infinite, which DeepEqual can't compare properly. | ||
360 | // We're accepting that limitation for simplicity here, since this | ||
361 | // function is here primarily for testing.) | ||
362 | return reflect.DeepEqual(s1, s2) | ||
363 | |||
364 | case ty.IsMapType(): | ||
365 | ety := ty.typeImpl.(typeMap).ElementTypeT | ||
366 | if len(val.v.(map[string]interface{})) == len(other.v.(map[string]interface{})) { | ||
367 | for k := range val.v.(map[string]interface{}) { | ||
368 | if _, ok := other.v.(map[string]interface{})[k]; !ok { | ||
369 | return false | ||
370 | } | ||
371 | lhs := Value{ | ||
372 | ty: ety, | ||
373 | v: val.v.(map[string]interface{})[k], | ||
374 | } | ||
375 | rhs := Value{ | ||
376 | ty: ety, | ||
377 | v: other.v.(map[string]interface{})[k], | ||
378 | } | ||
379 | eq := lhs.RawEquals(rhs) | ||
380 | if !eq { | ||
381 | return false | ||
382 | } | ||
383 | } | ||
384 | return true | ||
385 | } | ||
386 | return false | ||
387 | case ty.IsCapsuleType(): | ||
388 | // A capsule type's encapsulated value is a pointer to a value of its | ||
389 | // native type, so we can just compare these to get the identity test | ||
390 | // we need. | ||
391 | return val.v == other.v | ||
392 | |||
393 | default: | ||
394 | // should never happen | ||
395 | panic(fmt.Errorf("unsupported value type %#v in RawEquals", ty)) | ||
396 | } | ||
397 | } | ||
398 | |||
399 | // Add returns the sum of the receiver and the given other value. Both values | ||
400 | // must be numbers; this method will panic if not. | ||
401 | func (val Value) Add(other Value) Value { | ||
402 | if shortCircuit := mustTypeCheck(Number, Number, val, other); shortCircuit != nil { | ||
403 | shortCircuit = forceShortCircuitType(shortCircuit, Number) | ||
404 | return *shortCircuit | ||
405 | } | ||
406 | |||
407 | ret := new(big.Float) | ||
408 | ret.Add(val.v.(*big.Float), other.v.(*big.Float)) | ||
409 | return NumberVal(ret) | ||
410 | } | ||
411 | |||
412 | // Subtract returns receiver minus the given other value. Both values must be | ||
413 | // numbers; this method will panic if not. | ||
414 | func (val Value) Subtract(other Value) Value { | ||
415 | if shortCircuit := mustTypeCheck(Number, Number, val, other); shortCircuit != nil { | ||
416 | shortCircuit = forceShortCircuitType(shortCircuit, Number) | ||
417 | return *shortCircuit | ||
418 | } | ||
419 | |||
420 | return val.Add(other.Negate()) | ||
421 | } | ||
422 | |||
423 | // Negate returns the numeric negative of the receiver, which must be a number. | ||
424 | // This method will panic when given a value of any other type. | ||
425 | func (val Value) Negate() Value { | ||
426 | if shortCircuit := mustTypeCheck(Number, Number, val); shortCircuit != nil { | ||
427 | shortCircuit = forceShortCircuitType(shortCircuit, Number) | ||
428 | return *shortCircuit | ||
429 | } | ||
430 | |||
431 | ret := new(big.Float).Neg(val.v.(*big.Float)) | ||
432 | return NumberVal(ret) | ||
433 | } | ||
434 | |||
435 | // Multiply returns the product of the receiver and the given other value. | ||
436 | // Both values must be numbers; this method will panic if not. | ||
437 | func (val Value) Multiply(other Value) Value { | ||
438 | if shortCircuit := mustTypeCheck(Number, Number, val, other); shortCircuit != nil { | ||
439 | shortCircuit = forceShortCircuitType(shortCircuit, Number) | ||
440 | return *shortCircuit | ||
441 | } | ||
442 | |||
443 | ret := new(big.Float) | ||
444 | ret.Mul(val.v.(*big.Float), other.v.(*big.Float)) | ||
445 | return NumberVal(ret) | ||
446 | } | ||
447 | |||
448 | // Divide returns the quotient of the receiver and the given other value. | ||
449 | // Both values must be numbers; this method will panic if not. | ||
450 | // | ||
451 | // If the "other" value is exactly zero, this operation will return either | ||
452 | // PositiveInfinity or NegativeInfinity, depending on the sign of the | ||
453 | // receiver value. For some use-cases the presence of infinities may be | ||
454 | // undesirable, in which case the caller should check whether the | ||
455 | // other value equals zero before calling and raise an error instead. | ||
456 | // | ||
457 | // If both values are zero or infinity, this function will panic with | ||
458 | // an instance of big.ErrNaN. | ||
459 | func (val Value) Divide(other Value) Value { | ||
460 | if shortCircuit := mustTypeCheck(Number, Number, val, other); shortCircuit != nil { | ||
461 | shortCircuit = forceShortCircuitType(shortCircuit, Number) | ||
462 | return *shortCircuit | ||
463 | } | ||
464 | |||
465 | ret := new(big.Float) | ||
466 | ret.Quo(val.v.(*big.Float), other.v.(*big.Float)) | ||
467 | return NumberVal(ret) | ||
468 | } | ||
469 | |||
470 | // Modulo returns the remainder of an integer division of the receiver and | ||
471 | // the given other value. Both values must be numbers; this method will panic | ||
472 | // if not. | ||
473 | // | ||
474 | // If the "other" value is exactly zero, this operation will return either | ||
475 | // PositiveInfinity or NegativeInfinity, depending on the sign of the | ||
476 | // receiver value. For some use-cases the presence of infinities may be | ||
477 | // undesirable, in which case the caller should check whether the | ||
478 | // other value equals zero before calling and raise an error instead. | ||
479 | // | ||
480 | // This operation is primarily here for use with nonzero natural numbers. | ||
481 | // Modulo with "other" as a non-natural number gets somewhat philosophical, | ||
482 | // and this function takes a position on what that should mean, but callers | ||
483 | // may wish to disallow such things outright or implement their own modulo | ||
484 | // if they disagree with the interpretation used here. | ||
485 | func (val Value) Modulo(other Value) Value { | ||
486 | if shortCircuit := mustTypeCheck(Number, Number, val, other); shortCircuit != nil { | ||
487 | shortCircuit = forceShortCircuitType(shortCircuit, Number) | ||
488 | return *shortCircuit | ||
489 | } | ||
490 | |||
491 | // We cheat a bit here with infinities, just abusing the Multiply operation | ||
492 | // to get an infinite result of the correct sign. | ||
493 | if val == PositiveInfinity || val == NegativeInfinity || other == PositiveInfinity || other == NegativeInfinity { | ||
494 | return val.Multiply(other) | ||
495 | } | ||
496 | |||
497 | if other.RawEquals(Zero) { | ||
498 | return val | ||
499 | } | ||
500 | |||
501 | // FIXME: This is a bit clumsy. Should come back later and see if there's a | ||
502 | // more straightforward way to do this. | ||
503 | rat := val.Divide(other) | ||
504 | ratFloorInt := &big.Int{} | ||
505 | rat.v.(*big.Float).Int(ratFloorInt) | ||
506 | work := (&big.Float{}).SetInt(ratFloorInt) | ||
507 | work.Mul(other.v.(*big.Float), work) | ||
508 | work.Sub(val.v.(*big.Float), work) | ||
509 | |||
510 | return NumberVal(work) | ||
511 | } | ||
512 | |||
513 | // Absolute returns the absolute (signless) value of the receiver, which must | ||
514 | // be a number or this method will panic. | ||
515 | func (val Value) Absolute() Value { | ||
516 | if shortCircuit := mustTypeCheck(Number, Number, val); shortCircuit != nil { | ||
517 | shortCircuit = forceShortCircuitType(shortCircuit, Number) | ||
518 | return *shortCircuit | ||
519 | } | ||
520 | |||
521 | ret := (&big.Float{}).Abs(val.v.(*big.Float)) | ||
522 | return NumberVal(ret) | ||
523 | } | ||
524 | |||
525 | // GetAttr returns the value of the given attribute of the receiver, which | ||
526 | // must be of an object type that has an attribute of the given name. | ||
527 | // This method will panic if the receiver type is not compatible. | ||
528 | // | ||
529 | // The method will also panic if the given attribute name is not defined | ||
530 | // for the value's type. Use the attribute-related methods on Type to | ||
531 | // check for the validity of an attribute before trying to use it. | ||
532 | // | ||
533 | // This method may be called on a value whose type is DynamicPseudoType, | ||
534 | // in which case the result will also be DynamicVal. | ||
535 | func (val Value) GetAttr(name string) Value { | ||
536 | if val.ty == DynamicPseudoType { | ||
537 | return DynamicVal | ||
538 | } | ||
539 | |||
540 | if !val.ty.IsObjectType() { | ||
541 | panic("value is not an object") | ||
542 | } | ||
543 | |||
544 | name = NormalizeString(name) | ||
545 | if !val.ty.HasAttribute(name) { | ||
546 | panic("value has no attribute of that name") | ||
547 | } | ||
548 | |||
549 | attrType := val.ty.AttributeType(name) | ||
550 | |||
551 | if !val.IsKnown() { | ||
552 | return UnknownVal(attrType) | ||
553 | } | ||
554 | |||
555 | return Value{ | ||
556 | ty: attrType, | ||
557 | v: val.v.(map[string]interface{})[name], | ||
558 | } | ||
559 | } | ||
560 | |||
561 | // Index returns the value of an element of the receiver, which must have | ||
562 | // either a list, map or tuple type. This method will panic if the receiver | ||
563 | // type is not compatible. | ||
564 | // | ||
565 | // The key value must be the correct type for the receving collection: a | ||
566 | // number if the collection is a list or tuple, or a string if it is a map. | ||
567 | // In the case of a list or tuple, the given number must be convertable to int | ||
568 | // or this method will panic. The key may alternatively be of | ||
569 | // DynamicPseudoType, in which case the result itself is an unknown of the | ||
570 | // collection's element type. | ||
571 | // | ||
572 | // The result is of the receiver collection's element type, or in the case | ||
573 | // of a tuple the type of the specific element index requested. | ||
574 | // | ||
575 | // This method may be called on a value whose type is DynamicPseudoType, | ||
576 | // in which case the result will also be the DynamicValue. | ||
577 | func (val Value) Index(key Value) Value { | ||
578 | if val.ty == DynamicPseudoType { | ||
579 | return DynamicVal | ||
580 | } | ||
581 | |||
582 | switch { | ||
583 | case val.Type().IsListType(): | ||
584 | elty := val.Type().ElementType() | ||
585 | if key.Type() == DynamicPseudoType { | ||
586 | return UnknownVal(elty) | ||
587 | } | ||
588 | |||
589 | if key.Type() != Number { | ||
590 | panic("element key for list must be number") | ||
591 | } | ||
592 | if !key.IsKnown() { | ||
593 | return UnknownVal(elty) | ||
594 | } | ||
595 | |||
596 | if !val.IsKnown() { | ||
597 | return UnknownVal(elty) | ||
598 | } | ||
599 | |||
600 | index, accuracy := key.v.(*big.Float).Int64() | ||
601 | if accuracy != big.Exact || index < 0 { | ||
602 | panic("element key for list must be non-negative integer") | ||
603 | } | ||
604 | |||
605 | return Value{ | ||
606 | ty: elty, | ||
607 | v: val.v.([]interface{})[index], | ||
608 | } | ||
609 | case val.Type().IsMapType(): | ||
610 | elty := val.Type().ElementType() | ||
611 | if key.Type() == DynamicPseudoType { | ||
612 | return UnknownVal(elty) | ||
613 | } | ||
614 | |||
615 | if key.Type() != String { | ||
616 | panic("element key for map must be string") | ||
617 | } | ||
618 | if !key.IsKnown() { | ||
619 | return UnknownVal(elty) | ||
620 | } | ||
621 | |||
622 | if !val.IsKnown() { | ||
623 | return UnknownVal(elty) | ||
624 | } | ||
625 | |||
626 | keyStr := key.v.(string) | ||
627 | |||
628 | return Value{ | ||
629 | ty: elty, | ||
630 | v: val.v.(map[string]interface{})[keyStr], | ||
631 | } | ||
632 | case val.Type().IsTupleType(): | ||
633 | if key.Type() == DynamicPseudoType { | ||
634 | return DynamicVal | ||
635 | } | ||
636 | |||
637 | if key.Type() != Number { | ||
638 | panic("element key for tuple must be number") | ||
639 | } | ||
640 | if !key.IsKnown() { | ||
641 | return DynamicVal | ||
642 | } | ||
643 | |||
644 | index, accuracy := key.v.(*big.Float).Int64() | ||
645 | if accuracy != big.Exact || index < 0 { | ||
646 | panic("element key for list must be non-negative integer") | ||
647 | } | ||
648 | |||
649 | eltys := val.Type().TupleElementTypes() | ||
650 | |||
651 | if !val.IsKnown() { | ||
652 | return UnknownVal(eltys[index]) | ||
653 | } | ||
654 | |||
655 | return Value{ | ||
656 | ty: eltys[index], | ||
657 | v: val.v.([]interface{})[index], | ||
658 | } | ||
659 | default: | ||
660 | panic("not a list, map, or tuple type") | ||
661 | } | ||
662 | } | ||
663 | |||
664 | // HasIndex returns True if the receiver (which must be supported for Index) | ||
665 | // has an element with the given index key, or False if it does not. | ||
666 | // | ||
667 | // The result will be UnknownVal(Bool) if either the collection or the | ||
668 | // key value are unknown. | ||
669 | // | ||
670 | // This method will panic if the receiver is not indexable, but does not | ||
671 | // impose any panic-causing type constraints on the key. | ||
672 | func (val Value) HasIndex(key Value) Value { | ||
673 | if val.ty == DynamicPseudoType { | ||
674 | return UnknownVal(Bool) | ||
675 | } | ||
676 | |||
677 | switch { | ||
678 | case val.Type().IsListType(): | ||
679 | if key.Type() == DynamicPseudoType { | ||
680 | return UnknownVal(Bool) | ||
681 | } | ||
682 | |||
683 | if key.Type() != Number { | ||
684 | return False | ||
685 | } | ||
686 | if !key.IsKnown() { | ||
687 | return UnknownVal(Bool) | ||
688 | } | ||
689 | if !val.IsKnown() { | ||
690 | return UnknownVal(Bool) | ||
691 | } | ||
692 | |||
693 | index, accuracy := key.v.(*big.Float).Int64() | ||
694 | if accuracy != big.Exact || index < 0 { | ||
695 | return False | ||
696 | } | ||
697 | |||
698 | return BoolVal(int(index) < len(val.v.([]interface{})) && index >= 0) | ||
699 | case val.Type().IsMapType(): | ||
700 | if key.Type() == DynamicPseudoType { | ||
701 | return UnknownVal(Bool) | ||
702 | } | ||
703 | |||
704 | if key.Type() != String { | ||
705 | return False | ||
706 | } | ||
707 | if !key.IsKnown() { | ||
708 | return UnknownVal(Bool) | ||
709 | } | ||
710 | if !val.IsKnown() { | ||
711 | return UnknownVal(Bool) | ||
712 | } | ||
713 | |||
714 | keyStr := key.v.(string) | ||
715 | _, exists := val.v.(map[string]interface{})[keyStr] | ||
716 | |||
717 | return BoolVal(exists) | ||
718 | case val.Type().IsTupleType(): | ||
719 | if key.Type() == DynamicPseudoType { | ||
720 | return UnknownVal(Bool) | ||
721 | } | ||
722 | |||
723 | if key.Type() != Number { | ||
724 | return False | ||
725 | } | ||
726 | if !key.IsKnown() { | ||
727 | return UnknownVal(Bool) | ||
728 | } | ||
729 | |||
730 | index, accuracy := key.v.(*big.Float).Int64() | ||
731 | if accuracy != big.Exact || index < 0 { | ||
732 | return False | ||
733 | } | ||
734 | |||
735 | length := val.Type().Length() | ||
736 | return BoolVal(int(index) < length && index >= 0) | ||
737 | default: | ||
738 | panic("not a list, map, or tuple type") | ||
739 | } | ||
740 | } | ||
741 | |||
742 | // HasElement returns True if the receiver (which must be of a set type) | ||
743 | // has the given value as an element, or False if it does not. | ||
744 | // | ||
745 | // The result will be UnknownVal(Bool) if either the set or the | ||
746 | // given value are unknown. | ||
747 | // | ||
748 | // This method will panic if the receiver is not a set, or if it is a null set. | ||
749 | func (val Value) HasElement(elem Value) Value { | ||
750 | ty := val.Type() | ||
751 | |||
752 | if !ty.IsSetType() { | ||
753 | panic("not a set type") | ||
754 | } | ||
755 | if !val.IsKnown() || !elem.IsKnown() { | ||
756 | return UnknownVal(Bool) | ||
757 | } | ||
758 | if val.IsNull() { | ||
759 | panic("can't call HasElement on a nil value") | ||
760 | } | ||
761 | if ty.ElementType() != elem.Type() { | ||
762 | return False | ||
763 | } | ||
764 | |||
765 | s := val.v.(set.Set) | ||
766 | return BoolVal(s.Has(elem.v)) | ||
767 | } | ||
768 | |||
769 | // Length returns the length of the receiver, which must be a collection type | ||
770 | // or tuple type, as a number value. If the receiver is not a compatible type | ||
771 | // then this method will panic. | ||
772 | // | ||
773 | // If the receiver is unknown then the result is also unknown. | ||
774 | // | ||
775 | // If the receiver is null then this function will panic. | ||
776 | // | ||
777 | // Note that Length is not supported for strings. To determine the length | ||
778 | // of a string, call AsString and take the length of the native Go string | ||
779 | // that is returned. | ||
780 | func (val Value) Length() Value { | ||
781 | if val.Type().IsTupleType() { | ||
782 | // For tuples, we can return the length even if the value is not known. | ||
783 | return NumberIntVal(int64(val.Type().Length())) | ||
784 | } | ||
785 | |||
786 | if !val.IsKnown() { | ||
787 | return UnknownVal(Number) | ||
788 | } | ||
789 | |||
790 | return NumberIntVal(int64(val.LengthInt())) | ||
791 | } | ||
792 | |||
793 | // LengthInt is like Length except it returns an int. It has the same behavior | ||
794 | // as Length except that it will panic if the receiver is unknown. | ||
795 | // | ||
796 | // This is an integration method provided for the convenience of code bridging | ||
797 | // into Go's type system. | ||
798 | func (val Value) LengthInt() int { | ||
799 | if val.Type().IsTupleType() { | ||
800 | // For tuples, we can return the length even if the value is not known. | ||
801 | return val.Type().Length() | ||
802 | } | ||
803 | if !val.IsKnown() { | ||
804 | panic("value is not known") | ||
805 | } | ||
806 | if val.IsNull() { | ||
807 | panic("value is null") | ||
808 | } | ||
809 | |||
810 | switch { | ||
811 | |||
812 | case val.ty.IsListType(): | ||
813 | return len(val.v.([]interface{})) | ||
814 | |||
815 | case val.ty.IsSetType(): | ||
816 | return val.v.(set.Set).Length() | ||
817 | |||
818 | case val.ty.IsMapType(): | ||
819 | return len(val.v.(map[string]interface{})) | ||
820 | |||
821 | default: | ||
822 | panic("value is not a collection") | ||
823 | } | ||
824 | } | ||
825 | |||
826 | // ElementIterator returns an ElementIterator for iterating the elements | ||
827 | // of the receiver, which must be a collection type, a tuple type, or an object | ||
828 | // type. If called on a method of any other type, this method will panic. | ||
829 | // | ||
830 | // The value must be Known and non-Null, or this method will panic. | ||
831 | // | ||
832 | // If the receiver is of a list type, the returned keys will be of type Number | ||
833 | // and the values will be of the list's element type. | ||
834 | // | ||
835 | // If the receiver is of a map type, the returned keys will be of type String | ||
836 | // and the value will be of the map's element type. Elements are passed in | ||
837 | // ascending lexicographical order by key. | ||
838 | // | ||
839 | // If the receiver is of a set type, each element is returned as both the | ||
840 | // key and the value, since set members are their own identity. | ||
841 | // | ||
842 | // If the receiver is of a tuple type, the returned keys will be of type Number | ||
843 | // and the value will be of the corresponding element's type. | ||
844 | // | ||
845 | // If the receiver is of an object type, the returned keys will be of type | ||
846 | // String and the value will be of the corresponding attributes's type. | ||
847 | // | ||
848 | // ElementIterator is an integration method, so it cannot handle Unknown | ||
849 | // values. This method will panic if the receiver is Unknown. | ||
850 | func (val Value) ElementIterator() ElementIterator { | ||
851 | if !val.IsKnown() { | ||
852 | panic("can't use ElementIterator on unknown value") | ||
853 | } | ||
854 | if val.IsNull() { | ||
855 | panic("can't use ElementIterator on null value") | ||
856 | } | ||
857 | return elementIterator(val) | ||
858 | } | ||
859 | |||
860 | // CanIterateElements returns true if the receiver can support the | ||
861 | // ElementIterator method (and by extension, ForEachElement) without panic. | ||
862 | func (val Value) CanIterateElements() bool { | ||
863 | return canElementIterator(val) | ||
864 | } | ||
865 | |||
866 | // ForEachElement executes a given callback function for each element of | ||
867 | // the receiver, which must be a collection type or tuple type, or this method | ||
868 | // will panic. | ||
869 | // | ||
870 | // ForEachElement uses ElementIterator internally, and so the values passed | ||
871 | // to the callback are as described for ElementIterator. | ||
872 | // | ||
873 | // Returns true if the iteration exited early due to the callback function | ||
874 | // returning true, or false if the loop ran to completion. | ||
875 | // | ||
876 | // ForEachElement is an integration method, so it cannot handle Unknown | ||
877 | // values. This method will panic if the receiver is Unknown. | ||
878 | func (val Value) ForEachElement(cb ElementCallback) bool { | ||
879 | it := val.ElementIterator() | ||
880 | for it.Next() { | ||
881 | key, val := it.Element() | ||
882 | stop := cb(key, val) | ||
883 | if stop { | ||
884 | return true | ||
885 | } | ||
886 | } | ||
887 | return false | ||
888 | } | ||
889 | |||
890 | // Not returns the logical inverse of the receiver, which must be of type | ||
891 | // Bool or this method will panic. | ||
892 | func (val Value) Not() Value { | ||
893 | if shortCircuit := mustTypeCheck(Bool, Bool, val); shortCircuit != nil { | ||
894 | shortCircuit = forceShortCircuitType(shortCircuit, Bool) | ||
895 | return *shortCircuit | ||
896 | } | ||
897 | |||
898 | return BoolVal(!val.v.(bool)) | ||
899 | } | ||
900 | |||
901 | // And returns the result of logical AND with the receiver and the other given | ||
902 | // value, which must both be of type Bool or this method will panic. | ||
903 | func (val Value) And(other Value) Value { | ||
904 | if shortCircuit := mustTypeCheck(Bool, Bool, val, other); shortCircuit != nil { | ||
905 | shortCircuit = forceShortCircuitType(shortCircuit, Bool) | ||
906 | return *shortCircuit | ||
907 | } | ||
908 | |||
909 | return BoolVal(val.v.(bool) && other.v.(bool)) | ||
910 | } | ||
911 | |||
912 | // Or returns the result of logical OR with the receiver and the other given | ||
913 | // value, which must both be of type Bool or this method will panic. | ||
914 | func (val Value) Or(other Value) Value { | ||
915 | if shortCircuit := mustTypeCheck(Bool, Bool, val, other); shortCircuit != nil { | ||
916 | shortCircuit = forceShortCircuitType(shortCircuit, Bool) | ||
917 | return *shortCircuit | ||
918 | } | ||
919 | |||
920 | return BoolVal(val.v.(bool) || other.v.(bool)) | ||
921 | } | ||
922 | |||
923 | // LessThan returns True if the receiver is less than the other given value, | ||
924 | // which must both be numbers or this method will panic. | ||
925 | func (val Value) LessThan(other Value) Value { | ||
926 | if shortCircuit := mustTypeCheck(Number, Bool, val, other); shortCircuit != nil { | ||
927 | shortCircuit = forceShortCircuitType(shortCircuit, Bool) | ||
928 | return *shortCircuit | ||
929 | } | ||
930 | |||
931 | return BoolVal(val.v.(*big.Float).Cmp(other.v.(*big.Float)) < 0) | ||
932 | } | ||
933 | |||
934 | // GreaterThan returns True if the receiver is greater than the other given | ||
935 | // value, which must both be numbers or this method will panic. | ||
936 | func (val Value) GreaterThan(other Value) Value { | ||
937 | if shortCircuit := mustTypeCheck(Number, Bool, val, other); shortCircuit != nil { | ||
938 | shortCircuit = forceShortCircuitType(shortCircuit, Bool) | ||
939 | return *shortCircuit | ||
940 | } | ||
941 | |||
942 | return BoolVal(val.v.(*big.Float).Cmp(other.v.(*big.Float)) > 0) | ||
943 | } | ||
944 | |||
945 | // LessThanOrEqualTo is equivalent to LessThan and Equal combined with Or. | ||
946 | func (val Value) LessThanOrEqualTo(other Value) Value { | ||
947 | return val.LessThan(other).Or(val.Equals(other)) | ||
948 | } | ||
949 | |||
950 | // GreaterThanOrEqualTo is equivalent to GreaterThan and Equal combined with Or. | ||
951 | func (val Value) GreaterThanOrEqualTo(other Value) Value { | ||
952 | return val.GreaterThan(other).Or(val.Equals(other)) | ||
953 | } | ||
954 | |||
955 | // AsString returns the native string from a non-null, non-unknown cty.String | ||
956 | // value, or panics if called on any other value. | ||
957 | func (val Value) AsString() string { | ||
958 | if val.ty != String { | ||
959 | panic("not a string") | ||
960 | } | ||
961 | if val.IsNull() { | ||
962 | panic("value is null") | ||
963 | } | ||
964 | if !val.IsKnown() { | ||
965 | panic("value is unknown") | ||
966 | } | ||
967 | |||
968 | return val.v.(string) | ||
969 | } | ||
970 | |||
971 | // AsBigFloat returns a big.Float representation of a non-null, non-unknown | ||
972 | // cty.Number value, or panics if called on any other value. | ||
973 | // | ||
974 | // For more convenient conversions to other native numeric types, use the | ||
975 | // "gocty" package. | ||
976 | func (val Value) AsBigFloat() *big.Float { | ||
977 | if val.ty != Number { | ||
978 | panic("not a number") | ||
979 | } | ||
980 | if val.IsNull() { | ||
981 | panic("value is null") | ||
982 | } | ||
983 | if !val.IsKnown() { | ||
984 | panic("value is unknown") | ||
985 | } | ||
986 | |||
987 | // Copy the float so that callers can't mutate our internal state | ||
988 | ret := *(val.v.(*big.Float)) | ||
989 | |||
990 | return &ret | ||
991 | } | ||
992 | |||
993 | // AsValueSlice returns a []cty.Value representation of a non-null, non-unknown | ||
994 | // value of any type that CanIterateElements, or panics if called on | ||
995 | // any other value. | ||
996 | // | ||
997 | // For more convenient conversions to slices of more specific types, use | ||
998 | // the "gocty" package. | ||
999 | func (val Value) AsValueSlice() []Value { | ||
1000 | l := val.LengthInt() | ||
1001 | if l == 0 { | ||
1002 | return nil | ||
1003 | } | ||
1004 | |||
1005 | ret := make([]Value, 0, l) | ||
1006 | for it := val.ElementIterator(); it.Next(); { | ||
1007 | _, v := it.Element() | ||
1008 | ret = append(ret, v) | ||
1009 | } | ||
1010 | return ret | ||
1011 | } | ||
1012 | |||
1013 | // AsValueMap returns a map[string]cty.Value representation of a non-null, | ||
1014 | // non-unknown value of any type that CanIterateElements, or panics if called | ||
1015 | // on any other value. | ||
1016 | // | ||
1017 | // For more convenient conversions to maps of more specific types, use | ||
1018 | // the "gocty" package. | ||
1019 | func (val Value) AsValueMap() map[string]Value { | ||
1020 | l := val.LengthInt() | ||
1021 | if l == 0 { | ||
1022 | return nil | ||
1023 | } | ||
1024 | |||
1025 | ret := make(map[string]Value, l) | ||
1026 | for it := val.ElementIterator(); it.Next(); { | ||
1027 | k, v := it.Element() | ||
1028 | ret[k.AsString()] = v | ||
1029 | } | ||
1030 | return ret | ||
1031 | } | ||
1032 | |||
1033 | // AsValueSet returns a ValueSet representation of a non-null, | ||
1034 | // non-unknown value of any collection type, or panics if called | ||
1035 | // on any other value. | ||
1036 | // | ||
1037 | // Unlike AsValueSlice and AsValueMap, this method requires specifically a | ||
1038 | // collection type (list, set or map) and does not allow structural types | ||
1039 | // (tuple or object), because the ValueSet type requires homogenous | ||
1040 | // element types. | ||
1041 | // | ||
1042 | // The returned ValueSet can store only values of the receiver's element type. | ||
1043 | func (val Value) AsValueSet() ValueSet { | ||
1044 | if !val.Type().IsCollectionType() { | ||
1045 | panic("not a collection type") | ||
1046 | } | ||
1047 | |||
1048 | // We don't give the caller our own set.Set (assuming we're a cty.Set value) | ||
1049 | // because then the caller could mutate our internals, which is forbidden. | ||
1050 | // Instead, we will construct a new set and append our elements into it. | ||
1051 | ret := NewValueSet(val.Type().ElementType()) | ||
1052 | for it := val.ElementIterator(); it.Next(); { | ||
1053 | _, v := it.Element() | ||
1054 | ret.Add(v) | ||
1055 | } | ||
1056 | return ret | ||
1057 | } | ||
1058 | |||
1059 | // EncapsulatedValue returns the native value encapsulated in a non-null, | ||
1060 | // non-unknown capsule-typed value, or panics if called on any other value. | ||
1061 | // | ||
1062 | // The result is the same pointer that was passed to CapsuleVal to create | ||
1063 | // the value. Since cty considers values to be immutable, it is strongly | ||
1064 | // recommended to treat the encapsulated value itself as immutable too. | ||
1065 | func (val Value) EncapsulatedValue() interface{} { | ||
1066 | if !val.Type().IsCapsuleType() { | ||
1067 | panic("not a capsule-typed value") | ||
1068 | } | ||
1069 | |||
1070 | return val.v | ||
1071 | } | ||
diff --git a/vendor/github.com/zclconf/go-cty/cty/walk.go b/vendor/github.com/zclconf/go-cty/cty/walk.go new file mode 100644 index 0000000..a6943ba --- /dev/null +++ b/vendor/github.com/zclconf/go-cty/cty/walk.go | |||
@@ -0,0 +1,182 @@ | |||
1 | package cty | ||
2 | |||
3 | // Walk visits all of the values in a possibly-complex structure, calling | ||
4 | // a given function for each value. | ||
5 | // | ||
6 | // For example, given a list of strings the callback would first be called | ||
7 | // with the whole list and then called once for each element of the list. | ||
8 | // | ||
9 | // The callback function may prevent recursive visits to child values by | ||
10 | // returning false. The callback function my halt the walk altogether by | ||
11 | // returning a non-nil error. If the returned error is about the element | ||
12 | // currently being visited, it is recommended to use the provided path | ||
13 | // value to produce a PathError describing that context. | ||
14 | // | ||
15 | // The path passed to the given function may not be used after that function | ||
16 | // returns, since its backing array is re-used for other calls. | ||
17 | func Walk(val Value, cb func(Path, Value) (bool, error)) error { | ||
18 | var path Path | ||
19 | return walk(path, val, cb) | ||
20 | } | ||
21 | |||
22 | func walk(path Path, val Value, cb func(Path, Value) (bool, error)) error { | ||
23 | deeper, err := cb(path, val) | ||
24 | if err != nil { | ||
25 | return err | ||
26 | } | ||
27 | if !deeper { | ||
28 | return nil | ||
29 | } | ||
30 | |||
31 | if val.IsNull() || !val.IsKnown() { | ||
32 | // Can't recurse into null or unknown values, regardless of type | ||
33 | return nil | ||
34 | } | ||
35 | |||
36 | ty := val.Type() | ||
37 | switch { | ||
38 | case ty.IsObjectType(): | ||
39 | for it := val.ElementIterator(); it.Next(); { | ||
40 | nameVal, av := it.Element() | ||
41 | path := append(path, GetAttrStep{ | ||
42 | Name: nameVal.AsString(), | ||
43 | }) | ||
44 | err := walk(path, av, cb) | ||
45 | if err != nil { | ||
46 | return err | ||
47 | } | ||
48 | } | ||
49 | case val.CanIterateElements(): | ||
50 | for it := val.ElementIterator(); it.Next(); { | ||
51 | kv, ev := it.Element() | ||
52 | path := append(path, IndexStep{ | ||
53 | Key: kv, | ||
54 | }) | ||
55 | err := walk(path, ev, cb) | ||
56 | if err != nil { | ||
57 | return err | ||
58 | } | ||
59 | } | ||
60 | } | ||
61 | return nil | ||
62 | } | ||
63 | |||
64 | // Transform visits all of the values in a possibly-complex structure, | ||
65 | // calling a given function for each value which has an opportunity to | ||
66 | // replace that value. | ||
67 | // | ||
68 | // Unlike Walk, Transform visits child nodes first, so for a list of strings | ||
69 | // it would first visit the strings and then the _new_ list constructed | ||
70 | // from the transformed values of the list items. | ||
71 | // | ||
72 | // This is useful for creating the effect of being able to make deep mutations | ||
73 | // to a value even though values are immutable. However, it's the responsibility | ||
74 | // of the given function to preserve expected invariants, such as homogenity of | ||
75 | // element types in collections; this function can panic if such invariants | ||
76 | // are violated, just as if new values were constructed directly using the | ||
77 | // value constructor functions. An easy way to preserve invariants is to | ||
78 | // ensure that the transform function never changes the value type. | ||
79 | // | ||
80 | // The callback function my halt the walk altogether by | ||
81 | // returning a non-nil error. If the returned error is about the element | ||
82 | // currently being visited, it is recommended to use the provided path | ||
83 | // value to produce a PathError describing that context. | ||
84 | // | ||
85 | // The path passed to the given function may not be used after that function | ||
86 | // returns, since its backing array is re-used for other calls. | ||
87 | func Transform(val Value, cb func(Path, Value) (Value, error)) (Value, error) { | ||
88 | var path Path | ||
89 | return transform(path, val, cb) | ||
90 | } | ||
91 | |||
92 | func transform(path Path, val Value, cb func(Path, Value) (Value, error)) (Value, error) { | ||
93 | ty := val.Type() | ||
94 | var newVal Value | ||
95 | |||
96 | switch { | ||
97 | |||
98 | case val.IsNull() || !val.IsKnown(): | ||
99 | // Can't recurse into null or unknown values, regardless of type | ||
100 | newVal = val | ||
101 | |||
102 | case ty.IsListType() || ty.IsSetType() || ty.IsTupleType(): | ||
103 | l := val.LengthInt() | ||
104 | switch l { | ||
105 | case 0: | ||
106 | // No deep transform for an empty sequence | ||
107 | newVal = val | ||
108 | default: | ||
109 | elems := make([]Value, 0, l) | ||
110 | for it := val.ElementIterator(); it.Next(); { | ||
111 | kv, ev := it.Element() | ||
112 | path := append(path, IndexStep{ | ||
113 | Key: kv, | ||
114 | }) | ||
115 | newEv, err := transform(path, ev, cb) | ||
116 | if err != nil { | ||
117 | return DynamicVal, err | ||
118 | } | ||
119 | elems = append(elems, newEv) | ||
120 | } | ||
121 | switch { | ||
122 | case ty.IsListType(): | ||
123 | newVal = ListVal(elems) | ||
124 | case ty.IsSetType(): | ||
125 | newVal = SetVal(elems) | ||
126 | case ty.IsTupleType(): | ||
127 | newVal = TupleVal(elems) | ||
128 | default: | ||
129 | panic("unknown sequence type") // should never happen because of the case we are in | ||
130 | } | ||
131 | } | ||
132 | |||
133 | case ty.IsMapType(): | ||
134 | l := val.LengthInt() | ||
135 | switch l { | ||
136 | case 0: | ||
137 | // No deep transform for an empty map | ||
138 | newVal = val | ||
139 | default: | ||
140 | elems := make(map[string]Value) | ||
141 | for it := val.ElementIterator(); it.Next(); { | ||
142 | kv, ev := it.Element() | ||
143 | path := append(path, IndexStep{ | ||
144 | Key: kv, | ||
145 | }) | ||
146 | newEv, err := transform(path, ev, cb) | ||
147 | if err != nil { | ||
148 | return DynamicVal, err | ||
149 | } | ||
150 | elems[kv.AsString()] = newEv | ||
151 | } | ||
152 | newVal = MapVal(elems) | ||
153 | } | ||
154 | |||
155 | case ty.IsObjectType(): | ||
156 | switch { | ||
157 | case ty.Equals(EmptyObject): | ||
158 | // No deep transform for an empty object | ||
159 | newVal = val | ||
160 | default: | ||
161 | atys := ty.AttributeTypes() | ||
162 | newAVs := make(map[string]Value) | ||
163 | for name := range atys { | ||
164 | av := val.GetAttr(name) | ||
165 | path := append(path, GetAttrStep{ | ||
166 | Name: name, | ||
167 | }) | ||
168 | newAV, err := transform(path, av, cb) | ||
169 | if err != nil { | ||
170 | return DynamicVal, err | ||
171 | } | ||
172 | newAVs[name] = newAV | ||
173 | } | ||
174 | newVal = ObjectVal(newAVs) | ||
175 | } | ||
176 | |||
177 | default: | ||
178 | newVal = val | ||
179 | } | ||
180 | |||
181 | return cb(path, newVal) | ||
182 | } | ||