Trait pushgen::traits::GeneratorExt[][src]

pub trait GeneratorExt: Sealed + Generator {
Show 40 methods fn all<F>(&mut self, predicate: F) -> bool
    where
        F: FnMut(Self::Output) -> bool
, { ... }
fn any<F>(&mut self, predicate: F) -> bool
    where
        F: FnMut(Self::Output) -> bool
, { ... }
fn next(&mut self) -> Result<Self::Output, GeneratorResult> { ... }
fn last(self) -> Option<Self::Output>
    where
        Self: Sized
, { ... }
fn cloned<'a, T>(self) -> Cloned<Self>
    where
        Self: Generator<Output = &'a T> + Sized,
        T: 'a + Clone
, { ... }
fn copied<'a, T>(self) -> Copied<Self>
    where
        T: 'a + Copy,
        Self: Generator<Output = &'a T> + Sized
, { ... }
fn chain<Gen>(self, other: Gen) -> Chain<Self, Gen>
    where
        Self: Sized,
        Gen: Generator<Output = Self::Output>
, { ... }
fn filter<Pred>(self, predicate: Pred) -> Filter<Self, Pred>
    where
        Self: Sized,
        Pred: FnMut(&Self::Output) -> bool
, { ... }
fn filter_map<B, F>(self, f: F) -> FilterMap<Self, F>
    where
        Self: Sized,
        F: FnMut(Self::Output) -> Option<B>
, { ... }
fn map<Trans, Out>(self, transform_fn: Trans) -> Map<Self, Trans>
    where
        Self: Sized,
        Trans: FnMut(Self::Output) -> Out
, { ... }
fn skip(self, n: usize) -> Skip<Self>
    where
        Self: Sized
, { ... }
fn skip_while<P>(self, predicate: P) -> SkipWhile<Self, P>
    where
        Self: Sized,
        P: FnMut(&Self::Output) -> bool
, { ... }
fn take(self, n: usize) -> Take<Self>
    where
        Self: Sized
, { ... }
fn take_while<P>(self, predicate: P) -> TakeWhile<Self, P>
    where
        Self: Sized,
        P: FnMut(&Self::Output) -> bool
, { ... }
fn flat_map<U, F>(self, f: F) -> Flatten<Map<Self, F>>
    where
        Self: Sized,
        U: IntoGenerator,
        F: FnMut(Self::Output) -> U
, { ... }
fn flatten(self) -> Flatten<Self>
    where
        Self: Sized,
        Self::Output: IntoGenerator
, { ... }
fn for_each<Func>(&mut self, func: Func) -> GeneratorResult
    where
        Self: Sized,
        Func: FnMut(Self::Output)
, { ... }
fn try_for_each<F, E>(&mut self, f: F) -> Result<(), E>
    where
        Self: Sized,
        F: FnMut(Self::Output) -> Result<(), E>
, { ... }
fn zip<Right>(self, right: Right) -> Zip<Self, Right>
    where
        Self: Sized,
        Right: Generator
, { ... }
fn dedup(self) -> Dedup<Self>
    where
        Self: Sized,
        Self::Output: PartialEq
, { ... }
fn iter(self) -> IteratorAdaptor<Self>
Notable traits for IteratorAdaptor<Src>
impl<Src> Iterator for IteratorAdaptor<Src> where
    Src: Generator
type Item = Src::Output;

