From e5a9293ec29e379a3b8f770dc4c2f7ae4ceb77d4 Mon Sep 17 00:00:00 2001 From: annieversary Date: Thu, 11 Nov 2021 12:56:54 +0000 Subject: [PATCH] add traversals --- src/lib.rs | 2 + src/prisms/mod.rs | 1 - src/traversals/both.rs | 27 +++++++++ src/traversals/each.rs | 123 +++++++++++++++++++++++++++++++++++++++++ src/traversals/mod.rs | 98 ++++++++++++++++++++++++++++++++ 5 files changed, 250 insertions(+), 1 deletion(-) create mode 100644 src/traversals/both.rs create mode 100644 src/traversals/each.rs create mode 100644 src/traversals/mod.rs diff --git a/src/lib.rs b/src/lib.rs index 039b4d7..0cbf6c1 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -5,6 +5,7 @@ pub trait OpticsTrait {} /// Wrapper type #[derive(Clone, Copy)] +#[repr(transparent)] pub struct Optics(pub(crate) T); impl OpticsTrait for Optics {} @@ -12,3 +13,4 @@ mod combinations; mod fns; pub mod lenses; pub mod prisms; +pub mod traversals; diff --git a/src/prisms/mod.rs b/src/prisms/mod.rs index d68601f..6ae71cf 100644 --- a/src/prisms/mod.rs +++ b/src/prisms/mod.rs @@ -1,6 +1,5 @@ use crate::{Optics, OpticsTrait}; -/// For lenses that allow viewing pub trait PrismPreview: OpticsTrait { type Field; diff --git a/src/traversals/both.rs b/src/traversals/both.rs new file mode 100644 index 0000000..0a05ecf --- /dev/null +++ b/src/traversals/both.rs @@ -0,0 +1,27 @@ +use crate::{ + traversals::{TraversalOver, TraversalTraverse}, + Optics, OpticsTrait, +}; + +#[derive(Clone, Copy)] +pub struct BothInner; +#[allow(non_upper_case_globals)] +pub const both: Optics = Optics(BothInner); +impl OpticsTrait for BothInner {} + +impl TraversalTraverse<(T, T)> for BothInner { + type Field = T; + + fn traverse(&self, (a, b): (T, T)) -> Vec { + vec![a, b] + } +} + +impl TraversalOver<(T, T)> for BothInner { + fn over(&self, (a, b): (T, T), mut f: F) -> (T, T) + where + F: FnMut(Self::Field) -> Self::Field, + { + (f(a), f(b)) + } +} diff --git a/src/traversals/each.rs b/src/traversals/each.rs new file mode 100644 index 0000000..5b26750 --- /dev/null +++ b/src/traversals/each.rs @@ -0,0 +1,123 @@ +use crate::{ + traversals::{TraversalOver, TraversalTraverse}, + Optics, OpticsTrait, +}; + +#[derive(Clone, Copy)] +pub struct EachInner; +#[allow(non_upper_case_globals)] +pub const each: Optics = Optics(EachInner); +impl OpticsTrait for EachInner {} + +impl TraversalTraverse> for EachInner { + type Field = T; + + fn traverse(&self, thing: Vec) -> Vec { + thing + } +} + +impl TraversalOver> for EachInner { + fn over(&self, thing: Vec, f: F) -> Vec + where + F: FnMut(Self::Field) -> Self::Field, + { + thing.into_iter().map(f).collect() + } +} + +macro_rules! make_tuples { + ($f:ident, ( $( $v:ident ),* ), ( $( $t:ident ),* ) ) => { + impl TraversalTraverse<( $($t,)* )> for EachInner { + type Field = T; + + fn traverse(&self, ( $($v,)* ): ($($t,)*)) -> Vec { + vec![ $($v,)* ] + } + } + impl TraversalOver<( $($t,)* )> for EachInner { + fn over( + &self, + ($($v,)*): ($($t,)*), + mut f: F + ) -> ( $($t,)* ) + where + F: FnMut(Self::Field) -> Self::Field + { + + ( $( f($v), )* ) + } + } + + impl<'a, T> TraversalTraverse<&'a ( $($t,)* )> for EachInner { + type Field = &'a T; + + fn traverse(&self, ( $($v,)* ): &'a ($($t,)*)) -> Vec { + vec![ $($v,)* ] + } + } + impl<'a, T> TraversalTraverse<&'a mut ( $($t,)* )> for EachInner { + type Field = &'a mut T; + + fn traverse(&self, ( $($v,)* ): &'a mut ($($t,)*)) -> Vec { + vec![ $($v,)* ] + } + } + }; +} + +make_tuples!(t, (t), (T)); +make_tuples!(t, (t, u), (T, T)); +make_tuples!(t, (t, u, v), (T, T, T)); +make_tuples!(t, (t, u, v, w), (T, T, T, T)); +make_tuples!(t, (t, u, v, w, x), (T, T, T, T, T)); +make_tuples!(t, (t, u, v, w, x, y), (T, T, T, T, T, T)); +make_tuples!(t, (t, u, v, w, x, y, z), (T, T, T, T, T, T, T)); +// not doing more cause i'm lazy, open a pr if you need more :) + +macro_rules! make_arrays { + ($f:ident, $n:expr, [$( $v:ident ),*]) => { + impl TraversalTraverse<[T; $n]> for EachInner { + type Field = T; + + fn traverse(&self, [ $($v,)* ]: [T; $n]) -> Vec { + vec![ $($v,)* ] + } + } + impl TraversalOver<[T; $n]> for EachInner { + fn over( + &self, + [ $($v,)* ]: [T; $n], + mut fun: F + ) -> [T; $n] + where + F: FnMut(Self::Field) -> Self::Field + { + [$(fun($v),)*] + } + } + + impl<'a, T> TraversalTraverse<&'a [T; $n]> for EachInner { + type Field = &'a T; + + fn traverse(&self, [ $($v,)* ]: &'a [T; $n]) -> Vec { + vec![ $($v,)* ] + } + } + impl<'a, T> TraversalTraverse<&'a mut [T; $n]> for EachInner { + type Field = &'a mut T; + + fn traverse(&self, [ $($v,)* ]: &'a mut [T; $n]) -> Vec { + vec![ $($v,)* ] + } + } + }; +} + +make_arrays!(t, 1, [t]); +make_arrays!(t, 2, [t, _a]); +make_arrays!(t, 3, [t, _a, _b]); +make_arrays!(t, 4, [t, _a, _b, _c]); +make_arrays!(t, 5, [t, _a, _b, _c, _d]); +make_arrays!(t, 6, [t, _a, _b, _c, _d, _e]); +make_arrays!(t, 7, [t, _a, _b, _c, _d, _e, _g]); diff --git a/src/traversals/mod.rs b/src/traversals/mod.rs new file mode 100644 index 0000000..753910a --- /dev/null +++ b/src/traversals/mod.rs @@ -0,0 +1,98 @@ +use crate::{Optics, OpticsTrait}; + +mod both; +pub use both::both; + +mod each; +pub use each::each; + +/// For lenses that allow viewing +pub trait TraversalTraverse: OpticsTrait { + type Field; + + fn traverse(&self, thing: T) -> Vec; +} + +/// For lenses that allow setting +pub trait TraversalOver: TraversalTraverse { + fn over(&self, thing: T, f: F) -> T + where + F: FnMut(Self::Field) -> Self::Field; + + fn set(&self, thing: T, v: Self::Field) -> T + where + Self::Field: Clone, + { + Self::over(self, thing, move |_| v.clone()) + } +} +impl TraversalTraverse for Optics +where + L: TraversalTraverse, +{ + type Field = L::Field; + + fn traverse(&self, thing: T) -> Vec { + L::traverse(&self.0, thing) + } +} +impl TraversalOver for Optics +where + L: TraversalOver, +{ + fn over(&self, thing: T, f: F) -> T + where + F: FnMut(Self::Field) -> Self::Field, + { + L::over(&self.0, thing, f) + } +} + +// // every lens is also a traversal +// impl TraversalTraverse for Optics +// where +// L: LensView, +// { +// type Field = L::Field; + +// fn traverse(&self, thing: T) -> Vec { +// vec![L::view(&self.0, thing)] +// } +// } +// impl TraversalOver for Optics +// where +// L: LensOver, +// { +// fn over(&self, thing: T, f: F) -> T +// where +// F: FnMut(Self::Field) -> Self::Field, +// { +// L::over(&self.0, thing, f) +// } +// } + +pub fn traverse>(lens: L, thing: T) -> Vec { + L::traverse(&lens, thing) +} +pub fn set>(lens: L, thing: T, v: L::Field) -> T +where + >::Field: Clone, +{ + L::set(&lens, thing, v) +} +pub fn over>(lens: L, thing: T, f: impl FnMut(L::Field) -> L::Field) -> T { + L::over(&lens, thing, f) +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn traverse_each_works_on_arrays() { + let array = [1, 2, 3, 4]; + + let res = over(each, array, |v| v + 1); + assert_eq!(res, [2, 3, 4, 5]); + } +}