mirror of
https://github.com/go-sylixos/elvish.git
synced 2024-12-04 10:57:50 +08:00
64 lines
1.6 KiB
Go
64 lines
1.6 KiB
Go
package vals
|
|
|
|
// Iterator wraps the Iterate method.
|
|
type Iterator interface {
|
|
// Iterate calls the passed function with each value within the receiver.
|
|
// The iteration is aborted if the function returns false.
|
|
Iterate(func(v any) bool)
|
|
}
|
|
|
|
type cannotIterate struct{ kind string }
|
|
|
|
func (err cannotIterate) Error() string { return "cannot iterate " + err.kind }
|
|
|
|
// CanIterate returns whether the value can be iterated. If CanIterate(v) is
|
|
// true, calling Iterate(v, f) will not result in an error.
|
|
func CanIterate(v any) bool {
|
|
switch v.(type) {
|
|
case Iterator, string, List:
|
|
return true
|
|
}
|
|
return false
|
|
}
|
|
|
|
// Iterate iterates the supplied value, and calls the supplied function in each
|
|
// of its elements. The function can return false to break the iteration. It is
|
|
// implemented for the builtin type string, the List type, and types satisfying
|
|
// the Iterator interface. For these types, it always returns a nil error. For
|
|
// other types, it doesn't do anything and returns an error.
|
|
func Iterate(v any, f func(any) bool) error {
|
|
switch v := v.(type) {
|
|
case string:
|
|
for _, r := range v {
|
|
b := f(string(r))
|
|
if !b {
|
|
break
|
|
}
|
|
}
|
|
case List:
|
|
for it := v.Iterator(); it.HasElem(); it.Next() {
|
|
if !f(it.Elem()) {
|
|
break
|
|
}
|
|
}
|
|
case Iterator:
|
|
v.Iterate(f)
|
|
default:
|
|
return cannotIterate{Kind(v)}
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// Collect collects all elements of an iterable value into a slice.
|
|
func Collect(it any) ([]any, error) {
|
|
var vs []any
|
|
if len := Len(it); len >= 0 {
|
|
vs = make([]any, 0, len)
|
|
}
|
|
err := Iterate(it, func(v any) bool {
|
|
vs = append(vs, v)
|
|
return true
|
|
})
|
|
return vs, err
|
|
}
|