    where
        Self: Sized
, { ... }
fn step_by(self, step_size: usize) -> StepBy<Self>
    where
        Self: Sized
, { ... }
fn boxed(self) -> BoxedGenerator<Self::Output>
    where
        Self: Sized + 'static
, { ... }
fn sum<S>(self) -> S
    where
        Self: Sized,
        S: Sum<Self::Output>
, { ... }
fn product<P>(self) -> P
    where
        Self: Sized,
        P: Product<Self::Output>
, { ... }
fn min(self) -> Option<Self::Output>
    where
        Self: Sized,
        Self::Output: Ord
, { ... }
fn min_by<F>(self, compare: F) -> Option<Self::Output>
    where
        Self: Sized,
        F: FnMut(&Self::Output, &Self::Output) -> Ordering
, { ... }
fn try_min_by<F>(
        &mut self,
        partial: Option<Self::Output>,
        compare: F
    ) -> TryReduction<Option<Self::Output>>
    where
        Self: Sized,
        F: FnMut(&Self::Output, &Self::Output) -> Ordering
, { ... }
fn min_by_key<F, B>(self, f: F) -> Option<Self::Output>
    where
        Self: Sized,
        F: FnMut(&Self::Output) -> B,
        B: Ord
, { ... }
fn max(self) -> Option<Self::Output>
    where
        Self: Sized,
        Self::Output: Ord
, { ... }
fn max_by<F>(self, compare: F) -> Option<Self::Output>
    where
        Self: Sized,
        F: FnMut(&Self::Output, &Self::Output) -> Ordering
, { ... }
fn try_max_by<F>(
        &mut self,
        partial: Option<Self::Output>,
        compare: F
    ) -> TryReduction<Option<Self::Output>>
    where
        Self: Sized,
        F: FnMut(&Self::Output, &Self::Output) -> Ordering
, { ... }
fn max_by_key<F, B>(self, f: F) -> Option<Self::Output>
    where
        Self: Sized,
        F: FnMut(&Self::Output) -> B,
        B: Ord
, { ... }
fn fold<B, F>(self, init: B, folder: F) -> B
    where
        Self: Sized,
        F: FnMut(B, Self::Output) -> B
, { ... }
fn try_fold<B, F, E>(
        &mut self,
        init: B,
        folder: F
    ) -> Result<TryReduction<B>, E>
    where
        Self: Sized,
        F: FnMut(B, Self::Output) -> Result<B, E>
, { ... }
fn reduce<F>(self, reducer: F) -> Option<Self::Output>
    where
        Self: Sized,
        F: FnMut(Self::Output, Self::Output) -> Self::Output
, { ... }
fn try_reduce<F>(
        &mut self,
        prev_reduction: Option<Self::Output>,
        reducer: F
    ) -> TryReduction<Option<Self::Output>>
    where
        Self: Sized,
        F: FnMut(Self::Output, Self::Output) -> Self::Output
, { ... }
fn collect<B>(self) -> B
    where
        Self: Sized,
        B: FromGenerator<Self::Output>
, { ... }
fn enumerate(self) -> Enumerate<Self>
    where
        Self: Sized
, { ... }
fn inspect<F>(self, inspector: F) -> Inspect<Self, F>
    where
        Self: Sized,
        F: FnMut(&Self::Output)
, { ... }
}
Expand description

Provides extension-methods for all generators.

This allows generators to be composed to new generators, or consumed.

Example

use pushgen::{SliceGenerator, GeneratorExt};
let data = [1, 2, 3, 4];
let mut output: Vec<i32> = Vec::new();
SliceGenerator::new(&data).map(|x| x*3).for_each(|x| output.push(x));
assert_eq!(output, [3,6,9,12]);

Provided methods

Tests if every value from the generator matches a predicate.

all() takes a closure that returns true or false. It applies this closure to each value generated by the generator, and if they all return true, then so does all(). If any value returns false, all() returns false.

all() is short-circuiting; it will stop processing as soon as it finds a false.

An empty generator returns true.

Examples

Basic usage:

use pushgen::{IntoGenerator, GeneratorExt};
let a = [1, 2, 3];
assert!(a.into_gen().all(|&x| x > 0));
assert!(!a.into_gen().all(|&x| x > 2));

Stopping at first false:

use pushgen::{IntoGenerator, GeneratorExt};
let a = [1, 2, 3];
let mut gen = a.into_gen();
assert!(!gen.all(|&x| x != 2));
assert_eq!(gen.iter().next(), Some(&3));

Tests if any value matches a predicate.

any() takes a closure that returns true or false. It applies this closure to each value from the generator, and if any of them return true, then so does any(). If they all return false, it returns false.

any() is short-circuiting; in other words, it will stop processing as soon as it finds a true, given that no matter what else happens, the result will also be true.

An empty generator returns false.

Examples

Basic usage:

use pushgen::{IntoGenerator, GeneratorExt};
let a = [1, 2, 3];

assert!(a.into_gen().any(|&x| x > 0));

assert!(!a.into_gen().any(|&x| x > 5));

Stopping at the first true:

use pushgen::{IntoGenerator, GeneratorExt};
let a = [1, 2, 3];

let mut gen = a.into_gen();

assert!(gen.any(|&x| x != 2));

// we can still use `gen`, as there are more elements.
assert_eq!(gen.iter().next(), Some(&2));

