k8s.io/apiserver@v0.31.1/pkg/cel/value.go (about) 1 /* 2 Copyright 2022 The Kubernetes Authors. 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 package cel 18 19 import ( 20 "fmt" 21 "reflect" 22 "sync" 23 "time" 24 25 "github.com/google/cel-go/common/types" 26 "github.com/google/cel-go/common/types/ref" 27 "github.com/google/cel-go/common/types/traits" 28 ) 29 30 // EncodeStyle is a hint for string encoding of parsed values. 31 type EncodeStyle int 32 33 const ( 34 // BlockValueStyle is the default string encoding which preserves whitespace and newlines. 35 BlockValueStyle EncodeStyle = iota 36 37 // FlowValueStyle indicates that the string is an inline representation of complex types. 38 FlowValueStyle 39 40 // FoldedValueStyle is a multiline string with whitespace and newlines trimmed to a single 41 // a whitespace. Repeated newlines are replaced with a single newline rather than a single 42 // whitespace. 43 FoldedValueStyle 44 45 // LiteralStyle is a multiline string that preserves newlines, but trims all other whitespace 46 // to a single character. 47 LiteralStyle 48 ) 49 50 // NewEmptyDynValue returns the zero-valued DynValue. 51 func NewEmptyDynValue() *DynValue { 52 // note: 0 is not a valid parse node identifier. 53 dv, _ := NewDynValue(0, nil) 54 return dv 55 } 56 57 // NewDynValue returns a DynValue that corresponds to a parse node id and value. 58 func NewDynValue(id int64, val interface{}) (*DynValue, error) { 59 dv := &DynValue{ID: id} 60 err := dv.SetValue(val) 61 return dv, err 62 } 63 64 // DynValue is a dynamically typed value used to describe unstructured content. 65 // Whether the value has the desired type is determined by where it is used within the Instance or 66 // Template, and whether there are schemas which might enforce a more rigid type definition. 67 type DynValue struct { 68 ID int64 69 EncodeStyle EncodeStyle 70 value interface{} 71 exprValue ref.Val 72 declType *DeclType 73 } 74 75 // DeclType returns the policy model type of the dyn value. 76 func (dv *DynValue) DeclType() *DeclType { 77 return dv.declType 78 } 79 80 // ConvertToNative is an implementation of the CEL ref.Val method used to adapt between CEL types 81 // and Go-native types. 82 // 83 // The default behavior of this method is to first convert to a CEL type which has a well-defined 84 // set of conversion behaviors and proxy to the CEL ConvertToNative method for the type. 85 func (dv *DynValue) ConvertToNative(typeDesc reflect.Type) (interface{}, error) { 86 ev := dv.ExprValue() 87 if types.IsError(ev) { 88 return nil, ev.(*types.Err) 89 } 90 return ev.ConvertToNative(typeDesc) 91 } 92 93 // Equal returns whether the dyn value is equal to a given CEL value. 94 func (dv *DynValue) Equal(other ref.Val) ref.Val { 95 dvType := dv.Type() 96 otherType := other.Type() 97 // Preserve CEL's homogeneous equality constraint. 98 if dvType.TypeName() != otherType.TypeName() { 99 return types.MaybeNoSuchOverloadErr(other) 100 } 101 switch v := dv.value.(type) { 102 case ref.Val: 103 return v.Equal(other) 104 case PlainTextValue: 105 return celBool(string(v) == other.Value().(string)) 106 case *MultilineStringValue: 107 return celBool(v.Value == other.Value().(string)) 108 case time.Duration: 109 otherDuration := other.Value().(time.Duration) 110 return celBool(v == otherDuration) 111 case time.Time: 112 otherTimestamp := other.Value().(time.Time) 113 return celBool(v.Equal(otherTimestamp)) 114 default: 115 return celBool(reflect.DeepEqual(v, other.Value())) 116 } 117 } 118 119 // ExprValue converts the DynValue into a CEL value. 120 func (dv *DynValue) ExprValue() ref.Val { 121 return dv.exprValue 122 } 123 124 // Value returns the underlying value held by this reference. 125 func (dv *DynValue) Value() interface{} { 126 return dv.value 127 } 128 129 // SetValue updates the underlying value held by this reference. 130 func (dv *DynValue) SetValue(value interface{}) error { 131 dv.value = value 132 var err error 133 dv.exprValue, dv.declType, err = exprValue(value) 134 return err 135 } 136 137 // Type returns the CEL type for the given value. 138 func (dv *DynValue) Type() ref.Type { 139 return dv.ExprValue().Type() 140 } 141 142 func exprValue(value interface{}) (ref.Val, *DeclType, error) { 143 switch v := value.(type) { 144 case bool: 145 return types.Bool(v), BoolType, nil 146 case []byte: 147 return types.Bytes(v), BytesType, nil 148 case float64: 149 return types.Double(v), DoubleType, nil 150 case int64: 151 return types.Int(v), IntType, nil 152 case string: 153 return types.String(v), StringType, nil 154 case uint64: 155 return types.Uint(v), UintType, nil 156 case time.Duration: 157 return types.Duration{Duration: v}, DurationType, nil 158 case time.Time: 159 return types.Timestamp{Time: v}, TimestampType, nil 160 case types.Null: 161 return v, NullType, nil 162 case *ListValue: 163 return v, ListType, nil 164 case *MapValue: 165 return v, MapType, nil 166 case *ObjectValue: 167 return v, v.objectType, nil 168 default: 169 return nil, unknownType, fmt.Errorf("unsupported type: (%T)%v", v, v) 170 } 171 } 172 173 // PlainTextValue is a text string literal which must not be treated as an expression. 174 type PlainTextValue string 175 176 // MultilineStringValue is a multiline string value which has been parsed in a way which omits 177 // whitespace as well as a raw form which preserves whitespace. 178 type MultilineStringValue struct { 179 Value string 180 Raw string 181 } 182 183 func newStructValue() *structValue { 184 return &structValue{ 185 Fields: []*Field{}, 186 fieldMap: map[string]*Field{}, 187 } 188 } 189 190 type structValue struct { 191 Fields []*Field 192 fieldMap map[string]*Field 193 } 194 195 // AddField appends a MapField to the MapValue and indexes the field by name. 196 func (sv *structValue) AddField(field *Field) { 197 sv.Fields = append(sv.Fields, field) 198 sv.fieldMap[field.Name] = field 199 } 200 201 // ConvertToNative converts the MapValue type to a native go types. 202 func (sv *structValue) ConvertToNative(typeDesc reflect.Type) (interface{}, error) { 203 if typeDesc.Kind() != reflect.Map && 204 typeDesc.Kind() != reflect.Struct && 205 typeDesc.Kind() != reflect.Pointer && 206 typeDesc.Kind() != reflect.Interface { 207 return nil, fmt.Errorf("type conversion error from object to '%v'", typeDesc) 208 } 209 210 // Unwrap pointers, but track their use. 211 isPtr := false 212 if typeDesc.Kind() == reflect.Pointer { 213 tk := typeDesc 214 typeDesc = typeDesc.Elem() 215 if typeDesc.Kind() == reflect.Pointer { 216 return nil, fmt.Errorf("unsupported type conversion to '%v'", tk) 217 } 218 isPtr = true 219 } 220 221 if typeDesc.Kind() == reflect.Map { 222 keyType := typeDesc.Key() 223 if keyType.Kind() != reflect.String && keyType.Kind() != reflect.Interface { 224 return nil, fmt.Errorf("object fields cannot be converted to type '%v'", keyType) 225 } 226 elemType := typeDesc.Elem() 227 sz := len(sv.fieldMap) 228 ntvMap := reflect.MakeMapWithSize(typeDesc, sz) 229 for name, val := range sv.fieldMap { 230 refVal, err := val.Ref.ConvertToNative(elemType) 231 if err != nil { 232 return nil, err 233 } 234 ntvMap.SetMapIndex(reflect.ValueOf(name), reflect.ValueOf(refVal)) 235 } 236 return ntvMap.Interface(), nil 237 } 238 239 if typeDesc.Kind() == reflect.Struct { 240 ntvObjPtr := reflect.New(typeDesc) 241 ntvObj := ntvObjPtr.Elem() 242 for name, val := range sv.fieldMap { 243 f := ntvObj.FieldByName(name) 244 if !f.IsValid() { 245 return nil, fmt.Errorf("type conversion error, no such field %s in type %v", 246 name, typeDesc) 247 } 248 fv, err := val.Ref.ConvertToNative(f.Type()) 249 if err != nil { 250 return nil, err 251 } 252 f.Set(reflect.ValueOf(fv)) 253 } 254 if isPtr { 255 return ntvObjPtr.Interface(), nil 256 } 257 return ntvObj.Interface(), nil 258 } 259 return nil, fmt.Errorf("type conversion error from object to '%v'", typeDesc) 260 } 261 262 // GetField returns a MapField by name if one exists. 263 func (sv *structValue) GetField(name string) (*Field, bool) { 264 field, found := sv.fieldMap[name] 265 return field, found 266 } 267 268 // IsSet returns whether the given field, which is defined, has also been set. 269 func (sv *structValue) IsSet(key ref.Val) ref.Val { 270 k, ok := key.(types.String) 271 if !ok { 272 return types.MaybeNoSuchOverloadErr(key) 273 } 274 name := string(k) 275 _, found := sv.fieldMap[name] 276 return celBool(found) 277 } 278 279 // NewObjectValue creates a struct value with a schema type and returns the empty ObjectValue. 280 func NewObjectValue(sType *DeclType) *ObjectValue { 281 return &ObjectValue{ 282 structValue: newStructValue(), 283 objectType: sType, 284 } 285 } 286 287 // ObjectValue is a struct with a custom schema type which indicates the fields and types 288 // associated with the structure. 289 type ObjectValue struct { 290 *structValue 291 objectType *DeclType 292 } 293 294 // ConvertToType is an implementation of the CEL ref.Val interface method. 295 func (o *ObjectValue) ConvertToType(t ref.Type) ref.Val { 296 if t == types.TypeType { 297 return types.NewObjectTypeValue(o.objectType.TypeName()) 298 } 299 if t.TypeName() == o.objectType.TypeName() { 300 return o 301 } 302 return types.NewErr("type conversion error from '%s' to '%s'", o.Type(), t) 303 } 304 305 // Equal returns true if the two object types are equal and their field values are equal. 306 func (o *ObjectValue) Equal(other ref.Val) ref.Val { 307 // Preserve CEL's homogeneous equality semantics. 308 if o.objectType.TypeName() != other.Type().TypeName() { 309 return types.MaybeNoSuchOverloadErr(other) 310 } 311 o2 := other.(traits.Indexer) 312 for name := range o.objectType.Fields { 313 k := types.String(name) 314 v := o.Get(k) 315 ov := o2.Get(k) 316 vEq := v.Equal(ov) 317 if vEq != types.True { 318 return vEq 319 } 320 } 321 return types.True 322 } 323 324 // Get returns the value of the specified field. 325 // 326 // If the field is set, its value is returned. If the field is not set, the default value for the 327 // field is returned thus allowing for safe-traversal and preserving proto-like field traversal 328 // semantics for Open API Schema backed types. 329 func (o *ObjectValue) Get(name ref.Val) ref.Val { 330 n, ok := name.(types.String) 331 if !ok { 332 return types.MaybeNoSuchOverloadErr(n) 333 } 334 nameStr := string(n) 335 field, found := o.fieldMap[nameStr] 336 if found { 337 return field.Ref.ExprValue() 338 } 339 fieldDef, found := o.objectType.Fields[nameStr] 340 if !found { 341 return types.NewErr("no such field: %s", nameStr) 342 } 343 defValue := fieldDef.DefaultValue() 344 if defValue != nil { 345 return defValue 346 } 347 return types.NewErr("no default for type: %s", fieldDef.TypeName()) 348 } 349 350 // Type returns the CEL type value of the object. 351 func (o *ObjectValue) Type() ref.Type { 352 return o.objectType 353 } 354 355 // Value returns the Go-native representation of the object. 356 func (o *ObjectValue) Value() interface{} { 357 return o 358 } 359 360 // NewMapValue returns an empty MapValue. 361 func NewMapValue() *MapValue { 362 return &MapValue{ 363 structValue: newStructValue(), 364 } 365 } 366 367 // MapValue declares an object with a set of named fields whose values are dynamically typed. 368 type MapValue struct { 369 *structValue 370 } 371 372 // ConvertToObject produces an ObjectValue from the MapValue with the associated schema type. 373 // 374 // The conversion is shallow and the memory shared between the Object and Map as all references 375 // to the map are expected to be replaced with the Object reference. 376 func (m *MapValue) ConvertToObject(declType *DeclType) *ObjectValue { 377 return &ObjectValue{ 378 structValue: m.structValue, 379 objectType: declType, 380 } 381 } 382 383 // Contains returns whether the given key is contained in the MapValue. 384 func (m *MapValue) Contains(key ref.Val) ref.Val { 385 v, found := m.Find(key) 386 if v != nil && types.IsUnknownOrError(v) { 387 return v 388 } 389 return celBool(found) 390 } 391 392 // ConvertToType converts the MapValue to another CEL type, if possible. 393 func (m *MapValue) ConvertToType(t ref.Type) ref.Val { 394 switch t { 395 case types.MapType: 396 return m 397 case types.TypeType: 398 return types.MapType 399 } 400 return types.NewErr("type conversion error from '%s' to '%s'", m.Type(), t) 401 } 402 403 // Equal returns true if the maps are of the same size, have the same keys, and the key-values 404 // from each map are equal. 405 func (m *MapValue) Equal(other ref.Val) ref.Val { 406 oMap, isMap := other.(traits.Mapper) 407 if !isMap { 408 return types.MaybeNoSuchOverloadErr(other) 409 } 410 if m.Size() != oMap.Size() { 411 return types.False 412 } 413 for name, field := range m.fieldMap { 414 k := types.String(name) 415 ov, found := oMap.Find(k) 416 if !found { 417 return types.False 418 } 419 v := field.Ref.ExprValue() 420 vEq := v.Equal(ov) 421 if vEq != types.True { 422 return vEq 423 } 424 } 425 return types.True 426 } 427 428 // Find returns the value for the key in the map, if found. 429 func (m *MapValue) Find(name ref.Val) (ref.Val, bool) { 430 // Currently only maps with string keys are supported as this is best aligned with JSON, 431 // and also much simpler to support. 432 n, ok := name.(types.String) 433 if !ok { 434 return types.MaybeNoSuchOverloadErr(n), true 435 } 436 nameStr := string(n) 437 field, found := m.fieldMap[nameStr] 438 if found { 439 return field.Ref.ExprValue(), true 440 } 441 return nil, false 442 } 443 444 // Get returns the value for the key in the map, or error if not found. 445 func (m *MapValue) Get(key ref.Val) ref.Val { 446 v, found := m.Find(key) 447 if found { 448 return v 449 } 450 return types.ValOrErr(key, "no such key: %v", key) 451 } 452 453 // Iterator produces a traits.Iterator which walks over the map keys. 454 // 455 // The Iterator is frequently used within comprehensions. 456 func (m *MapValue) Iterator() traits.Iterator { 457 keys := make([]ref.Val, len(m.fieldMap)) 458 i := 0 459 for k := range m.fieldMap { 460 keys[i] = types.String(k) 461 i++ 462 } 463 return &baseMapIterator{ 464 baseVal: &baseVal{}, 465 keys: keys, 466 } 467 } 468 469 // Size returns the number of keys in the map. 470 func (m *MapValue) Size() ref.Val { 471 return types.Int(len(m.Fields)) 472 } 473 474 // Type returns the CEL ref.Type for the map. 475 func (m *MapValue) Type() ref.Type { 476 return types.MapType 477 } 478 479 // Value returns the Go-native representation of the MapValue. 480 func (m *MapValue) Value() interface{} { 481 return m 482 } 483 484 type baseMapIterator struct { 485 *baseVal 486 keys []ref.Val 487 idx int 488 } 489 490 // HasNext implements the traits.Iterator interface method. 491 func (it *baseMapIterator) HasNext() ref.Val { 492 if it.idx < len(it.keys) { 493 return types.True 494 } 495 return types.False 496 } 497 498 // Next implements the traits.Iterator interface method. 499 func (it *baseMapIterator) Next() ref.Val { 500 key := it.keys[it.idx] 501 it.idx++ 502 return key 503 } 504 505 // Type implements the CEL ref.Val interface metohd. 506 func (it *baseMapIterator) Type() ref.Type { 507 return types.IteratorType 508 } 509 510 // NewField returns a MapField instance with an empty DynValue that refers to the 511 // specified parse node id and field name. 512 func NewField(id int64, name string) *Field { 513 return &Field{ 514 ID: id, 515 Name: name, 516 Ref: NewEmptyDynValue(), 517 } 518 } 519 520 // Field specifies a field name and a reference to a dynamic value. 521 type Field struct { 522 ID int64 523 Name string 524 Ref *DynValue 525 } 526 527 // NewListValue returns an empty ListValue instance. 528 func NewListValue() *ListValue { 529 return &ListValue{ 530 Entries: []*DynValue{}, 531 } 532 } 533 534 // ListValue contains a list of dynamically typed entries. 535 type ListValue struct { 536 Entries []*DynValue 537 initValueSet sync.Once 538 valueSet map[ref.Val]struct{} 539 } 540 541 // Add concatenates two lists together to produce a new CEL list value. 542 func (lv *ListValue) Add(other ref.Val) ref.Val { 543 oArr, isArr := other.(traits.Lister) 544 if !isArr { 545 return types.MaybeNoSuchOverloadErr(other) 546 } 547 szRight := len(lv.Entries) 548 szLeft := int(oArr.Size().(types.Int)) 549 sz := szRight + szLeft 550 combo := make([]ref.Val, sz) 551 for i := 0; i < szRight; i++ { 552 combo[i] = lv.Entries[i].ExprValue() 553 } 554 for i := 0; i < szLeft; i++ { 555 combo[i+szRight] = oArr.Get(types.Int(i)) 556 } 557 return types.DefaultTypeAdapter.NativeToValue(combo) 558 } 559 560 // Append adds another entry into the ListValue. 561 func (lv *ListValue) Append(entry *DynValue) { 562 lv.Entries = append(lv.Entries, entry) 563 // The append resets all previously built indices. 564 lv.initValueSet = sync.Once{} 565 } 566 567 // Contains returns whether the input `val` is equal to an element in the list. 568 // 569 // If any pair-wise comparison between the input value and the list element is an error, the 570 // operation will return an error. 571 func (lv *ListValue) Contains(val ref.Val) ref.Val { 572 if types.IsUnknownOrError(val) { 573 return val 574 } 575 lv.initValueSet.Do(lv.finalizeValueSet) 576 if lv.valueSet != nil { 577 _, found := lv.valueSet[val] 578 if found { 579 return types.True 580 } 581 // Instead of returning false, ensure that CEL's heterogeneous equality constraint 582 // is satisfied by allowing pair-wise equality behavior to determine the outcome. 583 } 584 var err ref.Val 585 sz := len(lv.Entries) 586 for i := 0; i < sz; i++ { 587 elem := lv.Entries[i] 588 cmp := elem.Equal(val) 589 b, ok := cmp.(types.Bool) 590 if !ok && err == nil { 591 err = types.MaybeNoSuchOverloadErr(cmp) 592 } 593 if b == types.True { 594 return types.True 595 } 596 } 597 if err != nil { 598 return err 599 } 600 return types.False 601 } 602 603 // ConvertToNative is an implementation of the CEL ref.Val method used to adapt between CEL types 604 // and Go-native array-like types. 605 func (lv *ListValue) ConvertToNative(typeDesc reflect.Type) (interface{}, error) { 606 // Non-list conversion. 607 if typeDesc.Kind() != reflect.Slice && 608 typeDesc.Kind() != reflect.Array && 609 typeDesc.Kind() != reflect.Interface { 610 return nil, fmt.Errorf("type conversion error from list to '%v'", typeDesc) 611 } 612 613 // If the list is already assignable to the desired type return it. 614 if reflect.TypeOf(lv).AssignableTo(typeDesc) { 615 return lv, nil 616 } 617 618 // List conversion. 619 otherElem := typeDesc.Elem() 620 621 // Allow the element ConvertToNative() function to determine whether conversion is possible. 622 sz := len(lv.Entries) 623 nativeList := reflect.MakeSlice(typeDesc, int(sz), int(sz)) 624 for i := 0; i < sz; i++ { 625 elem := lv.Entries[i] 626 nativeElemVal, err := elem.ConvertToNative(otherElem) 627 if err != nil { 628 return nil, err 629 } 630 nativeList.Index(int(i)).Set(reflect.ValueOf(nativeElemVal)) 631 } 632 return nativeList.Interface(), nil 633 } 634 635 // ConvertToType converts the ListValue to another CEL type. 636 func (lv *ListValue) ConvertToType(t ref.Type) ref.Val { 637 switch t { 638 case types.ListType: 639 return lv 640 case types.TypeType: 641 return types.ListType 642 } 643 return types.NewErr("type conversion error from '%s' to '%s'", ListType, t) 644 } 645 646 // Equal returns true if two lists are of the same size, and the values at each index are also 647 // equal. 648 func (lv *ListValue) Equal(other ref.Val) ref.Val { 649 oArr, isArr := other.(traits.Lister) 650 if !isArr { 651 return types.MaybeNoSuchOverloadErr(other) 652 } 653 sz := types.Int(len(lv.Entries)) 654 if sz != oArr.Size() { 655 return types.False 656 } 657 for i := types.Int(0); i < sz; i++ { 658 cmp := lv.Get(i).Equal(oArr.Get(i)) 659 if cmp != types.True { 660 return cmp 661 } 662 } 663 return types.True 664 } 665 666 // Get returns the value at the given index. 667 // 668 // If the index is negative or greater than the size of the list, an error is returned. 669 func (lv *ListValue) Get(idx ref.Val) ref.Val { 670 iv, isInt := idx.(types.Int) 671 if !isInt { 672 return types.ValOrErr(idx, "unsupported index: %v", idx) 673 } 674 i := int(iv) 675 if i < 0 || i >= len(lv.Entries) { 676 return types.NewErr("index out of bounds: %v", idx) 677 } 678 return lv.Entries[i].ExprValue() 679 } 680 681 // Iterator produces a traits.Iterator suitable for use in CEL comprehension macros. 682 func (lv *ListValue) Iterator() traits.Iterator { 683 return &baseListIterator{ 684 getter: lv.Get, 685 sz: len(lv.Entries), 686 } 687 } 688 689 // Size returns the number of elements in the list. 690 func (lv *ListValue) Size() ref.Val { 691 return types.Int(len(lv.Entries)) 692 } 693 694 // Type returns the CEL ref.Type for the list. 695 func (lv *ListValue) Type() ref.Type { 696 return types.ListType 697 } 698 699 // Value returns the Go-native value. 700 func (lv *ListValue) Value() interface{} { 701 return lv 702 } 703 704 // finalizeValueSet inspects the ListValue entries in order to make internal optimizations once all list 705 // entries are known. 706 func (lv *ListValue) finalizeValueSet() { 707 valueSet := make(map[ref.Val]struct{}) 708 for _, e := range lv.Entries { 709 switch e.value.(type) { 710 case bool, float64, int64, string, uint64, types.Null, PlainTextValue: 711 valueSet[e.ExprValue()] = struct{}{} 712 default: 713 lv.valueSet = nil 714 return 715 } 716 } 717 lv.valueSet = valueSet 718 } 719 720 type baseVal struct{} 721 722 func (*baseVal) ConvertToNative(typeDesc reflect.Type) (interface{}, error) { 723 return nil, fmt.Errorf("unsupported native conversion to: %v", typeDesc) 724 } 725 726 func (*baseVal) ConvertToType(t ref.Type) ref.Val { 727 return types.NewErr("unsupported type conversion to: %v", t) 728 } 729 730 func (*baseVal) Equal(other ref.Val) ref.Val { 731 return types.NewErr("unsupported equality test between instances") 732 } 733 734 func (v *baseVal) Value() interface{} { 735 return nil 736 } 737 738 type baseListIterator struct { 739 *baseVal 740 getter func(idx ref.Val) ref.Val 741 sz int 742 idx int 743 } 744 745 func (it *baseListIterator) HasNext() ref.Val { 746 if it.idx < it.sz { 747 return types.True 748 } 749 return types.False 750 } 751 752 func (it *baseListIterator) Next() ref.Val { 753 v := it.getter(types.Int(it.idx)) 754 it.idx++ 755 return v 756 } 757 758 func (it *baseListIterator) Type() ref.Type { 759 return types.IteratorType 760 } 761 762 func celBool(pred bool) ref.Val { 763 if pred { 764 return types.True 765 } 766 return types.False 767 } 768 769 var unknownType = &DeclType{name: "unknown", MinSerializedSize: 1}