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));
fn next(&mut self) -> Result<Self::Output, GeneratorResult>
fn next(&mut self) -> Result<Self::Output, GeneratorResult>
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 value
s 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 map
ping, and then flatten
ing 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 value | Dedup-generated value |
---|---|
1 | None |
2 | 1 |
3 | 2 |
3 | Ignored |
4 | 3 |
Complete | 4 |
Complete | Complete |
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]);
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 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,
impl<Src> Iterator for IteratorAdaptor<Src> where
Src: Generator, type Item = Src::Output;
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));
fn boxed(self) -> BoxedGenerator<Self::Output> where
Self: Sized + 'static,
fn boxed(self) -> BoxedGenerator<Self::Output> where
Self: Sized + 'static,
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. Latertry_fold
calls should use the partial value asinit
.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));
fn collect<B>(self) -> B where
Self: Sized,
B: FromGenerator<Self::Output>,
fn collect<B>(self) -> B where
Self: Sized,
B: FromGenerator<Self::Output>,
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