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

     1  package vals
     2  
     3  // Iterator wraps the Iterate method.
     4  type Iterator interface {
     5  	// Iterate calls the passed function with each value within the receiver.
     6  	// The iteration is aborted if the function returns false.
     7  	Iterate(func(v interface{}) bool)
     8  }
     9  
    10  type cannotIterate struct{ kind string }
    11  
    12  func (err cannotIterate) Error() string { return "cannot iterate " + err.kind }
    13  
    14  // CanIterate returns whether the value can be iterated. If CanIterate(v) is
    15  // true, calling Iterate(v, f) will not result in an error.
    16  func CanIterate(v interface{}) bool {
    17  	switch v.(type) {
    18  	case Iterator, string, List:
    19  		return true
    20  	}
    21  	return false
    22  }
    23  
    24  // Iterate iterates the supplied value, and calls the supplied function in each
    25  // of its elements. The function can return false to break the iteration. It is
    26  // implemented for the builtin type string, the List type, and types satisfying
    27  // the Iterator interface. For these types, it always returns a nil error. For
    28  // other types, it doesn't do anything and returns an error.
    29  func Iterate(v interface{}, f func(interface{}) bool) error {
    30  	switch v := v.(type) {
    31  	case string:
    32  		for _, r := range v {
    33  			b := f(string(r))
    34  			if !b {
    35  				break
    36  			}
    37  		}
    38  	case List:
    39  		for it := v.Iterator(); it.HasElem(); it.Next() {
    40  			if !f(it.Elem()) {
    41  				break
    42  			}
    43  		}
    44  	case Iterator:
    45  		v.Iterate(f)
    46  	default:
    47  		return cannotIterate{Kind(v)}
    48  	}
    49  	return nil
    50  }
    51  
    52  // Collect collects all elements of an iterable value into a slice.
    53  func Collect(it interface{}) ([]interface{}, error) {
    54  	var vs []interface{}
    55  	if len := Len(it); len >= 0 {
    56  		vs = make([]interface{}, 0, len)
    57  	}
    58  	err := Iterate(it, func(v interface{}) bool {
    59  		vs = append(vs, v)
    60  		return true
    61  	})
    62  	return vs, err
    63  }