diff options
Diffstat (limited to 'vendor/github.com/zclconf/go-cty/cty/element_iterator.go')
-rw-r--r-- | vendor/github.com/zclconf/go-cty/cty/element_iterator.go | 191 |
1 files changed, 191 insertions, 0 deletions
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 | } | ||