6 releases (breaking)
0.5.1 | Oct 1, 2024 |
---|---|
0.5.0 | Apr 22, 2023 |
0.4.0 | Dec 21, 2022 |
0.3.0 | May 30, 2022 |
0.1.0 | Apr 16, 2022 |
#239 in Rust patterns
53KB
785 lines
autofolder
autofolder provides a single-element "folding" container that can be used to accumulate/select/etc. values in an ad-hoc fashion.
TL;DR: DynFolder
example
use autofolder::*;
// Create an autofolder that retains the max u32 value:
let mut max = DynFolder::new(0_u32, std::cmp::max);
// We can "fold-in" individual items:
max.fold(3);
// We can then peek at the running output:
println!("Partial max is {}", max.as_ref());
// And still keep on folding by processing whole iterators:
max.extend((1..=5));
// And finally consume the autofolder to get the final output value:
println!("Max value is {}", max.into_inner());
See also Min
, Max
and MinMax
for useful specific reducers.
Rationale
Folding in Rust is accomplished via the Iterator::fold
method, like so:
iterator.fold(initial, function);
// (and this is all you can do)
That works well when all the data we need is provided by a single iterator. If we have a
more complex logic, fold
can't be used.
autofolder flips this structure by being built with the initial value and the folding function, and accepting values from various types of different sources during its lifetime.
let mut autofolder = Autofolder::new(initial, function);
// Fold in a whole iterator, can be repeated:
autofolder.extend(iterator);
// Fold in an individual value:
autofolder.fold(value);
Types of folders
By binding strategy
This crate provides two types of autofolders with different function binding strategies:
DynFolder
: the folding function is provided as a closure that is kept in a struct field. Characteristics:- Folding function can use any type, builtin or otherwise.
- Each instance can use a different folding function, provided as a constructor argument.
On the flip side, we can't use
DynFolder
with.collect()
. - Slightly less efficient than
ImplFolder
due to the use of dynamic dispatch - we are effectively using a function pointer instead of a function call, after all.
ImplFolder
: the folding function is implemented via a trait.- Folding function can only use types defined in the user crate, which is a limitation of using traits.
- Each parameterized
ImplFolder
, defined by the pair of types, can only have one folding function. Because of that, we can useImplFolder
with.collect()
if theoutput
type implementsDefault
- Slighly more efficient than
DynFolder
due to monomorphization, which turns.fold
calls into direct function calls.
By aggregation strategy
Reduce in rust is a special kind of folding where the aggregator and the item types of
the folding function are the same (Fn(Item, Item) -> Item
). That allows us to set the
internal autofolder state with the first yielded value, without calling the corresponding
function.
This crate provides the following "autoreducer" types:
DynReduce
: the reduce function is implemented via a trait.- Similar to
DynFolder
. .into_inner()
returns anOption
.- Constructor takes the
reduce
function.
- Similar to
ImplReduce
: the reduce function is implemented via a trait.- Similar to
ImplFolder
. .into_inner()
returns anOption
.- Implements
.collect()
even when the type parameters don't implementDefault
.
- Similar to
Specific autofolders
This create also provides some built-in autofolders for specific functions:
Min
: container that keeps only the minimal value iterated, as given bystd::cmp::PartialOrd
.Max
: analogous toMax
, but for the max value.MinMax
: container that keeps a tuple with both the min and max values.
Dependencies
~71KB