github.com/elves/elvish@v0.15.0/pkg/eval/vals/iterate_keys.go (about)

     1  package vals
     2  
     3  import (
     4  	"reflect"
     5  )
     6  
     7  // KeysIterator wraps the IterateKeys method.
     8  type KeysIterator interface {
     9  	// IterateKeys calls the passed function with each key within the receiver.
    10  	// The iteration is aborted if the function returns false.
    11  	IterateKeys(func(v interface{}) bool)
    12  }
    13  
    14  type cannotIterateKeysOf struct{ kind string }
    15  
    16  func (err cannotIterateKeysOf) Error() string {
    17  	return "cannot iterate keys of " + err.kind
    18  }
    19  
    20  // IterateKeys iterates the keys of the supplied value, calling the supplied
    21  // function for each key. The function can return false to break the iteration.
    22  // It is implemented for the Map type, StructMap types, and types satisfying the
    23  // IterateKeyser interface. For these types, it always returns a nil error. For
    24  // other types, it doesn't do anything and returns an error.
    25  func IterateKeys(v interface{}, f func(interface{}) bool) error {
    26  	switch v := v.(type) {
    27  	case KeysIterator:
    28  		v.IterateKeys(f)
    29  	case Map:
    30  		for it := v.Iterator(); it.HasElem(); it.Next() {
    31  			k, _ := it.Elem()
    32  			if !f(k) {
    33  				break
    34  			}
    35  		}
    36  	case StructMap:
    37  		iterateKeysStructMap(v, f)
    38  	case PseudoStructMap:
    39  		iterateKeysStructMap(v.Fields(), f)
    40  	default:
    41  		return cannotIterateKeysOf{Kind(v)}
    42  	}
    43  	return nil
    44  }
    45  
    46  func iterateKeysStructMap(v StructMap, f func(interface{}) bool) {
    47  	for _, k := range getStructMapInfo(reflect.TypeOf(v)).fieldNames {
    48  		if k == "" {
    49  			continue
    50  		}
    51  		if !f(k) {
    52  			break
    53  		}
    54  	}
    55  }