Skip to content
CryoCryo home
Stdlibcore

iter

import std::core::iter; — in the prelude · source

Types

Iterator

type trait Iterator {
    type Item;
    next(mut &this) -> Option<This::Item>;
    count(mut &this) -> u64;
    fold<Acc>(mut &this, initial: Acc, f: (Acc, This::Item) -> Acc) -> Acc;
    for_each(mut &this, f: (This::Item) -> void) -> void;
    take(this, n: u64) -> TakeIter<This>;
    skip(this, n: u64) -> SkipIter<This>;
    map<B>(this, f: (This::Item) -> B) -> MapIter<This, B>;
    filter(this, pred: (&This::Item) -> boolean) -> FilterIter<This>;
    chain<J>(this, other: J) -> ChainIter<This, J>;
    enumerate(this) -> EnumerateIter<This>;
    zip<J>(this, other: J) -> ZipIter<This, J>;
    any(mut &this, pred: (This::Item) -> boolean) -> boolean;
    all(mut &this, pred: (This::Item) -> boolean) -> boolean;
    find(mut &this, pred: (&This::Item) -> boolean) -> Option<This::Item>;

    min(mut &this) -> Option<This::Item>
    where This::Item: Ord;

    max(mut &this) -> Option<This::Item>
    where This::Item: Ord;
}

Iterator has exactly one required method — next — and everything else is derived from it. for (x in seq) drives the scrutinee through this trait, so anything that implements it works in a for loop. Item is an associated type; implement Iterator<T> for X is positional sugar for binding it.

type struct Counter { n: i32; }

implement trait Iterator<i32> for struct Counter {
    next(mut &this) -> Option<i32> {
        if (this.n >= 5) { return Option::<i32>::None; }
        this.n = this.n + 1;
        return Option::<i32>::Some(this.n);
    }
}

mut c: Counter = Counter { n: 0 };
for (v in c.take(3)) { println(f"{v}"); }

Associated types

TypeNotes
ItemThe element type this iterator yields. Each implementor binds it once (positional sugar: implement Iterator<T> for X => Item = T); refer to it as This::Item inside the trait and X::Item outside.

Methods

next(mut &this) -> Option<This::Item>;

Advance the sequence and return the next value, or None when exhausted. Calling next again after None may return None forever or may panic; implementations should document which.

count(mut &this) -> u64;

Number of remaining elements. The default walks the iterator to count, consuming it. Implementations with O(1) knowledge of their length should override.

fold<Acc>(mut &this, initial: Acc, f: (Acc, This::Item) -> Acc) -> Acc;

Reduce the sequence to a single value. initial is the starting accumulator; f folds each element into it.

for_each(mut &this, f: (This::Item) -> void) -> void;

Call f on each element, discarding the results. The natural way to consume an iterator purely for its side effects.

take(this, n: u64) -> TakeIter<This>;

Yield at most the first n elements, then stop.

skip(this, n: u64) -> SkipIter<This>;

Discard the first n elements, then yield the rest. An iterator with fewer than n elements is drained and yields nothing.

map<B>(this, f: (This::Item) -> B) -> MapIter<This, B>;

Transform each element with f, yielding the results. f must be a non-capturing function (a plain fn or a non-capturing lambda).

filter(this, pred: (&This::Item) -> boolean) -> FilterIter<This>;

Yield only the elements for which pred returns true. pred must be a non-capturing function. It BORROWS each element: the element it keeps is the one yielded, so it cannot also be handed to pred.

chain<J>(this, other: J) -> ChainIter<This, J>;

Yield every element of this, then every element of other. other must be an Iterator with the same Item type - the shared element type is enforced by ChainIter's impl bounds.

enumerate(this) -> EnumerateIter<This>;

Yield (index, value) pairs, the index counting up from 0 as a u64. The pair is Pair<u64, Item>: p.first is the index, p.second the element. (Cryo has no heterogeneous tuple literal, so Pair is the element type.)

zip<J>(this, other: J) -> ZipIter<This, J>;

Yield pairs (a, b) drawing a from this and b from other, stopping as soon as either iterator is exhausted. The pair is Pair<Item, B> where B is other's element type: p.first comes from this, p.second from other. (Cryo has no heterogeneous tuple literal, so Pair is the element type.)

any(mut &this, pred: (This::Item) -> boolean) -> boolean;

True if pred holds for at least one element. Short-circuits on the first match; consumes elements up to it.

all(mut &this, pred: (This::Item) -> boolean) -> boolean;

True if pred holds for every element. Short-circuits on the first failure; vacuously true for an empty iterator.

find(mut &this, pred: (&This::Item) -> boolean) -> Option<This::Item>;

The first element for which pred holds, or None. Consumes elements up to and including the match. pred borrows each element, since the one it accepts is returned.

min(mut &this) -> Option<This::Item> where This::Item: Ord;

The smallest element by Ord, or None for an empty iterator. Consumes the iterator. On ties the FIRST minimal element wins (only a strictly smaller element displaces the running best), so min and max of equal elements differ. Available only where the element type is Ord - the where This::Item: Ord associated-type projection bound; adapters whose element is never Ord (e.g. enumerate/zip, which yield Pair) do not carry it.

max(mut &this) -> Option<This::Item> where This::Item: Ord;

