diff --git a/src/combinations.rs b/src/combinations.rs
index 60eee2b..9fd4a10 100644
--- a/src/combinations.rs
+++ b/src/combinations.rs
@@ -1,8 +1,13 @@
-use crate::lenses::{Lens, LensOver, LensView};
+use crate::{
+ lenses::{Lens, LensOver, LensView},
+ traversals::{Traversal, TraversalOver, TraversalTraverse},
+};
#[derive(Clone, Copy)]
pub struct Combination(A, B);
+// additions
+
impl std::ops::Add> for Lens {
type Output = Lens, Lens>>;
@@ -10,6 +15,29 @@ impl std::ops::Add> for Lens {
Lens(Combination(self, rhs))
}
}
+impl std::ops::Add> for Traversal {
+ type Output = Traversal, Traversal>>;
+
+ fn add(self, rhs: Traversal) -> Self::Output {
+ Traversal(Combination(self, rhs))
+ }
+}
+impl std::ops::Add> for Traversal {
+ type Output = Traversal, Traversal>>>;
+
+ fn add(self, rhs: Lens) -> Self::Output {
+ Traversal(Combination(self, rhs.to_traversal()))
+ }
+}
+impl std::ops::Add> for Lens {
+ type Output = Traversal>, Traversal>>;
+
+ fn add(self, rhs: Traversal) -> Self::Output {
+ Traversal(Combination(self.to_traversal(), rhs))
+ }
+}
+
+// trait impls for Combination
impl LensView for Combination
where
@@ -35,3 +63,32 @@ where
A::over(&self.0, thing, |b| B::over(&self.1, b, f))
}
}
+
+impl TraversalTraverse for Combination
+where
+ A: TraversalTraverse,
+ B: TraversalTraverse,
+{
+ type Field = B::Field;
+
+ fn traverse(&self, thing: T) -> Vec {
+ let a = A::traverse(&self.0, thing);
+ a.into_iter()
+ .map(|v| B::traverse(&self.1, v))
+ .flatten()
+ .collect()
+ }
+}
+
+impl TraversalOver for Combination
+where
+ A: TraversalOver,
+ B: TraversalOver,
+{
+ fn over(&self, thing: T, mut f: F) -> T
+ where
+ F: FnMut(Self::Field) -> Self::Field,
+ {
+ A::over(&self.0, thing, |b| B::over(&self.1, b, &mut f))
+ }
+}
diff --git a/src/lenses/lens.rs b/src/lenses/lens.rs
index aa83efc..ec8e647 100644
--- a/src/lenses/lens.rs
+++ b/src/lenses/lens.rs
@@ -3,16 +3,16 @@ use crate::lenses::{Lens, LensOver, LensView};
type Getter = dyn Fn(T) -> U;
type Setter = dyn Fn(T, U) -> T;
-pub struct LensInner(pub(crate) Box>, pub(crate) Box>);
+pub struct FuncLens(pub(crate) Box>, pub(crate) Box>);
-impl LensView for LensInner {
+impl LensView for FuncLens {
type Field = U;
fn view(&self, thing: T) -> Self::Field {
(self.0)(thing)
}
}
-impl LensOver for LensInner {
+impl LensOver for FuncLens {
fn over(&self, thing: T, f: F) -> T
where
F: FnOnce(Self::Field) -> Self::Field,
@@ -30,13 +30,13 @@ impl LensOver for LensInner {
pub fn lens_from_boxed(
getter: Box>,
setter: Box>,
-) -> Lens> {
- Lens(LensInner(getter, setter))
+) -> Lens> {
+ Lens(FuncLens(getter, setter))
}
/// Makes a lens that implements `LensView` and `LensOver` with the provided functions
pub fn lens(
getter: impl Fn(T) -> U + 'static,
setter: impl Fn(T, U) -> T + 'static,
-) -> Lens> {
- Lens(LensInner(Box::new(getter), Box::new(setter)))
+) -> Lens> {
+ Lens(FuncLens(Box::new(getter), Box::new(setter)))
}
diff --git a/src/lenses/mod.rs b/src/lenses/mod.rs
index e6ce140..9492ab9 100644
--- a/src/lenses/mod.rs
+++ b/src/lenses/mod.rs
@@ -11,28 +11,11 @@ pub use to::{to, to_from_boxed};
mod lens;
pub use lens::{lens, lens_from_boxed};
-use crate::traversals::Traversal;
-
/// Wrapper type
#[derive(Clone, Copy)]
#[repr(transparent)]
pub struct Lens(pub(crate) L);
-// 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
- }
-}
-
/// For lenses that allow viewing
pub trait LensView {
type Field;
diff --git a/src/lenses/to.rs b/src/lenses/to.rs
index d9309dd..c6e9f24 100644
--- a/src/lenses/to.rs
+++ b/src/lenses/to.rs
@@ -1,6 +1,6 @@
use crate::lenses::{Lens, LensView};
-use super::lens::LensInner;
+use super::lens::FuncLens;
pub struct ToInner(Box U>);
@@ -23,7 +23,7 @@ pub fn to(f: impl Fn(T) -> U + 'static) -> Lens> {
impl Lens> {
/// Makes a full lens that implements `LensView` and `LensOver` with the provided functions
- pub fn make_lens(self, setter: impl Fn(T, U) -> T + 'static) -> Lens> {
- Lens(LensInner((self.0).0, Box::new(setter)))
+ pub fn make_lens(self, setter: impl Fn(T, U) -> T + 'static) -> Lens> {
+ Lens(FuncLens((self.0).0, Box::new(setter)))
}
}
diff --git a/src/traversals/mod.rs b/src/traversals/mod.rs
index d3cfef8..19043ac 100644
--- a/src/traversals/mod.rs
+++ b/src/traversals/mod.rs
@@ -4,6 +4,8 @@ pub use both::both;
mod each;
pub use each::each;
+use crate::lenses::{Lens, LensOver, LensView};
+
/// Wrapper type
#[derive(Clone, Copy)]
#[repr(transparent)]
@@ -14,7 +16,6 @@ pub trait TraversalTraverse {
fn traverse(&self, thing: T) -> Vec;
}
-
pub trait TraversalOver: TraversalTraverse {
fn over(&self, thing: T, f: F) -> T
where
@@ -27,6 +28,7 @@ pub trait TraversalOver: TraversalTraverse {
Self::over(self, thing, move |_| v.clone())
}
}
+
impl TraversalTraverse for Traversal
where
L: TraversalTraverse,
@@ -49,6 +51,42 @@ where
}
}
+// 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)
}
@@ -64,13 +102,59 @@ pub fn over>(lens: L, thing: T, f: impl FnMut(L::Field) -
#[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)]);
+ }
}