src.elv.sh@v0.21.0-dev.0.20240515223629-06979efb9a2a/pkg/eval/vals/index.go (about) 1 package vals 2 3 import ( 4 "errors" 5 "os" 6 ) 7 8 // Indexer wraps the Index method. 9 type Indexer interface { 10 // Index retrieves the value corresponding to the specified key in the 11 // container. It returns the value (if any), and whether it actually exists. 12 Index(k any) (v any, ok bool) 13 } 14 15 // ErrIndexer wraps the Index method. 16 type ErrIndexer interface { 17 // Index retrieves one value from the receiver at the specified index. 18 Index(k any) (any, error) 19 } 20 21 var errNotIndexable = errors.New("not indexable") 22 23 type noSuchKeyError struct { 24 key any 25 } 26 27 // NoSuchKey returns an error indicating that a key is not found in a map-like 28 // value. 29 func NoSuchKey(k any) error { 30 return noSuchKeyError{k} 31 } 32 33 func (err noSuchKeyError) Error() string { 34 return "no such key: " + ReprPlain(err.key) 35 } 36 37 // Index indexes a value with the given key. It is implemented for the builtin 38 // type string, *os.File, List, StructMap and PseudoStructMap types, and types 39 // satisfying the ErrIndexer or Indexer interface (the Map type satisfies 40 // Indexer). For other types, it returns a nil value and a non-nil error. 41 func Index(a, k any) (any, error) { 42 convertResult := func(v any, ok bool) (any, error) { 43 if !ok { 44 return nil, NoSuchKey(k) 45 } 46 return v, nil 47 } 48 switch a := a.(type) { 49 case string: 50 return indexString(a, k) 51 case *os.File: 52 return indexFile(a, k) 53 case ErrIndexer: 54 return a.Index(k) 55 case Indexer: 56 return convertResult(a.Index(k)) 57 case List: 58 return indexList(a, k) 59 case StructMap: 60 return convertResult(indexStructMap(a, k)) 61 case PseudoMap: 62 return convertResult(indexStructMap(a.Fields(), k)) 63 default: 64 return nil, errNotIndexable 65 } 66 } 67 68 func indexFile(f *os.File, k any) (any, error) { 69 switch k { 70 case "fd": 71 return int(f.Fd()), nil 72 case "name": 73 return f.Name(), nil 74 } 75 return nil, NoSuchKey(k) 76 } 77 78 func indexStructMap(a StructMap, k any) (any, bool) { 79 fieldName, ok := k.(string) 80 if !ok || fieldName == "" { 81 return nil, false 82 } 83 for it := iterateStructMap(a); it.HasElem(); it.Next() { 84 k, v := it.elem() 85 if k == fieldName { 86 return FromGo(v), true 87 } 88 } 89 return nil, false 90 }