The largest element by Ord, or None for an empty iterator. Consumes the iterator. On ties the LAST maximal element wins (an equal-or-greater element displaces the running best), the mirror of min.

Lazy adapters

Each of these returns a wrapper that is itself an Iterator, so they compose. Nothing is computed until something consumes the chain.

take and skip cut the front of the sequence, map and filter transform and select, chain runs a second iterator of the same Item after the first, and enumerate and zip pair each element with its index or with another iterator's element — stopping when either side runs out.

f and pred must be non-capturing — a plain function or a non-capturing lambda.

enumerate and zip yield Pair rather than a tuple because Cryo has no heterogeneous tuple literal.

The adapter types

type struct TakeIter<I> {
    inner:     I;
    remaining: u64;

    static new(inner: I, n: u64) -> TakeIter<I>;
}

type struct SkipIter<I> {
    inner:     I;
    remaining: u64;

    static new(inner: I, n: u64) -> SkipIter<I>;
}

type struct MapIter<I, O> where I: Iterator {
    inner: I;

    f: (I::Item) -> O;
    static new(inner: I, f: (I::Item) -> O) -> MapIter<I, O>;
}

type struct FilterIter<I> where I: Iterator {
    inner: I;

    pred: (&I::Item) -> boolean;
    static new(inner: I, pred: (&I::Item) -> boolean) -> FilterIter<I>;
}

type struct ChainIter<I, J> {
    first:      I;
    second:     J;
    first_done: boolean;

    static new(first: I, second: J) -> ChainIter<I, J>;
}

type struct EnumerateIter<I> {
    inner: I;
    index: u64;

    static new(inner: I) -> EnumerateIter<I>;
}

type struct ZipIter<I, J> {
    first:  I;
    second: J;

    static new(first: I, second: J) -> ZipIter<I, J>;
}

The wrappers the adapters return are public structs, so you can name one in a signature when the opaque implement Iterator<T> is not enough. Each is an Iterator in turn; their impls are listed under Implementors.

Eager consumers

count, fold, and for_each walk the whole iterator; any, all, and find short-circuit; the predicates of filter and find borrow the element ((&Item) -> boolean) rather than consuming it, so the element they keep is still whole; min and max need Item: Ord and return None on an empty sequence.

On ties min keeps the first minimal element and max keeps the last maximal one, matching the conventional behaviour.

The adapters resolve on any concrete Iterator receiver, including your own structs. Re-adapting a local whose type is the opaque implement Iterator<T> works when its initialiser is a concrete constructor (mut it: implement Iterator<i32> = Range::<i32>::new(0, 10); it.take(3)); a local initialised from a producer that itself returns an opaque iterator is still restricted, so chain directly off the source in that case.

Implementors

Every iterator in the library, including the adapters above and the by-reference cursors the containers hand out:

implement<I, A> trait Iterator<A> for struct TakeIter<I> where I: Iterator<A>
implement<I, A> trait Iterator<A> for struct SkipIter<I> where I: Iterator<A>
implement<I, O> trait Iterator<O> for struct MapIter<I, O> where I: Iterator
implement<I> trait Iterator<I::Item> for struct FilterIter<I> where I: Iterator
implement<I, J, A> trait Iterator<A> for struct ChainIter<I, J> where I: Iterator<A>, J: Iterator<A>
implement<I> trait Iterator<Pair<u64, I::Item>> for struct EnumerateIter<I> where I: Iterator
implement<I, J, A, O> trait Iterator<Pair<A, O>> for struct ZipIter<I, J> where I: Iterator<A>, J: Iterator<O>
implement<T> trait Iterator<T*> for struct RefIter<T>
std::collections::array
implement<I, T> trait Iterator<T> for struct CopiedIter<I> where I: Iterator<T*>, T: Copy
std::collections::array
implement<I, T> trait Iterator<T> for struct ClonedIter<I> where I: Iterator<T*>, T: Clone
std::collections::array
implement<K, V> trait Iterator<Pair<K, V>> for struct HashMapIter<K, V> where K: Copy, V: Copy
std::collections::hashmap
implement<K, V> trait Iterator<K> for struct KeysIter<K, V>
std::collections::hashmap
implement<K, V> trait Iterator<V> for struct ValuesIter<K, V>
std::collections::hashmap
implement<K, V> trait Iterator<Pair<K*, V*>> for struct EntriesRefIter<K, V>
std::collections::hashmap
implement<K, V> trait Iterator<K*> for struct KeysRefIter<K, V>
std::collections::hashmap
implement<K, V> trait Iterator<V*> for struct ValuesRefIter<K, V>
std::collections::hashmap
implement<T> trait Iterator<T> for struct HashSetIter<T> where T: Copy
std::collections::hashset
implement<T> trait Iterator<T*> for struct HashSetRefIter<T>
std::collections::hashset
implement trait Iterator<Str> for struct SplitIter
std::collections::str
implement trait Iterator<u32> for struct Chars
std::collections::str
implement trait Iterator<Pair<u64, u32>> for struct CharIndices
std::collections::str
implement<T> trait Iterator<T> for struct Range<T> where T: Step
std::core::ops
implement<T> trait Iterator<T> for struct RangeInclusive<T> where T: Step
std::core::ops
implement<T> trait Iterator<T> for struct SliceIter<T>
std::core::slice
implement trait Iterator<DirEntry> for struct ReadDir
std::fs::dir