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