1package cty 2 3import ( 4 "fmt" 5 "math/big" 6 "reflect" 7 8 "github.com/zclconf/go-cty/cty/set" 9) 10 11// GoString is an implementation of fmt.GoStringer that produces concise 12// source-like representations of values suitable for use in debug messages. 13func (val Value) GoString() string { 14 if val == NilVal { 15 return "cty.NilVal" 16 } 17 18 if val.IsNull() { 19 return fmt.Sprintf("cty.NullVal(%#v)", val.ty) 20 } 21 if val == DynamicVal { // is unknown, so must be before the IsKnown check below 22 return "cty.DynamicVal" 23 } 24 if !val.IsKnown() { 25 return fmt.Sprintf("cty.UnknownVal(%#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 } 37 return "cty.False" 38 case Number: 39 fv := val.v.(*big.Float) 40 // We'll try to use NumberIntVal or NumberFloatVal if we can, since 41 // the fully-general initializer call is pretty ugly-looking. 42 if fv.IsInt() { 43 return fmt.Sprintf("cty.NumberIntVal(%#v)", fv) 44 } 45 if rfv, accuracy := fv.Float64(); accuracy == big.Exact { 46 return fmt.Sprintf("cty.NumberFloatVal(%#v)", rfv) 47 } 48 return fmt.Sprintf("cty.MustParseNumberVal(%q)", fv.Text('f', -1)) 49 case String: 50 return fmt.Sprintf("cty.StringVal(%#v)", val.v) 51 } 52 53 switch { 54 case val.ty.IsSetType(): 55 vals := val.AsValueSlice() 56 if len(vals) == 0 { 57 return fmt.Sprintf("cty.SetValEmpty(%#v)", val.ty.ElementType()) 58 } 59 return fmt.Sprintf("cty.SetVal(%#v)", vals) 60 case val.ty.IsListType(): 61 vals := val.AsValueSlice() 62 if len(vals) == 0 { 63 return fmt.Sprintf("cty.ListValEmpty(%#v)", val.ty.ElementType()) 64 } 65 return fmt.Sprintf("cty.ListVal(%#v)", vals) 66 case val.ty.IsMapType(): 67 vals := val.AsValueMap() 68 if len(vals) == 0 { 69 return fmt.Sprintf("cty.MapValEmpty(%#v)", val.ty.ElementType()) 70 } 71 return fmt.Sprintf("cty.MapVal(%#v)", vals) 72 case val.ty.IsTupleType(): 73 if val.ty.Equals(EmptyTuple) { 74 return "cty.EmptyTupleVal" 75 } 76 vals := val.AsValueSlice() 77 return fmt.Sprintf("cty.TupleVal(%#v)", vals) 78 case val.ty.IsObjectType(): 79 if val.ty.Equals(EmptyObject) { 80 return "cty.EmptyObjectVal" 81 } 82 vals := val.AsValueMap() 83 return fmt.Sprintf("cty.ObjectVal(%#v)", vals) 84 case val.ty.IsCapsuleType(): 85 return fmt.Sprintf("cty.CapsuleVal(%#v, %#v)", val.ty, val.v) 86 } 87 88 // Default exposes implementation details, so should actually cover 89 // all of the cases above for good caller UX. 90 return fmt.Sprintf("cty.Value{ty: %#v, v: %#v}", val.ty, val.v) 91} 92 93// Equals returns True if the receiver and the given other value have the 94// same type and are exactly equal in value. 95// 96// As a special case, two null values are always equal regardless of type. 97// 98// The usual short-circuit rules apply, so the result will be unknown if 99// either of the given values are. 100// 101// Use RawEquals to compare if two values are equal *ignoring* the 102// short-circuit rules and the exception for null values. 103func (val Value) Equals(other Value) Value { 104 // Start by handling Unknown values before considering types. 105 // This needs to be done since Null values are always equal regardless of 106 // type. 107 switch { 108 case !val.IsKnown() && !other.IsKnown(): 109 // both unknown 110 return UnknownVal(Bool) 111 case val.IsKnown() && !other.IsKnown(): 112 switch { 113 case val.IsNull(), other.ty.HasDynamicTypes(): 114 // If known is Null, we need to wait for the unkown value since 115 // nulls of any type are equal. 116 // An unkown with a dynamic type compares as unknown, which we need 117 // to check before the type comparison below. 118 return UnknownVal(Bool) 119 case !val.ty.Equals(other.ty): 120 // There is no null comparison or dynamic types, so unequal types 121 // will never be equal. 122 return False 123 default: 124 return UnknownVal(Bool) 125 } 126 case other.IsKnown() && !val.IsKnown(): 127 switch { 128 case other.IsNull(), val.ty.HasDynamicTypes(): 129 // If known is Null, we need to wait for the unkown value since 130 // nulls of any type are equal. 131 // An unkown with a dynamic type compares as unknown, which we need 132 // to check before the type comparison below. 133 return UnknownVal(Bool) 134 case !other.ty.Equals(val.ty): 135 // There's no null comparison or dynamic types, so unequal types 136 // will never be equal. 137 return False 138 default: 139 return UnknownVal(Bool) 140 } 141 } 142 143 switch { 144 case val.IsNull() && other.IsNull(): 145 // Nulls are always equal, regardless of type 146 return BoolVal(true) 147 case val.IsNull() || other.IsNull(): 148 // If only one is null then the result must be false 149 return BoolVal(false) 150 } 151 152 if val.ty.HasDynamicTypes() || other.ty.HasDynamicTypes() { 153 return UnknownVal(Bool) 154 } 155 156 if !val.ty.Equals(other.ty) { 157 return BoolVal(false) 158 } 159 160 ty := val.ty 161 result := false 162 163 switch { 164 case ty == Number: 165 result = val.v.(*big.Float).Cmp(other.v.(*big.Float)) == 0 166 case ty == Bool: 167 result = val.v.(bool) == other.v.(bool) 168 case ty == String: 169 // Simple equality is safe because we NFC-normalize strings as they 170 // enter our world from StringVal, and so we can assume strings are 171 // always in normal form. 172 result = val.v.(string) == other.v.(string) 173 case ty.IsObjectType(): 174 oty := ty.typeImpl.(typeObject) 175 result = true 176 for attr, aty := range oty.AttrTypes { 177 lhs := Value{ 178 ty: aty, 179 v: val.v.(map[string]interface{})[attr], 180 } 181 rhs := Value{ 182 ty: aty, 183 v: other.v.(map[string]interface{})[attr], 184 } 185 eq := lhs.Equals(rhs) 186 if !eq.IsKnown() { 187 return UnknownVal(Bool) 188 } 189 if eq.False() { 190 result = false 191 break 192 } 193 } 194 case ty.IsTupleType(): 195 tty := ty.typeImpl.(typeTuple) 196 result = true 197 for i, ety := range tty.ElemTypes { 198 lhs := Value{ 199 ty: ety, 200 v: val.v.([]interface{})[i], 201 } 202 rhs := Value{ 203 ty: ety, 204 v: other.v.([]interface{})[i], 205 } 206 eq := lhs.Equals(rhs) 207 if !eq.IsKnown() { 208 return UnknownVal(Bool) 209 } 210 if eq.False() { 211 result = false 212 break 213 } 214 } 215 case ty.IsListType(): 216 ety := ty.typeImpl.(typeList).ElementTypeT 217 if len(val.v.([]interface{})) == len(other.v.([]interface{})) { 218 result = true 219 for i := range val.v.([]interface{}) { 220 lhs := Value{ 221 ty: ety, 222 v: val.v.([]interface{})[i], 223 } 224 rhs := Value{ 225 ty: ety, 226 v: other.v.([]interface{})[i], 227 } 228 eq := lhs.Equals(rhs) 229 if !eq.IsKnown() { 230 return UnknownVal(Bool) 231 } 232 if eq.False() { 233 result = false 234 break 235 } 236 } 237 } 238 case ty.IsSetType(): 239 s1 := val.v.(set.Set) 240 s2 := other.v.(set.Set) 241 equal := true 242 243 // Note that by our definition of sets it's never possible for two 244 // sets that contain unknown values (directly or indicrectly) to 245 // ever be equal, even if they are otherwise identical. 246 247 // FIXME: iterating both lists and checking each item is not the 248 // ideal implementation here, but it works with the primitives we 249 // have in the set implementation. Perhaps the set implementation 250 // can provide its own equality test later. 251 s1.EachValue(func(v interface{}) { 252 if !s2.Has(v) { 253 equal = false 254 } 255 }) 256 s2.EachValue(func(v interface{}) { 257 if !s1.Has(v) { 258 equal = false 259 } 260 }) 261 262 result = equal 263 case ty.IsMapType(): 264 ety := ty.typeImpl.(typeMap).ElementTypeT 265 if len(val.v.(map[string]interface{})) == len(other.v.(map[string]interface{})) { 266 result = true 267 for k := range val.v.(map[string]interface{}) { 268 if _, ok := other.v.(map[string]interface{})[k]; !ok { 269 result = false 270 break 271 } 272 lhs := Value{ 273 ty: ety, 274 v: val.v.(map[string]interface{})[k], 275 } 276 rhs := Value{ 277 ty: ety, 278 v: other.v.(map[string]interface{})[k], 279 } 280 eq := lhs.Equals(rhs) 281 if !eq.IsKnown() { 282 return UnknownVal(Bool) 283 } 284 if eq.False() { 285 result = false 286 break 287 } 288 } 289 } 290 case ty.IsCapsuleType(): 291 // A capsule type's encapsulated value is a pointer to a value of its 292 // native type, so we can just compare these to get the identity test 293 // we need. 294 return BoolVal(val.v == other.v) 295 296 default: 297 // should never happen 298 panic(fmt.Errorf("unsupported value type %#v in Equals", ty)) 299 } 300 301 return BoolVal(result) 302} 303 304// NotEqual is a shorthand for Equals followed by Not. 305func (val Value) NotEqual(other Value) Value { 306 return val.Equals(other).Not() 307} 308 309// True returns true if the receiver is True, false if False, and panics if 310// the receiver is not of type Bool. 311// 312// This is a helper function to help write application logic that works with 313// values, rather than a first-class operation. It does not work with unknown 314// or null values. For more robust handling with unknown value 315// short-circuiting, use val.Equals(cty.True). 316func (val Value) True() bool { 317 if val.ty != Bool { 318 panic("not bool") 319 } 320 return val.Equals(True).v.(bool) 321} 322 323// False is the opposite of True. 324func (val Value) False() bool { 325 return !val.True() 326} 327 328// RawEquals returns true if and only if the two given values have the same 329// type and equal value, ignoring the usual short-circuit rules about 330// unknowns and dynamic types. 331// 332// This method is more appropriate for testing than for real use, since it 333// skips over usual semantics around unknowns but as a consequence allows 334// testing the result of another operation that is expected to return unknown. 335// It returns a primitive Go bool rather than a Value to remind us that it 336// is not a first-class value operation. 337func (val Value) RawEquals(other Value) bool { 338 if !val.ty.Equals(other.ty) { 339 return false 340 } 341 if (!val.IsKnown()) && (!other.IsKnown()) { 342 return true 343 } 344 if (val.IsKnown() && !other.IsKnown()) || (other.IsKnown() && !val.IsKnown()) { 345 return false 346 } 347 if val.IsNull() && other.IsNull() { 348 return true 349 } 350 if (val.IsNull() && !other.IsNull()) || (other.IsNull() && !val.IsNull()) { 351 return false 352 } 353 if val.ty == DynamicPseudoType && other.ty == DynamicPseudoType { 354 return true 355 } 356 357 ty := val.ty 358 switch { 359 case ty == Number || ty == Bool || ty == String || ty == DynamicPseudoType: 360 return val.Equals(other).True() 361 case ty.IsObjectType(): 362 oty := ty.typeImpl.(typeObject) 363 for attr, aty := range oty.AttrTypes { 364 lhs := Value{ 365 ty: aty, 366 v: val.v.(map[string]interface{})[attr], 367 } 368 rhs := Value{ 369 ty: aty, 370 v: other.v.(map[string]interface{})[attr], 371 } 372 eq := lhs.RawEquals(rhs) 373 if !eq { 374 return false 375 } 376 } 377 return true 378 case ty.IsTupleType(): 379 tty := ty.typeImpl.(typeTuple) 380 for i, ety := range tty.ElemTypes { 381 lhs := Value{ 382 ty: ety, 383 v: val.v.([]interface{})[i], 384 } 385 rhs := Value{ 386 ty: ety, 387 v: other.v.([]interface{})[i], 388 } 389 eq := lhs.RawEquals(rhs) 390 if !eq { 391 return false 392 } 393 } 394 return true 395 case ty.IsListType(): 396 ety := ty.typeImpl.(typeList).ElementTypeT 397 if len(val.v.([]interface{})) == len(other.v.([]interface{})) { 398 for i := range val.v.([]interface{}) { 399 lhs := Value{ 400 ty: ety, 401 v: val.v.([]interface{})[i], 402 } 403 rhs := Value{ 404 ty: ety, 405 v: other.v.([]interface{})[i], 406 } 407 eq := lhs.RawEquals(rhs) 408 if !eq { 409 return false 410 } 411 } 412 return true 413 } 414 return false 415 case ty.IsSetType(): 416 s1 := val.v.(set.Set) 417 s2 := other.v.(set.Set) 418 419 // Since we're intentionally ignoring our rule that two unknowns 420 // are never equal, we can cheat here. 421 // (This isn't 100% right since e.g. it will fail if the set contains 422 // numbers that are infinite, which DeepEqual can't compare properly. 423 // We're accepting that limitation for simplicity here, since this 424 // function is here primarily for testing.) 425 return reflect.DeepEqual(s1, s2) 426 427 case ty.IsMapType(): 428 ety := ty.typeImpl.(typeMap).ElementTypeT 429 if len(val.v.(map[string]interface{})) == len(other.v.(map[string]interface{})) { 430 for k := range val.v.(map[string]interface{}) { 431 if _, ok := other.v.(map[string]interface{})[k]; !ok { 432 return false 433 } 434 lhs := Value{ 435 ty: ety, 436 v: val.v.(map[string]interface{})[k], 437 } 438 rhs := Value{ 439 ty: ety, 440 v: other.v.(map[string]interface{})[k], 441 } 442 eq := lhs.RawEquals(rhs) 443 if !eq { 444 return false 445 } 446 } 447 return true 448 } 449 return false 450 case ty.IsCapsuleType(): 451 // A capsule type's encapsulated value is a pointer to a value of its 452 // native type, so we can just compare these to get the identity test 453 // we need. 454 return val.v == other.v 455 456 default: 457 // should never happen 458 panic(fmt.Errorf("unsupported value type %#v in RawEquals", ty)) 459 } 460} 461 462// Add returns the sum of the receiver and the given other value. Both values 463// must be numbers; this method will panic if not. 464func (val Value) Add(other Value) Value { 465 if shortCircuit := mustTypeCheck(Number, Number, val, other); shortCircuit != nil { 466 shortCircuit = forceShortCircuitType(shortCircuit, Number) 467 return *shortCircuit 468 } 469 470 ret := new(big.Float) 471 ret.Add(val.v.(*big.Float), other.v.(*big.Float)) 472 return NumberVal(ret) 473} 474 475// Subtract returns receiver minus the given other value. Both values must be 476// numbers; this method will panic if not. 477func (val Value) Subtract(other Value) Value { 478 if shortCircuit := mustTypeCheck(Number, Number, val, other); shortCircuit != nil { 479 shortCircuit = forceShortCircuitType(shortCircuit, Number) 480 return *shortCircuit 481 } 482 483 return val.Add(other.Negate()) 484} 485 486// Negate returns the numeric negative of the receiver, which must be a number. 487// This method will panic when given a value of any other type. 488func (val Value) Negate() Value { 489 if shortCircuit := mustTypeCheck(Number, Number, val); shortCircuit != nil { 490 shortCircuit = forceShortCircuitType(shortCircuit, Number) 491 return *shortCircuit 492 } 493 494 ret := new(big.Float).Neg(val.v.(*big.Float)) 495 return NumberVal(ret) 496} 497 498// Multiply returns the product of the receiver and the given other value. 499// Both values must be numbers; this method will panic if not. 500func (val Value) Multiply(other Value) Value { 501 if shortCircuit := mustTypeCheck(Number, Number, val, other); shortCircuit != nil { 502 shortCircuit = forceShortCircuitType(shortCircuit, Number) 503 return *shortCircuit 504 } 505 506 ret := new(big.Float) 507 ret.Mul(val.v.(*big.Float), other.v.(*big.Float)) 508 return NumberVal(ret) 509} 510 511// Divide returns the quotient of the receiver and the given other value. 512// Both values must be numbers; this method will panic if not. 513// 514// If the "other" value is exactly zero, this operation will return either 515// PositiveInfinity or NegativeInfinity, depending on the sign of the 516// receiver value. For some use-cases the presence of infinities may be 517// undesirable, in which case the caller should check whether the 518// other value equals zero before calling and raise an error instead. 519// 520// If both values are zero or infinity, this function will panic with 521// an instance of big.ErrNaN. 522func (val Value) Divide(other Value) Value { 523 if shortCircuit := mustTypeCheck(Number, Number, val, other); shortCircuit != nil { 524 shortCircuit = forceShortCircuitType(shortCircuit, Number) 525 return *shortCircuit 526 } 527 528 ret := new(big.Float) 529 ret.Quo(val.v.(*big.Float), other.v.(*big.Float)) 530 return NumberVal(ret) 531} 532 533// Modulo returns the remainder of an integer division of the receiver and 534// the given other value. Both values must be numbers; this method will panic 535// if not. 536// 537// If the "other" value is exactly zero, this operation will return either 538// PositiveInfinity or NegativeInfinity, depending on the sign of the 539// receiver value. For some use-cases the presence of infinities may be 540// undesirable, in which case the caller should check whether the 541// other value equals zero before calling and raise an error instead. 542// 543// This operation is primarily here for use with nonzero natural numbers. 544// Modulo with "other" as a non-natural number gets somewhat philosophical, 545// and this function takes a position on what that should mean, but callers 546// may wish to disallow such things outright or implement their own modulo 547// if they disagree with the interpretation used here. 548func (val Value) Modulo(other Value) Value { 549 if shortCircuit := mustTypeCheck(Number, Number, val, other); shortCircuit != nil { 550 shortCircuit = forceShortCircuitType(shortCircuit, Number) 551 return *shortCircuit 552 } 553 554 // We cheat a bit here with infinities, just abusing the Multiply operation 555 // to get an infinite result of the correct sign. 556 if val == PositiveInfinity || val == NegativeInfinity || other == PositiveInfinity || other == NegativeInfinity { 557 return val.Multiply(other) 558 } 559 560 if other.RawEquals(Zero) { 561 return val 562 } 563 564 // FIXME: This is a bit clumsy. Should come back later and see if there's a 565 // more straightforward way to do this. 566 rat := val.Divide(other) 567 ratFloorInt := &big.Int{} 568 rat.v.(*big.Float).Int(ratFloorInt) 569 work := (&big.Float{}).SetInt(ratFloorInt) 570 work.Mul(other.v.(*big.Float), work) 571 work.Sub(val.v.(*big.Float), work) 572 573 return NumberVal(work) 574} 575 576// Absolute returns the absolute (signless) value of the receiver, which must 577// be a number or this method will panic. 578func (val Value) Absolute() Value { 579 if shortCircuit := mustTypeCheck(Number, Number, val); shortCircuit != nil { 580 shortCircuit = forceShortCircuitType(shortCircuit, Number) 581 return *shortCircuit 582 } 583 584 ret := (&big.Float{}).Abs(val.v.(*big.Float)) 585 return NumberVal(ret) 586} 587 588// GetAttr returns the value of the given attribute of the receiver, which 589// must be of an object type that has an attribute of the given name. 590// This method will panic if the receiver type is not compatible. 591// 592// The method will also panic if the given attribute name is not defined 593// for the value's type. Use the attribute-related methods on Type to 594// check for the validity of an attribute before trying to use it. 595// 596// This method may be called on a value whose type is DynamicPseudoType, 597// in which case the result will also be DynamicVal. 598func (val Value) GetAttr(name string) Value { 599 if val.ty == DynamicPseudoType { 600 return DynamicVal 601 } 602 603 if !val.ty.IsObjectType() { 604 panic("value is not an object") 605 } 606 607 name = NormalizeString(name) 608 if !val.ty.HasAttribute(name) { 609 panic("value has no attribute of that name") 610 } 611 612 attrType := val.ty.AttributeType(name) 613 614 if !val.IsKnown() { 615 return UnknownVal(attrType) 616 } 617 618 return Value{ 619 ty: attrType, 620 v: val.v.(map[string]interface{})[name], 621 } 622} 623 624// Index returns the value of an element of the receiver, which must have 625// either a list, map or tuple type. This method will panic if the receiver 626// type is not compatible. 627// 628// The key value must be the correct type for the receving collection: a 629// number if the collection is a list or tuple, or a string if it is a map. 630// In the case of a list or tuple, the given number must be convertable to int 631// or this method will panic. The key may alternatively be of 632// DynamicPseudoType, in which case the result itself is an unknown of the 633// collection's element type. 634// 635// The result is of the receiver collection's element type, or in the case 636// of a tuple the type of the specific element index requested. 637// 638// This method may be called on a value whose type is DynamicPseudoType, 639// in which case the result will also be the DynamicValue. 640func (val Value) Index(key Value) Value { 641 if val.ty == DynamicPseudoType { 642 return DynamicVal 643 } 644 645 switch { 646 case val.Type().IsListType(): 647 elty := val.Type().ElementType() 648 if key.Type() == DynamicPseudoType { 649 return UnknownVal(elty) 650 } 651 652 if key.Type() != Number { 653 panic("element key for list must be number") 654 } 655 if !key.IsKnown() { 656 return UnknownVal(elty) 657 } 658 659 if !val.IsKnown() { 660 return UnknownVal(elty) 661 } 662 663 index, accuracy := key.v.(*big.Float).Int64() 664 if accuracy != big.Exact || index < 0 { 665 panic("element key for list must be non-negative integer") 666 } 667 668 return Value{ 669 ty: elty, 670 v: val.v.([]interface{})[index], 671 } 672 case val.Type().IsMapType(): 673 elty := val.Type().ElementType() 674 if key.Type() == DynamicPseudoType { 675 return UnknownVal(elty) 676 } 677 678 if key.Type() != String { 679 panic("element key for map must be string") 680 } 681 if !key.IsKnown() { 682 return UnknownVal(elty) 683 } 684 685 if !val.IsKnown() { 686 return UnknownVal(elty) 687 } 688 689 keyStr := key.v.(string) 690 691 return Value{ 692 ty: elty, 693 v: val.v.(map[string]interface{})[keyStr], 694 } 695 case val.Type().IsTupleType(): 696 if key.Type() == DynamicPseudoType { 697 return DynamicVal 698 } 699 700 if key.Type() != Number { 701 panic("element key for tuple must be number") 702 } 703 if !key.IsKnown() { 704 return DynamicVal 705 } 706 707 index, accuracy := key.v.(*big.Float).Int64() 708 if accuracy != big.Exact || index < 0 { 709 panic("element key for list must be non-negative integer") 710 } 711 712 eltys := val.Type().TupleElementTypes() 713 714 if !val.IsKnown() { 715 return UnknownVal(eltys[index]) 716 } 717 718 return Value{ 719 ty: eltys[index], 720 v: val.v.([]interface{})[index], 721 } 722 default: 723 panic("not a list, map, or tuple type") 724 } 725} 726 727// HasIndex returns True if the receiver (which must be supported for Index) 728// has an element with the given index key, or False if it does not. 729// 730// The result will be UnknownVal(Bool) if either the collection or the 731// key value are unknown. 732// 733// This method will panic if the receiver is not indexable, but does not 734// impose any panic-causing type constraints on the key. 735func (val Value) HasIndex(key Value) Value { 736 if val.ty == DynamicPseudoType { 737 return UnknownVal(Bool) 738 } 739 740 switch { 741 case val.Type().IsListType(): 742 if key.Type() == DynamicPseudoType { 743 return UnknownVal(Bool) 744 } 745 746 if key.Type() != Number { 747 return False 748 } 749 if !key.IsKnown() { 750 return UnknownVal(Bool) 751 } 752 if !val.IsKnown() { 753 return UnknownVal(Bool) 754 } 755 756 index, accuracy := key.v.(*big.Float).Int64() 757 if accuracy != big.Exact || index < 0 { 758 return False 759 } 760 761 return BoolVal(int(index) < len(val.v.([]interface{})) && index >= 0) 762 case val.Type().IsMapType(): 763 if key.Type() == DynamicPseudoType { 764 return UnknownVal(Bool) 765 } 766 767 if key.Type() != String { 768 return False 769 } 770 if !key.IsKnown() { 771 return UnknownVal(Bool) 772 } 773 if !val.IsKnown() { 774 return UnknownVal(Bool) 775 } 776 777 keyStr := key.v.(string) 778 _, exists := val.v.(map[string]interface{})[keyStr] 779 780 return BoolVal(exists) 781 case val.Type().IsTupleType(): 782 if key.Type() == DynamicPseudoType { 783 return UnknownVal(Bool) 784 } 785 786 if key.Type() != Number { 787 return False 788 } 789 if !key.IsKnown() { 790 return UnknownVal(Bool) 791 } 792 793 index, accuracy := key.v.(*big.Float).Int64() 794 if accuracy != big.Exact || index < 0 { 795 return False 796 } 797 798 length := val.Type().Length() 799 return BoolVal(int(index) < length && index >= 0) 800 default: 801 panic("not a list, map, or tuple type") 802 } 803} 804 805// HasElement returns True if the receiver (which must be of a set type) 806// has the given value as an element, or False if it does not. 807// 808// The result will be UnknownVal(Bool) if either the set or the 809// given value are unknown. 810// 811// This method will panic if the receiver is not a set, or if it is a null set. 812func (val Value) HasElement(elem Value) Value { 813 ty := val.Type() 814 815 if !ty.IsSetType() { 816 panic("not a set type") 817 } 818 if !val.IsKnown() || !elem.IsKnown() { 819 return UnknownVal(Bool) 820 } 821 if val.IsNull() { 822 panic("can't call HasElement on a nil value") 823 } 824 if !ty.ElementType().Equals(elem.Type()) { 825 return False 826 } 827 828 s := val.v.(set.Set) 829 return BoolVal(s.Has(elem.v)) 830} 831 832// Length returns the length of the receiver, which must be a collection type 833// or tuple type, as a number value. If the receiver is not a compatible type 834// then this method will panic. 835// 836// If the receiver is unknown then the result is also unknown. 837// 838// If the receiver is null then this function will panic. 839// 840// Note that Length is not supported for strings. To determine the length 841// of a string, call AsString and take the length of the native Go string 842// that is returned. 843func (val Value) Length() Value { 844 if val.Type().IsTupleType() { 845 // For tuples, we can return the length even if the value is not known. 846 return NumberIntVal(int64(val.Type().Length())) 847 } 848 849 if !val.IsKnown() { 850 return UnknownVal(Number) 851 } 852 853 return NumberIntVal(int64(val.LengthInt())) 854} 855 856// LengthInt is like Length except it returns an int. It has the same behavior 857// as Length except that it will panic if the receiver is unknown. 858// 859// This is an integration method provided for the convenience of code bridging 860// into Go's type system. 861func (val Value) LengthInt() int { 862 if val.Type().IsTupleType() { 863 // For tuples, we can return the length even if the value is not known. 864 return val.Type().Length() 865 } 866 if val.Type().IsObjectType() { 867 // For objects, the length is the number of attributes associated with the type. 868 return len(val.Type().AttributeTypes()) 869 } 870 if !val.IsKnown() { 871 panic("value is not known") 872 } 873 if val.IsNull() { 874 panic("value is null") 875 } 876 877 switch { 878 879 case val.ty.IsListType(): 880 return len(val.v.([]interface{})) 881 882 case val.ty.IsSetType(): 883 return val.v.(set.Set).Length() 884 885 case val.ty.IsMapType(): 886 return len(val.v.(map[string]interface{})) 887 888 default: 889 panic("value is not a collection") 890 } 891} 892 893// ElementIterator returns an ElementIterator for iterating the elements 894// of the receiver, which must be a collection type, a tuple type, or an object 895// type. If called on a method of any other type, this method will panic. 896// 897// The value must be Known and non-Null, or this method will panic. 898// 899// If the receiver is of a list type, the returned keys will be of type Number 900// and the values will be of the list's element type. 901// 902// If the receiver is of a map type, the returned keys will be of type String 903// and the value will be of the map's element type. Elements are passed in 904// ascending lexicographical order by key. 905// 906// If the receiver is of a set type, each element is returned as both the 907// key and the value, since set members are their own identity. 908// 909// If the receiver is of a tuple type, the returned keys will be of type Number 910// and the value will be of the corresponding element's type. 911// 912// If the receiver is of an object type, the returned keys will be of type 913// String and the value will be of the corresponding attributes's type. 914// 915// ElementIterator is an integration method, so it cannot handle Unknown 916// values. This method will panic if the receiver is Unknown. 917func (val Value) ElementIterator() ElementIterator { 918 if !val.IsKnown() { 919 panic("can't use ElementIterator on unknown value") 920 } 921 if val.IsNull() { 922 panic("can't use ElementIterator on null value") 923 } 924 return elementIterator(val) 925} 926 927// CanIterateElements returns true if the receiver can support the 928// ElementIterator method (and by extension, ForEachElement) without panic. 929func (val Value) CanIterateElements() bool { 930 return canElementIterator(val) 931} 932 933// ForEachElement executes a given callback function for each element of 934// the receiver, which must be a collection type or tuple type, or this method 935// will panic. 936// 937// ForEachElement uses ElementIterator internally, and so the values passed 938// to the callback are as described for ElementIterator. 939// 940// Returns true if the iteration exited early due to the callback function 941// returning true, or false if the loop ran to completion. 942// 943// ForEachElement is an integration method, so it cannot handle Unknown 944// values. This method will panic if the receiver is Unknown. 945func (val Value) ForEachElement(cb ElementCallback) bool { 946 it := val.ElementIterator() 947 for it.Next() { 948 key, val := it.Element() 949 stop := cb(key, val) 950 if stop { 951 return true 952 } 953 } 954 return false 955} 956 957// Not returns the logical inverse of the receiver, which must be of type 958// Bool or this method will panic. 959func (val Value) Not() Value { 960 if shortCircuit := mustTypeCheck(Bool, Bool, val); shortCircuit != nil { 961 shortCircuit = forceShortCircuitType(shortCircuit, Bool) 962 return *shortCircuit 963 } 964 965 return BoolVal(!val.v.(bool)) 966} 967 968// And returns the result of logical AND with the receiver and the other given 969// value, which must both be of type Bool or this method will panic. 970func (val Value) And(other Value) Value { 971 if shortCircuit := mustTypeCheck(Bool, Bool, val, other); shortCircuit != nil { 972 shortCircuit = forceShortCircuitType(shortCircuit, Bool) 973 return *shortCircuit 974 } 975 976 return BoolVal(val.v.(bool) && other.v.(bool)) 977} 978 979// Or returns the result of logical OR with the receiver and the other given 980// value, which must both be of type Bool or this method will panic. 981func (val Value) Or(other Value) Value { 982 if shortCircuit := mustTypeCheck(Bool, Bool, val, other); shortCircuit != nil { 983 shortCircuit = forceShortCircuitType(shortCircuit, Bool) 984 return *shortCircuit 985 } 986 987 return BoolVal(val.v.(bool) || other.v.(bool)) 988} 989 990// LessThan returns True if the receiver is less than the other given value, 991// which must both be numbers or this method will panic. 992func (val Value) LessThan(other Value) Value { 993 if shortCircuit := mustTypeCheck(Number, Bool, val, other); shortCircuit != nil { 994 shortCircuit = forceShortCircuitType(shortCircuit, Bool) 995 return *shortCircuit 996 } 997 998 return BoolVal(val.v.(*big.Float).Cmp(other.v.(*big.Float)) < 0) 999} 1000 1001// GreaterThan returns True if the receiver is greater than the other given 1002// value, which must both be numbers or this method will panic. 1003func (val Value) GreaterThan(other Value) Value { 1004 if shortCircuit := mustTypeCheck(Number, Bool, val, other); shortCircuit != nil { 1005 shortCircuit = forceShortCircuitType(shortCircuit, Bool) 1006 return *shortCircuit 1007 } 1008 1009 return BoolVal(val.v.(*big.Float).Cmp(other.v.(*big.Float)) > 0) 1010} 1011 1012// LessThanOrEqualTo is equivalent to LessThan and Equal combined with Or. 1013func (val Value) LessThanOrEqualTo(other Value) Value { 1014 return val.LessThan(other).Or(val.Equals(other)) 1015} 1016 1017// GreaterThanOrEqualTo is equivalent to GreaterThan and Equal combined with Or. 1018func (val Value) GreaterThanOrEqualTo(other Value) Value { 1019 return val.GreaterThan(other).Or(val.Equals(other)) 1020} 1021 1022// AsString returns the native string from a non-null, non-unknown cty.String 1023// value, or panics if called on any other value. 1024func (val Value) AsString() string { 1025 if val.ty != String { 1026 panic("not a string") 1027 } 1028 if val.IsNull() { 1029 panic("value is null") 1030 } 1031 if !val.IsKnown() { 1032 panic("value is unknown") 1033 } 1034 1035 return val.v.(string) 1036} 1037 1038// AsBigFloat returns a big.Float representation of a non-null, non-unknown 1039// cty.Number value, or panics if called on any other value. 1040// 1041// For more convenient conversions to other native numeric types, use the 1042// "gocty" package. 1043func (val Value) AsBigFloat() *big.Float { 1044 if val.ty != Number { 1045 panic("not a number") 1046 } 1047 if val.IsNull() { 1048 panic("value is null") 1049 } 1050 if !val.IsKnown() { 1051 panic("value is unknown") 1052 } 1053 1054 // Copy the float so that callers can't mutate our internal state 1055 ret := *(val.v.(*big.Float)) 1056 1057 return &ret 1058} 1059 1060// AsValueSlice returns a []cty.Value representation of a non-null, non-unknown 1061// value of any type that CanIterateElements, or panics if called on 1062// any other value. 1063// 1064// For more convenient conversions to slices of more specific types, use 1065// the "gocty" package. 1066func (val Value) AsValueSlice() []Value { 1067 l := val.LengthInt() 1068 if l == 0 { 1069 return nil 1070 } 1071 1072 ret := make([]Value, 0, l) 1073 for it := val.ElementIterator(); it.Next(); { 1074 _, v := it.Element() 1075 ret = append(ret, v) 1076 } 1077 return ret 1078} 1079 1080// AsValueMap returns a map[string]cty.Value representation of a non-null, 1081// non-unknown value of any type that CanIterateElements, or panics if called 1082// on any other value. 1083// 1084// For more convenient conversions to maps of more specific types, use 1085// the "gocty" package. 1086func (val Value) AsValueMap() map[string]Value { 1087 l := val.LengthInt() 1088 if l == 0 { 1089 return nil 1090 } 1091 1092 ret := make(map[string]Value, l) 1093 for it := val.ElementIterator(); it.Next(); { 1094 k, v := it.Element() 1095 ret[k.AsString()] = v 1096 } 1097 return ret 1098} 1099 1100// AsValueSet returns a ValueSet representation of a non-null, 1101// non-unknown value of any collection type, or panics if called 1102// on any other value. 1103// 1104// Unlike AsValueSlice and AsValueMap, this method requires specifically a 1105// collection type (list, set or map) and does not allow structural types 1106// (tuple or object), because the ValueSet type requires homogenous 1107// element types. 1108// 1109// The returned ValueSet can store only values of the receiver's element type. 1110func (val Value) AsValueSet() ValueSet { 1111 if !val.Type().IsCollectionType() { 1112 panic("not a collection type") 1113 } 1114 1115 // We don't give the caller our own set.Set (assuming we're a cty.Set value) 1116 // because then the caller could mutate our internals, which is forbidden. 1117 // Instead, we will construct a new set and append our elements into it. 1118 ret := NewValueSet(val.Type().ElementType()) 1119 for it := val.ElementIterator(); it.Next(); { 1120 _, v := it.Element() 1121 ret.Add(v) 1122 } 1123 return ret 1124} 1125 1126// EncapsulatedValue returns the native value encapsulated in a non-null, 1127// non-unknown capsule-typed value, or panics if called on any other value. 1128// 1129// The result is the same pointer that was passed to CapsuleVal to create 1130// the value. Since cty considers values to be immutable, it is strongly 1131// recommended to treat the encapsulated value itself as immutable too. 1132func (val Value) EncapsulatedValue() interface{} { 1133 if !val.Type().IsCapsuleType() { 1134 panic("not a capsule-typed value") 1135 } 1136 1137 return val.v 1138} 1139