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