combination of traversals
parent
f73c2ad5b6
commit
6b339ddde1
|
@ -1,8 +1,13 @@
|
||||||
use crate::lenses::{Lens, LensOver, LensView};
|
use crate::{
|
||||||
|
lenses::{Lens, LensOver, LensView},
|
||||||
|
traversals::{Traversal, TraversalOver, TraversalTraverse},
|
||||||
|
};
|
||||||
|
|
||||||
#[derive(Clone, Copy)]
|
#[derive(Clone, Copy)]
|
||||||
pub struct Combination<A, B>(A, B);
|
pub struct Combination<A, B>(A, B);
|
||||||
|
|
||||||
|
// additions
|
||||||
|
|
||||||
impl<A, B> std::ops::Add<Lens<B>> for Lens<A> {
|
impl<A, B> std::ops::Add<Lens<B>> for Lens<A> {
|
||||||
type Output = Lens<Combination<Lens<A>, Lens<B>>>;
|
type Output = Lens<Combination<Lens<A>, Lens<B>>>;
|
||||||
|
|
||||||
|
@ -10,6 +15,29 @@ impl<A, B> std::ops::Add<Lens<B>> for Lens<A> {
|
||||||
Lens(Combination(self, rhs))
|
Lens(Combination(self, rhs))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
impl<A, B> std::ops::Add<Traversal<B>> for Traversal<A> {
|
||||||
|
type Output = Traversal<Combination<Traversal<A>, Traversal<B>>>;
|
||||||
|
|
||||||
|
fn add(self, rhs: Traversal<B>) -> Self::Output {
|
||||||
|
Traversal(Combination(self, rhs))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl<A, B> std::ops::Add<Lens<B>> for Traversal<A> {
|
||||||
|
type Output = Traversal<Combination<Traversal<A>, Traversal<Lens<B>>>>;
|
||||||
|
|
||||||
|
fn add(self, rhs: Lens<B>) -> Self::Output {
|
||||||
|
Traversal(Combination(self, rhs.to_traversal()))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl<A, B> std::ops::Add<Traversal<B>> for Lens<A> {
|
||||||
|
type Output = Traversal<Combination<Traversal<Lens<A>>, Traversal<B>>>;
|
||||||
|
|
||||||
|
fn add(self, rhs: Traversal<B>) -> Self::Output {
|
||||||
|
Traversal(Combination(self.to_traversal(), rhs))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// trait impls for Combination
|
||||||
|
|
||||||
impl<A, B, T> LensView<T> for Combination<A, B>
|
impl<A, B, T> LensView<T> for Combination<A, B>
|
||||||
where
|
where
|
||||||
|
@ -35,3 +63,32 @@ where
|
||||||
A::over(&self.0, thing, |b| B::over(&self.1, b, f))
|
A::over(&self.0, thing, |b| B::over(&self.1, b, f))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<A, B, T> TraversalTraverse<T> for Combination<A, B>
|
||||||
|
where
|
||||||
|
A: TraversalTraverse<T>,
|
||||||
|
B: TraversalTraverse<A::Field>,
|
||||||
|
{
|
||||||
|
type Field = B::Field;
|
||||||
|
|
||||||
|
fn traverse(&self, thing: T) -> Vec<Self::Field> {
|
||||||
|
let a = A::traverse(&self.0, thing);
|
||||||
|
a.into_iter()
|
||||||
|
.map(|v| B::traverse(&self.1, v))
|
||||||
|
.flatten()
|
||||||
|
.collect()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<A, B, T> TraversalOver<T> for Combination<A, B>
|
||||||
|
where
|
||||||
|
A: TraversalOver<T>,
|
||||||
|
B: TraversalOver<A::Field>,
|
||||||
|
{
|
||||||
|
fn over<F>(&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))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -3,16 +3,16 @@ use crate::lenses::{Lens, LensOver, LensView};
|
||||||
type Getter<T, U> = dyn Fn(T) -> U;
|
type Getter<T, U> = dyn Fn(T) -> U;
|
||||||
type Setter<T, U> = dyn Fn(T, U) -> T;
|
type Setter<T, U> = dyn Fn(T, U) -> T;
|
||||||
|
|
||||||
pub struct LensInner<T, U>(pub(crate) Box<Getter<T, U>>, pub(crate) Box<Setter<T, U>>);
|
pub struct FuncLens<T, U>(pub(crate) Box<Getter<T, U>>, pub(crate) Box<Setter<T, U>>);
|
||||||
|
|
||||||
impl<T, U> LensView<T> for LensInner<T, U> {
|
impl<T, U> LensView<T> for FuncLens<T, U> {
|
||||||
type Field = U;
|
type Field = U;
|
||||||
|
|
||||||
fn view(&self, thing: T) -> Self::Field {
|
fn view(&self, thing: T) -> Self::Field {
|
||||||
(self.0)(thing)
|
(self.0)(thing)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
impl<T: Clone, U> LensOver<T> for LensInner<T, U> {
|
impl<T: Clone, U> LensOver<T> for FuncLens<T, U> {
|
||||||
fn over<F>(&self, thing: T, f: F) -> T
|
fn over<F>(&self, thing: T, f: F) -> T
|
||||||
where
|
where
|
||||||
F: FnOnce(Self::Field) -> Self::Field,
|
F: FnOnce(Self::Field) -> Self::Field,
|
||||||
|
@ -30,13 +30,13 @@ impl<T: Clone, U> LensOver<T> for LensInner<T, U> {
|
||||||
pub fn lens_from_boxed<T, U>(
|
pub fn lens_from_boxed<T, U>(
|
||||||
getter: Box<Getter<T, U>>,
|
getter: Box<Getter<T, U>>,
|
||||||
setter: Box<Setter<T, U>>,
|
setter: Box<Setter<T, U>>,
|
||||||
) -> Lens<LensInner<T, U>> {
|
) -> Lens<FuncLens<T, U>> {
|
||||||
Lens(LensInner(getter, setter))
|
Lens(FuncLens(getter, setter))
|
||||||
}
|
}
|
||||||
/// Makes a lens that implements `LensView<T>` and `LensOver<T>` with the provided functions
|
/// Makes a lens that implements `LensView<T>` and `LensOver<T>` with the provided functions
|
||||||
pub fn lens<T, U>(
|
pub fn lens<T, U>(
|
||||||
getter: impl Fn(T) -> U + 'static,
|
getter: impl Fn(T) -> U + 'static,
|
||||||
setter: impl Fn(T, U) -> T + 'static,
|
setter: impl Fn(T, U) -> T + 'static,
|
||||||
) -> Lens<LensInner<T, U>> {
|
) -> Lens<FuncLens<T, U>> {
|
||||||
Lens(LensInner(Box::new(getter), Box::new(setter)))
|
Lens(FuncLens(Box::new(getter), Box::new(setter)))
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,28 +11,11 @@ pub use to::{to, to_from_boxed};
|
||||||
mod lens;
|
mod lens;
|
||||||
pub use lens::{lens, lens_from_boxed};
|
pub use lens::{lens, lens_from_boxed};
|
||||||
|
|
||||||
use crate::traversals::Traversal;
|
|
||||||
|
|
||||||
/// Wrapper type
|
/// Wrapper type
|
||||||
#[derive(Clone, Copy)]
|
#[derive(Clone, Copy)]
|
||||||
#[repr(transparent)]
|
#[repr(transparent)]
|
||||||
pub struct Lens<L>(pub(crate) L);
|
pub struct Lens<L>(pub(crate) L);
|
||||||
|
|
||||||
// all lenses are traversals, so we can freely transform them into a traversal
|
|
||||||
impl<L> Lens<L> {
|
|
||||||
/// Returns this lens as a traversal
|
|
||||||
pub fn to_traversal(self) -> Traversal<Lens<L>> {
|
|
||||||
Traversal(self)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// we can go back to a lens from a "traversal-ed" lens
|
|
||||||
impl<L> Traversal<Lens<L>> {
|
|
||||||
/// Returns the wrapped lens
|
|
||||||
pub fn to_lens(self) -> Lens<L> {
|
|
||||||
self.0
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// For lenses that allow viewing
|
/// For lenses that allow viewing
|
||||||
pub trait LensView<T> {
|
pub trait LensView<T> {
|
||||||
type Field;
|
type Field;
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
use crate::lenses::{Lens, LensView};
|
use crate::lenses::{Lens, LensView};
|
||||||
|
|
||||||
use super::lens::LensInner;
|
use super::lens::FuncLens;
|
||||||
|
|
||||||
pub struct ToInner<T, U>(Box<dyn Fn(T) -> U>);
|
pub struct ToInner<T, U>(Box<dyn Fn(T) -> U>);
|
||||||
|
|
||||||
|
@ -23,7 +23,7 @@ pub fn to<T, U>(f: impl Fn(T) -> U + 'static) -> Lens<ToInner<T, U>> {
|
||||||
|
|
||||||
impl<T, U> Lens<ToInner<T, U>> {
|
impl<T, U> Lens<ToInner<T, U>> {
|
||||||
/// Makes a full lens that implements `LensView<T>` and `LensOver<T>` with the provided functions
|
/// Makes a full lens that implements `LensView<T>` and `LensOver<T>` with the provided functions
|
||||||
pub fn make_lens(self, setter: impl Fn(T, U) -> T + 'static) -> Lens<LensInner<T, U>> {
|
pub fn make_lens(self, setter: impl Fn(T, U) -> T + 'static) -> Lens<FuncLens<T, U>> {
|
||||||
Lens(LensInner((self.0).0, Box::new(setter)))
|
Lens(FuncLens((self.0).0, Box::new(setter)))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,6 +4,8 @@ pub use both::both;
|
||||||
mod each;
|
mod each;
|
||||||
pub use each::each;
|
pub use each::each;
|
||||||
|
|
||||||
|
use crate::lenses::{Lens, LensOver, LensView};
|
||||||
|
|
||||||
/// Wrapper type
|
/// Wrapper type
|
||||||
#[derive(Clone, Copy)]
|
#[derive(Clone, Copy)]
|
||||||
#[repr(transparent)]
|
#[repr(transparent)]
|
||||||
|
@ -14,7 +16,6 @@ pub trait TraversalTraverse<T> {
|
||||||
|
|
||||||
fn traverse(&self, thing: T) -> Vec<Self::Field>;
|
fn traverse(&self, thing: T) -> Vec<Self::Field>;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait TraversalOver<T>: TraversalTraverse<T> {
|
pub trait TraversalOver<T>: TraversalTraverse<T> {
|
||||||
fn over<F>(&self, thing: T, f: F) -> T
|
fn over<F>(&self, thing: T, f: F) -> T
|
||||||
where
|
where
|
||||||
|
@ -27,6 +28,7 @@ pub trait TraversalOver<T>: TraversalTraverse<T> {
|
||||||
Self::over(self, thing, move |_| v.clone())
|
Self::over(self, thing, move |_| v.clone())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<L, T> TraversalTraverse<T> for Traversal<L>
|
impl<L, T> TraversalTraverse<T> for Traversal<L>
|
||||||
where
|
where
|
||||||
L: TraversalTraverse<T>,
|
L: TraversalTraverse<T>,
|
||||||
|
@ -49,6 +51,42 @@ where
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// all lenses are traversals, so we can freely transform them into a traversal
|
||||||
|
impl<L> Lens<L> {
|
||||||
|
/// Returns this lens as a traversal
|
||||||
|
pub fn to_traversal(self) -> Traversal<Lens<L>> {
|
||||||
|
Traversal(self)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// we can go back to a lens from a "traversal-ed" lens
|
||||||
|
impl<L> Traversal<Lens<L>> {
|
||||||
|
/// Returns the wrapped lens
|
||||||
|
pub fn to_lens(self) -> Lens<L> {
|
||||||
|
self.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl<L, T> TraversalTraverse<T> for Lens<L>
|
||||||
|
where
|
||||||
|
L: LensView<T>,
|
||||||
|
{
|
||||||
|
type Field = L::Field;
|
||||||
|
|
||||||
|
fn traverse(&self, thing: T) -> Vec<Self::Field> {
|
||||||
|
vec![L::view(&self.0, thing)]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl<L, T> TraversalOver<T> for Lens<L>
|
||||||
|
where
|
||||||
|
L: LensView<T> + LensOver<T>,
|
||||||
|
{
|
||||||
|
fn over<F>(&self, thing: T, f: F) -> T
|
||||||
|
where
|
||||||
|
F: FnMut(Self::Field) -> Self::Field,
|
||||||
|
{
|
||||||
|
L::over(&self.0, thing, f)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn traverse<T, L: TraversalTraverse<T>>(lens: L, thing: T) -> Vec<L::Field> {
|
pub fn traverse<T, L: TraversalTraverse<T>>(lens: L, thing: T) -> Vec<L::Field> {
|
||||||
L::traverse(&lens, thing)
|
L::traverse(&lens, thing)
|
||||||
}
|
}
|
||||||
|
@ -64,13 +102,59 @@ pub fn over<T, L: TraversalOver<T>>(lens: L, thing: T, f: impl FnMut(L::Field) -
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
|
use crate::lenses::_0;
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn traverse_each_works_on_arrays() {
|
fn traverse_each_works_on_arrays() {
|
||||||
let array = [1, 2, 3, 4];
|
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);
|
let res = each(array, |v| v + 1);
|
||||||
assert_eq!(res, [2, 3, 4, 5]);
|
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)]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue