=begin pod

=TITLE role Iterator

=SUBTITLE Generic API for producing a sequence of values

    constant IterationEnd
    role Iterator { }

A C<Iterator> is an object that can generate or provide elements of a
sequence. Users usually don't have to care about iterators, their usage
is hidden behind iteration APIs such as C<for @list { }>, L<map>, L<grep>
and list indexing with C<.[$idx]>.

Iterators generally only allow one iteration over the sequence; afterwards
they are exhausted.

The main API is the C<pull-one> method, which either returns the next value,
or the sentinel value C<IterationEnd> if no more elements are available. Each
class implementing C<Iterator> must provide a C<pull-one> method. All other
Iterator API methods can be implemented in terms of C<pull-one>, but also
overridden for performance reasons.

Note: The only valid use of the sentinel value C<IterationEnd> in a program
is identity comparison (using C<=:=>) with the result of a method in the
iterator API. Any other behavior is undefined and implementation dependent.

=head1 Methods

=head2 method pull-one

Defined as:

    method pull-one(Iterator:D:) returns Mu { ... }

Usage:

    ITERATOR.pull-one

This method stub ensures that classes implementing the C<Iterator> role
provide a method named C<pull-one>.

The C<pull-one> method is supposed to return the next value if available, or
the sentinel value C<IterationEnd> if no more elements are available.

=head2 method push-exactly

Defined as:

    method push-exactly(Iterator:D: $target, int $count) returns Mu

Usage:

    ITERATOR.push-exactly(TARGET, COUNT)

Produces C<$count> elements, and for each of them, calls
C<$target.push($value)>.

If fewer than C<$count> elements are available from the iterator, it
returns the sentinel value C<IterationEnd>. Otherwise it returns
C<$count>.

=head2 method push-at-least

Defined as:

    method push-at-least(Iterator:D: $target, int $count) returns Mu

Usage:

    ITERATOR.push-at-least(TARGET, COUNT)

Produces at least C<$count> elements, and for each of them, calls
C<$target.push($value)>.

If fewer than C<$count> elements are available from the iterator, it
returns the sentinel value C<IterationEnd>. Otherwise it returns
C<$count>.

Iterators with side effects should produce exactly C<$count> elements;
iterators without side effects (such as L<Range|/type/Range> iterators) can
produce more elements to achieve better performance.

=head2 method push-all

Defined as:

    method push-all(Iterator:D: $target)

Usage:

    ITERATOR.push-all(TARGET)

Produces all elements from the iterator and pushes them to C<$target>.

The fallback is implemented in terms of repeated C<push-at-least> with a large
C<$count>.

=head2 method push-until-lazy

Defined as:

    method push-until-lazy(Iterator:D: $target) returns Mu

Usage:

    ITERATOR.push-until-lazy(TARGET)

Produces values until it considers itself to be lazy, and pushes them onto
C<$target>.

This matters mostly for iterators that have other iterators embedded, some of
which might be lazy, while others aren't.

=head2 method is-lazy

Defined as:

    method is-lazy(Iterator:D:) returns Bool:D

Usage:

    ITERATOR.is-lazy

Returns C<True> for iterators that consider themselves lazy, and C<False>
otherwise.

Built-in operations that know that they can produce infinitely many values
return C<True> here, for example C<(1..6).roll(*)>.

=head2 method count-only

Defined as:

    method count-only(Iterator:D:) returns int

Usage:

    ITERATOR.count-only

Produces and discards all elements until it returns the end of the iteration,
and returns the number of elements produced. This is useful to reduce memory
usage in scenarios such as C<open($file).lines.elems>.

=head2 method sink-all

Defined as:

    method sink-all(Iterator:D:)

Usage:

    ITERATOR.sink-all

Exhausts the iterator (while discarding generated elements) purely for the
side effects of the iteration.

=end pod
