kompost 0.0.2

A crate to easen functional programming in rust by facilitating the creating composition of Iterator methods and anonymous Iterators—all without writing any trait or struct, without macros or unsafe code.
Documentation
# Kompost

🚧🚧🚧🚧🚧 **Under construction** 🚧🚧🚧🚧🚧

A crate to ease functional programming in rust by facilitating
the composability and re-usability of Iterator methods and anonymous
Iterators—all without writing any trait or struct, without using macros
or unsafe code.

## Anonymous iterators

Adding a method to `Iterator` requires boilerplate in Rust—just have a look
at [`src/anonymous.rs`]:

- A Struct that holds a state (e.g., the parent iterator)
- A Constructor
- The implementation of `Iterator` for the struct
- A trait that defines the method
- A blanket implementation of that trait for all `Iterator`s.

This crate provides convenience by offering anonymous Iterators
that are defined by two closures only.

As all `Iterator`s, they are defined by their behavior during creation and in
the next method. The former is given by a closure that receives the current
[`Iterator`] and returns a context structure. The second closure
then computes the next value from the context and has mutable access to this context.
Hence, the `anonymous()` method strongly resembles `Iterator::scan()` with the notable
exception that the first parameter is a closure.

```rust
use kompost::*;

assert_eq!(
    vec![1,2,3]
        .into_iter()
        .anonymous(
            |it| it.into_iter(),
            |it| it.next()
        )
        .collect::<Vec<_>>(),
    vec![1,2,3]
);
```

A slightly more complex idea is to collect the iterator first and define
a custom behavior.

```rust
assert_eq!(
    [1, 2, 3]
        .iter()                      // Don't consume
        .anonymous(
            |it| it
                .into_iter()
                .rev()               // Revert
                .copied()            
                .collect::<Vec<_>>()
                .into_iter(),        // We need an iterator in next
            |it| it.next().map(|x| x + 4)
        )
        .collect::<Vec<_>>(),
    vec![7, 6, 5]
);
```

This enables more complex tasks. For instance, we can transpose a nested iterable
structure ([`IntoIterator`]`<Item =` [`IntoIterator`]`<_>>`) without the need of
writing a single struct or trait! The example is annotated with the inline type
hints as shown by [rust-analyzer lsp](https://rust-analyzer.github.io/):

```rust
let x: Vec<_> = [1, 2, 3, 4]                 // An array in row-major order
    .chunks(2)                               // Nested iterable: Chunks<i32>
    .anonymous(
        |chunks| chunks.map(|row| row.iter()).collect::<Vec<_>>(),
        |context| {
            let transposed = context         // &mut Vec<Iter,i32>
                .iter_mut()
                .filter_map(|i| i.next())    // impl Iterator<Item = &i32>
                .collect::<Vec<_>>();        // Vec<&i32>
                                             // If the iterators over the rows return `None`, transpose is empty
            if transposed.is_empty() {
                None
            } else {
                Some(transposed.into_iter())
            }
        },
    )                                        // AnonymousIterator
    .flatten()                               // impl Iterator<Item = &i32>
    .copied()                                // impl Iterator<Item = i32>
    .collect();
assert_eq!(x, [1, 3, 2, 4]);
```

This can be conveniently "bundled" in a function—[`transpose()`](crate::transpose)
to be used with the [`composed()`](crate::ComposedIterable::composed) from this crate.

## Composed iterators

Iterator composition allows defining reusable groups of frequently used combinations of [`Iterator`]
methods (such as `map` or `scan`) that can be easily tested.

A very simple example might look like:

```rust
use kompost::ComposedIterable;
    fn favorite_pipeline(it: impl Iterator<Item = i32>) -> impl Iterator<Item = f64> {
    it.skip(5)
        .map(|x| x.pow(2))
        .take_while(|x| *x < 100)
        .map(|x| x as f64)
}
assert_eq!(
    [1, 2, 3, 4, 5, 6, 7].into_iter().composed(favorite_pipeline).collect::<Vec<_>>(),
    vec![36.0f64, 49.0]
)
```

`Kompost` comes with a few useful (at least to me), predefined compound functions such as
`transpose` and `periodic_windows()`.

The letter shows a few interesting aspects: How a compound function can accept an additional parameter,
how stricter type restrictions can be enforced (`ExactSizeIterator`), and a more advanced showcase
of the `anonymous()` method.

```rust
pub fn periodic_windows<T>(
    size: usize,
    it: impl ExactSizeIterator<Item = T> + Clone,
) -> impl Iterator<Item = impl Iterator<Item = T>> {
    it.anonymous(
        |it| {
            let len = it.len();
            (0usize, len, it.cycle())
        },
        move |(i, len, it)| {
            let window = it.clone();
            it.next();
            *i += 1;
            if i <= len {
                Some(window.take(size))
            } else {
                None
            }
        },
    )
}
```

The compound function can then be easily applied:

```rust
let size=3;
let x = [1, 2, 3, 4].into_iter()
    .composed(|i| periodic_windows(3, i))
    .flatten()
    .collect::<Vec<_>>();
assert_eq!(x, [1,2,3,2,3,4,3,4,1,4,1,2])
```