github.com/elves/elvish@v0.15.0/pkg/eval/vals/has_key.go (about) 1 package vals 2 3 import ( 4 "reflect" 5 6 "github.com/xiaq/persistent/hashmap" 7 ) 8 9 // HasKeyer wraps the HasKey method. 10 type HasKeyer interface { 11 // HasKey returns whether the receiver has the given argument as a valid 12 // key. 13 HasKey(interface{}) bool 14 } 15 16 // HasKey returns whether a container has a key. It is implemented for the Map 17 // type, StructMap types, and types satisfying the HasKeyer interface. It falls 18 // back to iterating keys using IterateKeys, and if that fails, it falls back to 19 // calling Len and checking if key is a valid numeric or slice index. Otherwise 20 // it returns false. 21 func HasKey(container, key interface{}) bool { 22 switch container := container.(type) { 23 case HasKeyer: 24 return container.HasKey(key) 25 case Map: 26 return hashmap.HasKey(container, key) 27 case StructMap: 28 return hasKeyStructMap(container, key) 29 case PseudoStructMap: 30 return hasKeyStructMap(container.Fields(), key) 31 default: 32 var found bool 33 err := IterateKeys(container, func(k interface{}) bool { 34 if key == k { 35 found = true 36 } 37 return !found 38 }) 39 if err == nil { 40 return found 41 } 42 if len := Len(container); len >= 0 { 43 // TODO(xiaq): Not all types that implement Lener have numerical 44 // indices 45 _, err := ConvertListIndex(key, len) 46 return err == nil 47 } 48 return false 49 } 50 } 51 52 func hasKeyStructMap(m StructMap, k interface{}) bool { 53 kstring, ok := k.(string) 54 if !ok || kstring == "" { 55 return false 56 } 57 for _, fieldName := range getStructMapInfo(reflect.TypeOf(m)).fieldNames { 58 if fieldName == kstring { 59 return true 60 } 61 } 62 return false 63 }