Retrieve the next value from the generator

If the generator is completed or stopped before a value is retrieved an Err(GeneratorResult) with the status of the generator is returned. Otherwise an Ok() value is returned.

Examples

Basic usage:

use pushgen::{SliceGenerator, GeneratorExt, GeneratorResult};
let data = [1, 2];
let mut gen = SliceGenerator::new(&data);
assert_eq!(gen.next(), Ok(&1));
assert_eq!(gen.next(), Ok(&2));
assert_eq!(gen.next(), Err(GeneratorResult::Complete));

Exhausts the generator, returning the last element.

This method will evaluate the generator until it completes. While doing so, it keeps track of the current element. After it completes last() will then return the last element it saw.

Examples

Basic usage:

use pushgen::IntoGenerator;
use pushgen::GeneratorExt;

let a = [1, 2, 3];
assert_eq!(a.into_gen().last(), Some(&3));

let a = [1, 2, 3, 4, 5];
assert_eq!(a.into_gen().last(), Some(&5));

Creates a generator that clones all of its elements.

This is useful when you have a generator that generates &T but you need a generate that generates T.

Examples

Basic usage

use pushgen::{SliceGenerator, GeneratorExt};
let data = [1, 2, 3];
let mut output: Vec<i32> = Vec::new();
SliceGenerator::new(&data).cloned().for_each(|x| output.push(x));
assert_eq!(output, [1, 2, 3])

Creates a generator that copies all of its elements.

This is useful when you have a generator of &T but need a generator of T.

Examples

Basic usage:

use pushgen::{SliceGenerator, GeneratorExt};
let data = [1, 2, 3];
let mut v_copied: Vec<_> = Vec::new();
SliceGenerator::new(&data).copied().for_each(|x| v_copied.push(x));

assert_eq!(v_copied, [1, 2, 3]);

Creates a generator by chaining two generators, running them one after the other.

Example

use pushgen::{SliceGenerator, GeneratorExt};
let data = [1, 2, 3];
let mut output: Vec<i32> = Vec::new();
SliceGenerator::new(&data).chain(SliceGenerator::new(&data)).for_each(|x| output.push(*x));
assert_eq!(output, [1, 2, 3, 1, 2, 3]);

Create a filtered generator. Only values for which the predicate returns true will be passed on.

The predicate must implement FnMut(&Gen::Output) -> bool.

Example

let input = [1,2,3,4];
let mut output: Vec<i32> = Vec::new();
let run_result = SliceGenerator::new(&input).filter(|x| *x % 2 == 0).for_each(|x| output.push(*x));
assert_eq!(run_result, GeneratorResult::Complete);
assert_eq!(output, [2,4]);

Creates a generator that both filters and maps.

The returned generator produces only the values for which the supplied closure returns Some(value).

filter_map can be used to make chains of filter and map more concise. The example below shows how a map().filter().map() can be shortened to a single call to filter_map.

Examples

Basic usage:

use pushgen::{SliceGenerator, GeneratorExt};

let a = ["1", "two", "NaN", "four", "5"];

let mut output: Vec<i32> = Vec::new();
SliceGenerator::new(&a).filter_map(|s| s.parse().ok()).for_each(|x: i32| output.push(x));
assert_eq!(output, [1, 5]);

Here’s the same example, but with filter and map:

use pushgen::{SliceGenerator, GeneratorExt};

let a = ["1", "two", "NaN", "four", "5"];

let mut output: Vec<i32> = Vec::new();
SliceGenerator::new(&a).map(|s| s.parse()).filter(|s| s.is_ok()).map(|s| s.unwrap()).for_each(|x: i32| output.push(x));
assert_eq!(output, [1, 5]);

Takes a closure and creates a generator which calls the closure on each value.

Example

use pushgen::{SliceGenerator, GeneratorExt};
let data = [1, 2, 3];
let mut output: Vec<String> = Vec::new();
SliceGenerator::new(&data).map(|x| x.to_string()).for_each(|x| output.push(x));
assert_eq!(output, ["1", "2", "3"]);

Skips over n values, consuming and ignoring them.

Example

 let input = [1,2,3,4];
 let mut skipped_generator = SliceGenerator::new(&input).skip(2);
 let mut output: Vec<i32> = Vec::new();
 skipped_generator.for_each(|x| output.push(*x));
 assert_eq!(output, [3,4]);

