mod both; pub use both::both; mod each; pub use each::each; use crate::lenses::{Lens, LensOver, LensView}; /// Wrapper type #[derive(Clone, Copy)] #[repr(transparent)] pub struct Traversal(pub(crate) T); pub trait TraversalTraverse { type Field; fn traverse(&self, thing: T) -> Vec; } 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 Traversal where L: TraversalTraverse, { type Field = L::Field; fn traverse(&self, thing: T) -> Vec { L::traverse(&self.0, thing) } } impl TraversalOver for Traversal where L: TraversalOver, { fn over(&self, thing: T, f: F) -> T where F: FnMut(Self::Field) -> Self::Field, { L::over(&self.0, thing, f) } } // all lenses are traversals, so we can freely transform them into a traversal impl Lens { /// Returns this lens as a traversal pub fn to_traversal(self) -> Traversal> { Traversal(self) } } // we can go back to a lens from a "traversal-ed" lens impl Traversal> { /// Returns the wrapped lens pub fn to_lens(self) -> Lens { self.0 } } impl TraversalTraverse for Lens where L: LensView, { type Field = L::Field; fn traverse(&self, thing: T) -> Vec { vec![L::view(&self.0, thing)] } } impl TraversalOver for Lens where L: LensView + 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 crate::lenses::_0; use super::*; #[test] fn traverse_each_works_on_arrays() { let array = [1, 2, 3, 4]; let res = each(array); assert_eq!(res, vec![1, 2, 3, 4,]); let res = each(array, |v| v + 1); assert_eq!(res, [2, 3, 4, 5]); } #[test] fn can_combine_traversals() { let array = [vec![1, 2], vec![3, 4]]; // combine two traversals let res = (each + each)(array, |v| v + 1); assert_eq!(res, [vec![2, 3], vec![4, 5]]); } #[test] fn can_combine_traversal_with_lens() { let array = [(1, 2), (3, 4), (5, 6)]; // combine a traversal with a lens let t = each + _0; // traverse let res = t(array); assert_eq!(res, vec![1, 3, 5]); // over let res = t(array, |v| v + 1); assert_eq!(res, [(2, 2), (4, 4), (6, 6)]); } #[test] fn can_combine_lens_with_traversal() { let array = [(1, 2), (3, 4), (5, 6)]; // combine a traversal with a lens let t = _0 + each; // traverse let res = t(array); assert_eq!(res, vec![1, 2]); // over let res = t(array, |v| v + 1); assert_eq!(res, [(2, 3), (3, 4), (5, 6)]); } }