diff --git a/src/traversals/init.rs b/src/traversals/init.rs new file mode 100644 index 0000000..247774f --- /dev/null +++ b/src/traversals/init.rs @@ -0,0 +1,98 @@ +use crate::traversals::{Traversal, TraversalOver, TraversalTraverse}; + +#[derive(Clone, Copy)] +pub struct InitInner; +#[allow(non_upper_case_globals)] +pub const _init: Traversal = Traversal(InitInner); + +macro_rules! make_tuples { + (( $( $v:ident ),* ), ( $( $t:ident ),* ) ) => { + impl TraversalTraverse<( $($t,)* )> for InitInner { + type Field = T; + + fn traverse(&self, ( $($v,)* _last ): ($($t,)*)) -> Vec { + vec![ $($v,)* ] + } + } + impl TraversalOver<( $($t,)* )> for InitInner { + fn over( + &self, + ($($v,)* last): ($($t,)*), + mut f: F + ) -> ( $($t,)* ) + where + F: FnMut(Self::Field) -> Self::Field + { + ( $(f($v),)* last ) + } + } + + impl<'a, T> TraversalTraverse<&'a ( $($t,)* )> for InitInner { + type Field = &'a T; + + fn traverse(&self, ($($v,)* _last): &'a ($($t,)*)) -> Vec { + vec![ $($v,)* ] + } + } + impl<'a, T> TraversalTraverse<&'a mut ( $($t,)* )> for InitInner { + type Field = &'a mut T; + + fn traverse(&self, ($($v,)* _last): &'a mut ($($t,)*)) -> Vec { + vec![ $($v,)* ] + } + } + }; +} + +make_tuples!((_u), (T, T)); +make_tuples!((_u, _v), (T, T, T)); +make_tuples!((_u, _v, _w), (T, T, T, T)); +make_tuples!((_u, _v, _w, _x), (T, T, T, T, T)); +make_tuples!((_u, _v, _w, _x, _y), (T, T, T, T, T, T)); +make_tuples!((_u, _v, _w, _x, _y, _z), (T, T, T, T, T, T, T)); + +macro_rules! make_arrays { + ($n:expr, [$( $v:ident ),*]) => { + impl TraversalTraverse<[T; $n]> for InitInner { + type Field = T; + + fn traverse(&self, [ $($v,)* _last]: [T; $n]) -> Vec { + vec![ $($v,)* ] + } + } + impl TraversalOver<[T; $n]> for InitInner { + fn over( + &self, + [ $($v,)* last]: [T; $n], + mut fun: F + ) -> [T; $n] + where + F: FnMut(Self::Field) -> Self::Field + { + [$(fun($v),)* last] + } + } + + impl<'a, T> TraversalTraverse<&'a [T; $n]> for InitInner { + type Field = &'a T; + + fn traverse(&self, [$($v,)* _last]: &'a [T; $n]) -> Vec { + vec![ $($v,)* ] + } + } + impl<'a, T> TraversalTraverse<&'a mut [T; $n]> for InitInner { + type Field = &'a mut T; + + fn traverse(&self, [$($v,)* _last ]: &'a mut [T; $n]) -> Vec { + vec![ $($v,)* ] + } + } + }; +} + +make_arrays!(2, [_a]); +make_arrays!(3, [_a, _b]); +make_arrays!(4, [_a, _b, _c]); +make_arrays!(5, [_a, _b, _c, _d]); +make_arrays!(6, [_a, _b, _c, _d, _e]); +make_arrays!(7, [_a, _b, _c, _d, _e, _g]); diff --git a/src/traversals/last.rs b/src/traversals/last.rs new file mode 100644 index 0000000..478ccfc --- /dev/null +++ b/src/traversals/last.rs @@ -0,0 +1,99 @@ +use crate::traversals::{Traversal, TraversalOver, TraversalTraverse}; + +#[derive(Clone, Copy)] +pub struct LastInner; +#[allow(non_upper_case_globals)] +pub const _last: Traversal = Traversal(LastInner); + +macro_rules! make_tuples { + (( $( $v:ident ),* ), ( $( $t:ident ),* ) ) => { + impl TraversalTraverse<( $($t,)* )> for LastInner { + type Field = T; + + fn traverse(&self, ( $($v,)* last ): ($($t,)*)) -> Vec { + vec![ last ] + } + } + impl TraversalOver<( $($t,)* )> for LastInner { + fn over( + &self, + ($($v,)* last): ($($t,)*), + mut f: F + ) -> ( $($t,)* ) + where + F: FnMut(Self::Field) -> Self::Field + { + ( $($v,)* f(last), ) + } + } + + impl<'a, T> TraversalTraverse<&'a ( $($t,)* )> for LastInner { + type Field = &'a T; + + fn traverse(&self, ($($v,)* last): &'a ($($t,)*)) -> Vec { + vec![ last ] + } + } + impl<'a, T> TraversalTraverse<&'a mut ( $($t,)* )> for LastInner { + type Field = &'a mut T; + + fn traverse(&self, ($($v,)* last): &'a mut ($($t,)*)) -> Vec { + vec![ last ] + } + } + }; +} + +make_tuples!((_u), (T, T)); +make_tuples!((_u, _v), (T, T, T)); +make_tuples!((_u, _v, _w), (T, T, T, T)); +make_tuples!((_u, _v, _w, _x), (T, T, T, T, T)); +make_tuples!((_u, _v, _w, _x, _y), (T, T, T, T, T, T)); +make_tuples!((_u, _v, _w, _x, _y, _z), (T, T, T, T, T, T, T)); + +macro_rules! make_arrays { + ($n:expr, [$( $v:ident ),*]) => { + impl TraversalTraverse<[T; $n]> for LastInner { + type Field = T; + + fn traverse(&self, [ $($v,)* last]: [T; $n]) -> Vec { + vec![ last ] + } + } + impl TraversalOver<[T; $n]> for LastInner { + fn over( + &self, + [ $($v,)* last]: [T; $n], + mut fun: F + ) -> [T; $n] + where + F: FnMut(Self::Field) -> Self::Field + { + [$(($v),)* fun(last)] + } + } + + impl<'a, T> TraversalTraverse<&'a [T; $n]> for LastInner { + type Field = &'a T; + + fn traverse(&self, [$($v,)* last]: &'a [T; $n]) -> Vec { + vec![ last ] + } + } + impl<'a, T> TraversalTraverse<&'a mut [T; $n]> for LastInner { + type Field = &'a mut T; + + fn traverse(&self, [ $($v,)* last ]: &'a mut [T; $n]) -> Vec { + vec![ last ] + } + } + }; +} + +make_arrays!(1, []); +make_arrays!(2, [_a]); +make_arrays!(3, [_a, _b]); +make_arrays!(4, [_a, _b, _c]); +make_arrays!(5, [_a, _b, _c, _d]); +make_arrays!(6, [_a, _b, _c, _d, _e]); +make_arrays!(7, [_a, _b, _c, _d, _e, _g]); diff --git a/src/traversals/mod.rs b/src/traversals/mod.rs index df57998..fe88a30 100644 --- a/src/traversals/mod.rs +++ b/src/traversals/mod.rs @@ -9,6 +9,11 @@ pub use head::_head; pub mod tail; pub use tail::_tail; +pub mod init; +pub use init::_init; +pub mod last; +pub use last::_last; + use crate::{ lenses::{Lens, LensOver, LensView}, prisms::{Prism, PrismPreview}, @@ -181,4 +186,26 @@ mod tests { let res = _tail(array, |v| v + 1); assert_eq!(res, [1, 3, 4, 5]); } + + #[test] + fn traverse_init_works_on_arrays() { + let array = [1, 2, 3, 4]; + + let res = _init(array); + assert_eq!(res, vec![1, 2, 3]); + + let res = _init(array, |v| v + 1); + assert_eq!(res, [2, 3, 4, 4,]); + } + + #[test] + fn traverse_last_works_on_arrays() { + let array = [1, 2, 3, 4]; + + let res = _last(array); + assert_eq!(res, vec![4]); + + let res = _last(array, |v| v + 1); + assert_eq!(res, [1, 2, 3, 5]); + } }