Creates a generator that skips values based on a predicate.

skip_while() takes a closure as argument. It will call this closure on each value, and ignore values until the closure returns false.

After false is returned, skip_while() will push the rest of the values.

Examples

Basic usage

use pushgen::{IntoGenerator, GeneratorExt};
let a = [-1i32, 0, 1];
let mut output = Vec::new();
a.into_gen().skip_while(|x| x.is_negative()).for_each(|x| output.push(x));
assert_eq!(output, [&0, &1]);

Takes n values and then completes the generator.

Example

use pushgen::{SliceGenerator, GeneratorExt};
let data = [1, 2, 3, 4];
let mut output: Vec<i32> = Vec::new();
SliceGenerator::new(&data).take(2).for_each(|x| output.push(*x));
assert_eq!(output, [1, 2]);

Creates a generator that pushes values based on a predicate.

take_while() takes a closure as an argument. It will call this closure on each value received from the source generator, and push values while it returns true. After false is returned, take_while()’s job is over and it will always report Complete.

Examples

Basic usage:

use pushgen::{IntoGenerator, GeneratorExt};
let a = [-1i32, 0, 1];

let mut gen_as_iter = a.into_gen().take_while(|x| x.is_negative()).iter();

assert_eq!(gen_as_iter.next(), Some(&-1));
assert_eq!(gen_as_iter.next(), None);

Creates a generator that works like map, but flattens nested structure.

The map adapter is very useful, but only when the closure argument produces values. If it produces a generator instead, there’s an extra layer of indirection. flat_map() will remove this extra layer on its own.

You can think of flat_map(f) as the semantic equivalent of mapping, and then flattening as in map(f).flatten().

Another way of thinking about flat_map(): map’s closure returns one item for each element, and flat_map()’s closure returns an iterator for each element.

Examples

Basic usage:

use pushgen::IntoGenerator;
use crate::pushgen::GeneratorExt;

let words = ["alpha", "beta", "gamma"];

let mut merged = String::new();
words.into_gen()
     .flat_map(|s| pushgen::from_iter(s.chars()))
     .for_each(|x| merged.push(x));
assert_eq!(merged, "alphabetagamma");

Creates a generator that flattens nested structure.

This is useful when you have a generator of generators or a generator of things that can be turned into generators and you want to remove one level of indirection.

Examples

Basic usage:

use pushgen::IntoGenerator;
use crate::pushgen::GeneratorExt;

let data = vec![vec![1, 2, 3, 4], vec![5, 6]];
let mut output: Vec<i32> = Vec::new();
let flattened = data.into_gen().flatten().for_each(|x| output.push(x));
assert_eq!(output, [1, 2, 3, 4, 5, 6]);

Mapping and then flattening:

use pushgen::IntoGenerator;
use crate::pushgen::GeneratorExt;

let words = &["alpha", "beta", "gamma"];

let mut merged = String::new();
words.into_gen()
     .map(|s| pushgen::from_iter(s.chars()))
     .flatten()
     .for_each(|x| merged.push(x));
assert_eq!(merged, "alphabetagamma");

Run a generator to completion, or until it is stopped, and call a closure for each value produced by the generator.

The closure will be called for as long as the generator produces values, it is not possible to abort processing early. If early abort is needed, use Generator::run

Example

let mut sum = 0i32;
let data = [1,2,3];
let result = SliceGenerator::new(&data).for_each(|x| sum += x);
assert_eq!(sum, 6);
assert_eq!(result, GeneratorResult::Complete);

A generator method that applies a fallible function to each item produced, stopping at the first error and returning that error.

This can also be thought of as the fallible form of for_each() or as the stateless version of try_fold().

Examples

use std::fs::rename;
use std::io::{stdout, Write};
use std::path::Path;
use pushgen::{SliceGenerator, GeneratorExt};

let data = ["no_tea.txt", "stale_bread.json", "torrential_rain.png"];

let res = SliceGenerator::new(&data).try_for_each(|x| writeln!(stdout(), "{}", x));
assert!(res.is_ok());

let mut gen = SliceGenerator::new(&data);
let res = gen.try_for_each(|x| rename(x, Path::new(x).with_extension("old")));
assert!(res.is_err());
// It short-circuited, so the remaining items are still in the generator:
let mut output: Vec<&'static str> = Vec::new();
gen.for_each(|x| output.push(*x));
assert_eq!(output, ["stale_bread.json", "torrential_rain.png"]);

