package miter import ( "context" "errors" ) // Empty returns the empty Iterator, i.e. one which will immediately produce // ErrEnd. func Empty[T any]() Iterator[T] { return Error[T](ErrEnd) } // ForEach calls fn with each item read off the iterator, returning nil once // ErrEnd is returned from the Iterator or function. If the Iterator or function // return any other error then that is returned instead. func ForEach[T any]( ctx context.Context, i Iterator[T], fn func(T) error, ) error { for { v, err := i.Next(ctx) if errors.Is(err, ErrEnd) { return nil } else if err != nil { return err } if err := fn(v); errors.Is(err, ErrEnd) { return nil } else if err != nil { return err } } } // Map will read items from the given Iterator, pass them through the given // mapping function, and produce the mapped items from the returned Iterator. // // If the mapping function returns an error then that is returned from returned // Iterator, and no more calls should be made to it. func Map[T1, T2 any](i Iterator[T1], fn func(T1) (T2, error)) Iterator[T2] { return FromFunc(func(ctx context.Context) (T2, error) { v, err := i.Next(ctx) if err != nil { var zero T2 return zero, err } return fn(v) }) } // Concat concats all the given Iterators together into a single larger one. // Each Iterator will be consumed until ErrEnd in turn. Any other errors from // the inner Iterators will be returned as-is from the outer one. func Concat[T any](iters ...Iterator[T]) Iterator[T] { var ( i int zero T ) return FromFunc(func(ctx context.Context) (T, error) { for { if i >= len(iters) { return zero, ErrEnd } v, err := iters[i].Next(ctx) if errors.Is(err, ErrEnd) { i++ continue } return v, err } }) } // Filter returns an Iterator which will produce all items from the given // Iterator for which the function returns true. If the function returns any // error then that error is returned as-is. func Filter[T any]( i Iterator[T], fn func(context.Context, T) (bool, error), ) Iterator[T] { var zero T return FromFunc(func(ctx context.Context) (T, error) { for { v, err := i.Next(ctx) if err != nil { return zero, err } keep, err := fn(ctx, v) if err != nil { return zero, err } if keep { return v, nil } } }) }