pub(super) trait Reduce {
type Element;
fn reduce<F>(&self, f: &F) -> Self::Element
where
F: Fn(Self::Element, Self::Element) -> Self::Element;
}
impl<T: Copy> Reduce for [T; 1] {
type Element = T;
#[inline(always)]
fn reduce<F>(&self, _f: &F) -> T
where
F: Fn(T, T) -> T,
{
self[0]
}
}
impl<T: Copy> Reduce for [T; 2] {
type Element = T;
#[inline(always)]
fn reduce<F>(&self, f: &F) -> T
where
F: Fn(T, T) -> T,
{
f(self[0], self[1])
}
}
impl<T: Copy> Reduce for [T; 3] {
type Element = T;
#[inline(always)]
fn reduce<F>(&self, f: &F) -> T
where
F: Fn(T, T) -> T,
{
f(f(self[0], self[1]), self[2])
}
}
impl<T: Copy> Reduce for [T; 4] {
type Element = T;
#[inline(always)]
fn reduce<F>(&self, f: &F) -> T
where
F: Fn(T, T) -> T,
{
f(f(self[0], self[1]), f(self[2], self[3]))
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn reduce_folds_correctly() {
let max = |a: f32, b: f32| a.max(b);
assert_eq!([5.0f32].reduce(&max), 5.0);
assert_eq!([1.0f32, 3.0].reduce(&max), 3.0);
assert_eq!([2.0f32, 1.0, 4.0].reduce(&max), 4.0);
assert_eq!([3.0f32, 1.0, 4.0, 2.0].reduce(&max), 4.0);
}
#[test]
fn reduce_fold_order() {
let sub = |a: f32, b: f32| a - b;
assert_eq!([10.0f32].reduce(&sub), 10.0);
assert_eq!([10.0f32, 3.0].reduce(&sub), 7.0);
assert_eq!([10.0f32, 3.0, 1.0].reduce(&sub), 6.0);
assert_eq!([10.0f32, 3.0, 1.0, 2.0].reduce(&sub), 8.0);
}
}