Zips the output of two generators into a single generator of pairs.

zip() returns a new generator that will use values from two generators, outputting a tuple where the first element comes from the first generator, and the second element comes from the second generator.

The zip generator will complete when either generator completes.

Example

use pushgen::{SliceGenerator, GeneratorExt};
let left = [1, 2, 3];
let right = [4, 5, 6];
let mut output: Vec<(i32, i32)> = Vec::new();
SliceGenerator::new(&left).zip(SliceGenerator::new(&right)).for_each(|(a, b)| output.push((*a, *b)));
assert_eq!(output, [(1,4), (2, 5), (3, 6)]);

Create a de-duplicating generator, removing consecutive duplicate values.

Values will be made available when a non-duplicate is detected. If the up-stream generator generates the following sequence: [1, 2, 3, 3, 4] then the value 1 will be generated from the Dedup generator once the value 2 has been generated by the upstream generator and so on.

Upstream valueDedup-generated value
1None
21
32
3Ignored
43
Complete4
CompleteComplete

Example

let data = [1, 2, 3, 3, 3, 3, 4, 3];
let mut output: Vec<i32> = Vec::new();
SliceGenerator::new(&data).dedup().for_each(|x| output.push(*x));
assert_eq!(output, [1, 2, 3, 4, 3]);

Create an iterator from a generator.

This allows generators to be used in basic for-loops.

Example

use pushgen::{SliceGenerator, GeneratorExt};
let data = [1, 2, 3, 4, 5, 6];
let mut sum = 0;
for x in SliceGenerator::new(&data).iter() {
    sum += x;
}
assert_eq!(sum, data.iter().sum());

Create a generator that starts at the same point but steps by the given amount.

Note 1: The first value will always be generated, regardless of the step given

Panics

The method will panic if given a step size of 0

Examples

Basic usage:

use pushgen::{IntoGenerator, GeneratorExt, GeneratorResult};
let a = [0, 1, 2, 3, 4, 5];
let mut gen = a.into_gen().step_by(2);

assert_eq!(gen.next(), Ok(&0));
assert_eq!(gen.next(), Ok(&2));
assert_eq!(gen.next(), Ok(&4));
assert_eq!(gen.next(), Err(GeneratorResult::Complete));
This is supported on crate feature std only.

Box a generator, making it possible to use as return value in for instance traits.

Performance

This causes at least one layer of redirection, which is very likely to impact performance. One should always prefer to use impl Generator<Output=X> instead.

Example

use pushgen::{generators::BoxedGenerator, IntoGenerator, GeneratorExt};
fn make_generator() -> BoxedGenerator<i32> {
    vec![1, 2, 3, 4].into_gen().map(|x| x*2).boxed()
}
let mut output = Vec::new();
make_generator().for_each(|x| output.push(x));
assert_eq!(output, [2, 4, 6, 8]);

Sums the values of a generator. Takes each value and adds them together and returns the result.

An empty generator returns the zero value of the type.

Spuriously stopping generators

sum() only sums the values up until the source generator is first stopped. If the source generator is not completed, but stops mid-generation for some reason, only the values up until the first stop are summed.

Panics

When calling sum() and a primitive integer type is being returned, this method will panic if the computation overflows and debug assertions are enabled.

Examples

Basic usage:

use pushgen::{IntoGenerator, GeneratorExt};
let a = [1, 2, 3];
let sum: i32 = a.into_gen().sum();

assert_eq!(sum, 6);

Multiplies the values of a generator. Takes each value and adds them together and returns the result.

An empty generator returns the one value of the type.

Spuriously stopping generators

product() only multiplies the values up until the source generator is first stopped. If the source generator is not completed, but stops mid-generation for some reason, only the values up until the first stop are multiplied.

Panics

When calling product() and a primitive integer type is being returned, this method will panic if the computation overflows and debug assertions are enabled.

Examples

Basic usage:

use pushgen::{GeneratorExt, from_iter};
fn factorial(n: u32) -> u32 {
    // Create a generator from an iterable
    from_iter((1..=n)).product()
}

assert_eq!(factorial(0), 1);
assert_eq!(factorial(1), 1);
assert_eq!(factorial(5), 120);

Returns the minimum value of a generator.

If several elements are equally minimum, the first element is returned. If the generator is empty, None is returned.

Spuriously stopping generators

min() will return the result after the source generator has stopped. It doesn’t matter if the source generator is stopped or completed.

Use try_min_by() to handle spuriously stopping generators.

Examples

Basic usage:

use pushgen::{GeneratorExt, IntoGenerator};
let a = [1, 2, 3];
let b: Vec<u32> = Vec::new();

assert_eq!(a.into_gen().min(), Some(&1));
assert_eq!(b.into_gen().min(), None);

Returns the value that gives the minimum value when compared with the specified comparison function.

If several elements are equally minimum, the first element is returned. If the generator is empty, None is returned.

Spuriously stopping generators

min_by() will return the result after the source generator has stopped. It doesn’t matter if the source generator is stopped or completed.

Use try_min_by() to handle spuriously stopping generators.

Examples

use pushgen::{GeneratorExt, IntoGenerator};
let a = [-3_i32, 0, 1, 5, -10];
assert_eq!(*a.into_gen().min_by(|x, y| x.cmp(y)).unwrap(), -10);

Returns the value that gives the minimum value when compared with the specified comparison function.

If several elements are equally minimum, the first element is returned. If the generator is empty, None is returned.

This method can be used with spuriously stopping generators.

Examples

Basic usage

use pushgen::{GeneratorExt, IntoGenerator};
let a = [-3_i32, 0, 1, 5, -10];
assert_eq!(a.into_gen().try_min_by(None, |x, y| x.cmp(y)).unwrap(), Some(&-10));

Stopping generator:

use pushgen::{Generator, ValueResult, GeneratorResult, GeneratorExt};
use pushgen::test::StoppingGen;
let data = [1, 2, 0, 4];
let mut gen = StoppingGen::new(1, &data);
let partial = gen.try_min_by(None, Ord::cmp);
// generator was stopped - indicated by a Partial reduction.
assert!(partial.is_partial());
let partial = partial.unwrap();
assert_eq!(partial, Some(&1));
// Feed partial value to continue reduction from the partial value
let res = gen.try_min_by(partial, Ord::cmp);
assert!(res.is_complete());
assert_eq!(res.unwrap(), Some(&0));

Returns the value that gives the minimum value from the specified function.

If several elements are equally minimum, the first element is returned. If the generator is empty, None is returned.

Spuriously stopping generators

min_by_key() will return the result after the source generator has stopped. It doesn’t matter if the source generator is stopped or completed.

Manually use try_min_by() to handle spuriously stopping generators.

Examples

use pushgen::{GeneratorExt, IntoGenerator};
let a = [-3_i32, 0, 1, 5, -10];
assert_eq!(*a.into_gen().min_by_key(|x| x.abs()).unwrap(), 0);

Returns the maximum value of a generator.

If several elements are equally maximum, the last element is returned. If the generator is empty, None is returned.

Spuriously stopping generators

max() will return the result after the source generator has stopped. It doesn’t matter if the source generator is stopped or completed.

Use try_max_by() to handle spuriously stopping generators.

Examples

Basic usage:

use pushgen::{GeneratorExt, IntoGenerator};
let a = [1, 2, 3];
let b: Vec<u32> = Vec::new();

assert_eq!(a.into_gen().max(), Some(&3));
assert_eq!(b.into_gen().max(), None);

Returns the value that gives the maximum value when compared with the specified comparison function.

If several elements are equally maximum, the last element is returned. If the generator is empty, None is returned.

Spuriously stopping generators

max_by() will return the result after the source generator has stopped. It doesn’t matter if the source generator is stopped or completed.

Manually use try_max_by() to handle spuriously stopping generators.

Examples

use pushgen::{GeneratorExt, IntoGenerator};
let a = [-3_i32, 0, 1, 5, -10];
assert_eq!(*a.into_gen().max_by(|x, y| x.cmp(y)).unwrap(), 5);

Returns the value that gives the maximum value when compared with the specified comparison function.

If several elements are equally maximum, the last element is returned. If the generator is empty, None is returned.

This method can be used with spuriously stopping generators.

Examples

Basic usage

use pushgen::{GeneratorExt, IntoGenerator};
let a = [-3_i32, 0, 1, 5, -10];
assert_eq!(a.into_gen().try_min_by(None, |x, y| x.cmp(y)).unwrap(), Some(&-10));

