aboutsummaryrefslogtreecommitdiffhomepage
path: root/vendor/github.com/zclconf/go-cty/cty/value_ops.go
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/github.com/zclconf/go-cty/cty/value_ops.go')
-rw-r--r--vendor/github.com/zclconf/go-cty/cty/value_ops.go1071
1 files changed, 1071 insertions, 0 deletions
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 @@
1package cty
2
3import (
4 "fmt"
5 "math/big"
6
7 "reflect"
8
9 "github.com/zclconf/go-cty/cty/set"
10)
11
12func (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.
77func (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.
242func (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).
253func (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.
261func (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.
274func (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.
401func (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.
414func (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.
425func (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.
437func (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.
459func (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.
485func (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.
515func (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.
535func (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.
577func (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.
672func (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.
749func (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.
780func (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.
798func (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.
850func (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.
862func (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.
878func (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.
892func (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.
903func (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.
914func (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.
925func (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.
936func (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.
946func (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.
951func (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.
957func (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.
976func (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.
999func (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.
1019func (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.
1043func (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.
1065func (val Value) EncapsulatedValue() interface{} {
1066 if !val.Type().IsCapsuleType() {
1067 panic("not a capsule-typed value")
1068 }
1069
1070 return val.v
1071}