Programming Language

Nocter

A self-contained systems language built around simplicity, encapsulation, and foolproof design.

/std/iter/index.nct

index.nct

//! Core iteration contracts, source iterators, and lazy adapters.
//!
//! Adapters retain their sources and callbacks. ViewIter retains the source
//! view itself so element borrows preserve the view's storage origin.

see ./core.nct
see ./defaults.nct
see ./mutable.nct
see ./sources.nct
see ./adapters.nct

/// Lazily transforms items from an owning source iterator.
pub struct MapIter<U, I, F>

/// Lazily retains items from an owning source iterator.
pub struct FilterIter<I, F>

/// Yields at most `remaining` items from `source`.
pub struct TakeIter<I>

/// Discards at most `remaining_to_skip` source items before yielding.
pub struct SkipIter<I>

/// Yields every left item before every right item.
pub struct ChainIter<L, R>

/// One indexed item yielded by `EnumerateIter`.
pub struct Indexed<T> {
    /// Zero-based position in the source iterator.
    pub index: usize

    /// Item yielded at `index`.
    pub item: T
}

/// An owning iterator that pairs every item with its zero-based index.
pub struct EnumerateIter<I>

/// Owned state passed to a folding callback.
pub struct FoldStep<T, U> {
    /// Accumulator produced by the preceding fold step.
    pub accumulator: U

    /// Next source item to combine into the accumulator.
    pub item: T
}

/// Advances a mutable iterator and returns one item, or `none` at exhaustion.
pub interface Iterator {
    /// Value yielded by one successful advance.
    pub type Item

    /// Advances the iterator and returns the next item, or `none` at exhaustion.
    pub method &+self.next(): Self.Item?

    /// Lazily transforms every yielded item.
    pub noalloc default method self.map<U, F>(transform: F): MapIter<U, Self, F> from self | transform where F: &+func(item: Self.Item): U

    /// Lazily retains items accepted by `predicate`.
    pub noalloc default method self.filter<F>(predicate: F): FilterIter<Self, F> from self | predicate where F: &+func(&Self.Item): bool

    /// Lazily yields at most `limit` items.
    pub noalloc default method self.take(limit: usize): TakeIter<Self>

    /// Lazily discards at most `count` items before yielding.
    pub noalloc default method self.skip(amount: usize): SkipIter<Self>

    /// Lazily yields this iterator followed by `right`.
    pub noalloc default method self.chain<R>(right: R): ChainIter<Self, R> from self | right where R impl Iterator { .Item = Self.Item }

    /// Lazily pairs every yielded item with its zero-based index.
    pub noalloc default method self.enumerate(): EnumerateIter<Self>

    /// Consumes the iterator and returns the number of yielded items.
    pub default method self.count(): usize

    /// Consumes the iterator and returns its last item, or `none`.
    pub default method self.last(): Self.Item? from self

    /// Returns the first item accepted by `predicate`, or `none`.
    pub default method self.find<F>(predicate: F): Self.Item? from self where F: &+func(&Self.Item): bool

    /// Returns true when `predicate` accepts any yielded item.
    pub default method self.any<F>(predicate: F): bool where F: &+func(&Self.Item): bool

    /// Returns true when `predicate` accepts every yielded item.
    pub default method self.all<F>(predicate: F): bool where F: &+func(&Self.Item): bool

    /// Consumes the iterator and returns whether it yields an equal item.
    pub default method self.contains<T>(expected: &T): bool where Self impl Iterator { .Item = T }, (&T == &T): bool

    /// Consumes the iterator and returns the index of its first equal item.
    pub default method self.position<T>(expected: &T): usize? where Self impl Iterator { .Item = T }, (&T == &T): bool

    /// Reduces every item into one accumulator value.
    pub default method self.fold<U, F>(
        initial: U,
        combine: F,
    ): U from self | initial | combine where F: &+func(step: FoldStep<Self.Item, U>): U
}

/// Reports the exact number of values that the iterator has not yielded yet.
pub interface ExactSizeIterator where Self impl Iterator {
    /// Returns the exact number of items not yet yielded.
    pub method &self.remaining_len(): usize
}

instance MapIter<U, I, F> where I impl Iterator, F: &+func(item: I.Item): U {
    impl Iterator { .Item = U }
}

instance MapIter<U, I, F> where I impl ExactSizeIterator, F: &+func(item: I.Item): U {
    impl ExactSizeIterator
}

instance FilterIter<I, F> where I impl Iterator, F: &+func(&I.Item): bool {
    impl Iterator { .Item = I.Item }
}

instance TakeIter<I> where I impl Iterator {
    impl Iterator { .Item = I.Item }
}

instance TakeIter<I> where I impl ExactSizeIterator {
    impl ExactSizeIterator
}

instance SkipIter<I> where I impl Iterator {
    impl Iterator { .Item = I.Item }
}

instance SkipIter<I> where I impl ExactSizeIterator {
    impl ExactSizeIterator
}

instance ChainIter<L, R> where L impl Iterator, R impl Iterator { .Item = L.Item } {
    impl Iterator { .Item = L.Item }
}

instance EnumerateIter<I> where I impl Iterator {
    impl Iterator { .Item = Indexed<I.Item> }
}

instance EnumerateIter<I> where I impl ExactSizeIterator {
    impl ExactSizeIterator
}

/// An iterator that never yields an item.
pub struct EmptyIter<T>

instance EmptyIter<T> {
    impl ExactSizeIterator
    impl Iterator { .Item = T }
}

/// An iterator that owns at most one unconsumed item.
pub struct OnceIter<T>

instance OnceIter<T> {
    impl ExactSizeIterator
    impl Iterator { .Item = T }
}

/// Creates an iterator that yields no items.
pub noalloc func empty<T>(): EmptyIter<T>

/// Creates an iterator that yields `item` exactly once.
pub noalloc func once<T>(item: T): OnceIter<T>

/// A forward cursor over readonly borrows into contiguous storage.
pub struct ViewIter<T>

/// A forward cursor over readwrite borrows into contiguous storage.
pub struct MutableViewIter<T>

instance MutableViewIter<T> {
    impl ExactSizeIterator
    impl Iterator { .Item = &+T }
}

construct MutableViewIter<T> {
    /// Creates an allocation-free mutable iterator over `view`.
    pub noalloc func from_view(view: &+[T]): Self
}

construct ViewIter<T> {
    /// Creates an allocation-free readonly iterator over `view`.
    pub noalloc func from_view(view: &[T]): Self
}

instance ViewIter<T> {
    impl ExactSizeIterator
    impl Iterator { .Item = &T }
}