Stopping generator:

use pushgen::{Generator, ValueResult, GeneratorResult, GeneratorExt};
use pushgen::test::StoppingGen;
let data = [1, 2, 0, 4];
let mut gen = StoppingGen::new(1, &data);
let partial = gen.try_max_by(None, Ord::cmp);
// generator was stopped - indicated by a Partial reduction.
assert!(partial.is_partial());
let partial = partial.unwrap();
assert_eq!(partial, Some(&1));
// Feed partial value to continue from the partial value
let res = gen.try_max_by(partial, Ord::cmp);
assert!(res.is_complete());
assert_eq!(res.unwrap(), Some(&4));

Returns the value that gives the maximum value from the specified function.

If several elements are equally maximum, the last element is returned. If the generator is empty, None is returned.

Spuriously stopping generators

max_by_key() will return the result after the source generator has stopped. It doesn’t matter if the source generator is stopped or completed.

Manually use try_max_by() to handle spuriously stopping generators.

Examples

use pushgen::{GeneratorExt, IntoGenerator};
let a = [-3_i32, 0, 1, 5, -10];
assert_eq!(*a.into_gen().max_by_key(|x| x.abs()).unwrap(), -10);

Folds every element into an accumulator by applying an operation, returning the final result.

Folding is useful whenever you have a collection of something, and want to produce a single value from it.

Note: reduce() can be used to use the first value as the initial value, if the accumulator type and the output type is the same.

Spuriously stopping generators

fold() will stop and return the result after the first stop of the generator. It doesn’t matter if the generator stopped or completed.

Use try_fold() to correctly handle spuriously stopping generators.

Arguments

init The initial accumulator value

folder A closure that takes an accumulator value and a generated value and returns a new accumulator value.

Examples

Basic usage:

use pushgen::{IntoGenerator, GeneratorExt};
let a = [1, 2, 3];

// the sum of all of the elements of the array
let sum = a.into_gen().fold(0, |acc, x| acc + x);

assert_eq!(sum, 6);

Apply a function as long as the return value is successful, producing a single final value.

try_fold() takes two arguments: an initial value, and a closure with two arguments: an ‘accumulator’, and a value. The closure either returns successfully, with the value that the accumulator should have for the next iteration, or it returns failure, with an error value that is propagated back to the caller immediately (short-circuiting).

The return value from try_fold() can distinguish between 3 different return-conditions:

  • Ok(Reduction::Complete(B)) -> the generator has completed and produced a final value.
  • Ok(Reduction::Partial(B)) -> the generator spuriously stopped early. Later try_fold calls should use the partial value as init.
  • Err(E) -> The provided closure returned an error.

Examples

Basic usage:

use pushgen::{IntoGenerator, GeneratorExt, TryReduction};
let a = [1, 2, 3];

// the checked sum of all of the elements of the array
let sum = a.into_gen().try_fold(0i8, |acc, &x| acc.checked_add(x).ok_or(()));

assert_eq!(sum, Ok(TryReduction::Complete(6)));

Short circuiting:

use pushgen::{IntoGenerator, GeneratorExt, TryReduction, GeneratorResult};
let a = [10, 20, 30, 100, 40, 50];
let mut gen = a.into_gen();

// This sum overflows when adding the 100 element
let sum = gen.try_fold(0i8, |acc, &x| acc.checked_add(x).ok_or(()));
assert_eq!(sum, Err(()));

// Because it short-circuited, the remaining elements are still
// available through the iterator.
assert_eq!(gen.next(), Ok(&40));
assert_eq!(gen.next(), Ok(&50));
assert_eq!(gen.next(), Err(GeneratorResult::Complete));

Reduces the elements to a single one by repeatedly applying a reducing operation.

Returns

None if the generator is empty, otherwise the result of the reduction.

Spuriously stopping generators

Reduce will return the result after the source generator has stopped. It doesn’t matter if the source generator is stopped or completed.

Use try_reduce to reduce spuriously stopping generators.

Example

Find the maximum value:

use pushgen::{Generator, GeneratorExt, IntoGenerator};
fn find_max<G>(gen: G) -> Option<G::Output>
    where G: Generator,
          G::Output: Ord,
{
    gen.reduce(|a, b| {
        if a >= b { a } else { b }
    })
}
let a = [10, 20, 5, -23, 0];
let b: [u32; 0] = [];

assert_eq!(find_max(a.into_gen()), Some(&20));
assert_eq!(find_max(b.into_gen()), None);

Reduces the values to a single value by repeatedly applying a reducing operation.

Use this reduction if the generator is known to spuriously stop mid-stream. Otherwise it is better to use reduce().

Arguments

prev_reduction The result of an earlier incomplete reduction. Set to None if this is the first reduction pass.

reducer The reducing closure to use.

Returns

Ok(x) if the generator was run to completion. x is None if the generator is empty, otherwise it is the result of the complete reduction.

Err(y) if the generator was stopped mid-reduction. y is the value that the generator was reduced to when it stopped. This value should be used in any subsequent calls to try_reduce until an Ok() value is returned.

Example

Find the maximum value:

use pushgen::{Generator, GeneratorExt, IntoGenerator, TryReduction};
fn find_max<G>(gen: &mut G) -> TryReduction<Option<G::Output>>
    where G: Generator,
          G::Output: Ord,
{
    gen.try_reduce(None, |a, b| {
        if a >= b { a } else { b }
    })
}
let a = [10, 20, 5, -23, 0];
let b: [u32; 0] = [];

assert_eq!(find_max(&mut a.into_gen()).unwrap(), Some(&20));
assert_eq!(find_max(&mut b.into_gen()).unwrap(), None);

With a stopping generator:

use pushgen::{Generator, ValueResult, GeneratorResult, GeneratorExt};
use pushgen::test::StoppingGen; // Available with feature `test`
let data = [1, 2, 3, 0, 4, 5];
let mut gen = StoppingGen::new(1, &data).copied();
let partial = gen.try_reduce(None, |a, b| a + b);
assert!(partial.is_partial());
let partial = partial.unwrap();
assert_eq!(partial, Some(1));
let res = gen.try_reduce(partial, |a, b| a + b);
assert!(res.is_complete());
assert_eq!(res.unwrap(), Some(1+2+3+4+5));

Transforms a generator into a collection.

collect() can take any generator and turn it into a relevant collection.

Spuriously stopping generators

Collect will stop collecting values as soon as the generator is stopped. It doesn’t matter if the generator was completed or not.

To handle spuriously stopping generators one should manually do the collecting with for instance for_each().

Examples

Basic usage:

use pushgen::{IntoGenerator, GeneratorExt};
let a = [1, 2, 3];

let doubled: Vec<i32> = a.into_gen()
                         .map(|&x| x * 2)
                         .collect();

assert_eq!(vec![2, 4, 6], doubled);

Creates a generator which gives the current generation count as well as the value.

The generator generates (i, val) values, where i is the current index of the value and val is the current value.

Overflow behaviour

The method does not guard against overflows, so enumerating more than usize::MAX values will either produce the wrong result or panic.

Panics

The generator might panic if the index overflows a usize.

Examples

Basic usage:

use pushgen::{SliceGenerator, GeneratorExt, GeneratorResult};
let data = ['a', 'b', 'c'];

let mut gen = SliceGenerator::new(&data).enumerate();
assert_eq!(gen.next(), Ok((0, &'a')));
assert_eq!(gen.next(), Ok((1, &'b')));
assert_eq!(gen.next(), Ok((2, &'c')));
assert_eq!(gen.next(), Err(GeneratorResult::Complete));

Does something with each value from the generator, passing the value on.

This is useful if you want to inspect a value in the middle of a pipeline, for instance to add debug output.

Example

Basic usage:

use pushgen::{IntoGenerator, GeneratorExt};
let a = [1, 4, 2, 3];

// this iterator sequence is complex.
let sum = a.into_gen()
    .cloned()
    .filter(|x| x % 2 == 0)
    .fold(0, |sum, i| sum + i);

println!("{}", sum);

// let's add some inspect() calls to investigate what's happening
let sum = a.into_gen()
    .cloned()
    .inspect(|x| println!("about to filter: {}", x))
    .filter(|x| x % 2 == 0)
    .inspect(|x| println!("made it through filter: {}", x))
    .fold(0, |sum, i| sum + i);

println!("{}", sum);

This will print

6
about to filter: 1
about to filter: 4
made it through filter: 4
about to filter: 2
made it through filter: 2
about to filter: 3
6

Implementors