add traversals
This commit is contained in:
parent
e6163ea626
commit
e5a9293ec2
5 changed files with 250 additions and 1 deletions
|
@ -5,6 +5,7 @@ pub trait OpticsTrait {}
|
|||
|
||||
/// Wrapper type
|
||||
#[derive(Clone, Copy)]
|
||||
#[repr(transparent)]
|
||||
pub struct Optics<T: OpticsTrait>(pub(crate) T);
|
||||
impl<L: OpticsTrait> OpticsTrait for Optics<L> {}
|
||||
|
||||
|
@ -12,3 +13,4 @@ mod combinations;
|
|||
mod fns;
|
||||
pub mod lenses;
|
||||
pub mod prisms;
|
||||
pub mod traversals;
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
use crate::{Optics, OpticsTrait};
|
||||
|
||||
/// For lenses that allow viewing
|
||||
pub trait PrismPreview<T>: OpticsTrait {
|
||||
type Field;
|
||||
|
||||
|
|
27
src/traversals/both.rs
Normal file
27
src/traversals/both.rs
Normal file
|
@ -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<BothInner> = Optics(BothInner);
|
||||
impl OpticsTrait for BothInner {}
|
||||
|
||||
impl<T> TraversalTraverse<(T, T)> for BothInner {
|
||||
type Field = T;
|
||||
|
||||
fn traverse(&self, (a, b): (T, T)) -> Vec<Self::Field> {
|
||||
vec![a, b]
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> TraversalOver<(T, T)> for BothInner {
|
||||
fn over<F>(&self, (a, b): (T, T), mut f: F) -> (T, T)
|
||||
where
|
||||
F: FnMut(Self::Field) -> Self::Field,
|
||||
{
|
||||
(f(a), f(b))
|
||||
}
|
||||
}
|
123
src/traversals/each.rs
Normal file
123
src/traversals/each.rs
Normal file
|
@ -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<EachInner> = Optics(EachInner);
|
||||
impl OpticsTrait for EachInner {}
|
||||
|
||||
impl<T> TraversalTraverse<Vec<T>> for EachInner {
|
||||
type Field = T;
|
||||
|
||||
fn traverse(&self, thing: Vec<T>) -> Vec<Self::Field> {
|
||||
thing
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> TraversalOver<Vec<T>> for EachInner {
|
||||
fn over<F>(&self, thing: Vec<T>, f: F) -> Vec<T>
|
||||
where
|
||||
F: FnMut(Self::Field) -> Self::Field,
|
||||
{
|
||||
thing.into_iter().map(f).collect()
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! make_tuples {
|
||||
($f:ident, ( $( $v:ident ),* ), ( $( $t:ident ),* ) ) => {
|
||||
impl<T> TraversalTraverse<( $($t,)* )> for EachInner {
|
||||
type Field = T;
|
||||
|
||||
fn traverse(&self, ( $($v,)* ): ($($t,)*)) -> Vec<Self::Field> {
|
||||
vec![ $($v,)* ]
|
||||
}
|
||||
}
|
||||
impl<T> TraversalOver<( $($t,)* )> for EachInner {
|
||||
fn over<F>(
|
||||
&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<Self::Field> {
|
||||
vec![ $($v,)* ]
|
||||
}
|
||||
}
|
||||
impl<'a, T> TraversalTraverse<&'a mut ( $($t,)* )> for EachInner {
|
||||
type Field = &'a mut T;
|
||||
|
||||
fn traverse(&self, ( $($v,)* ): &'a mut ($($t,)*)) -> Vec<Self::Field> {
|
||||
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<T> TraversalTraverse<[T; $n]> for EachInner {
|
||||
type Field = T;
|
||||
|
||||
fn traverse(&self, [ $($v,)* ]: [T; $n]) -> Vec<Self::Field> {
|
||||
vec![ $($v,)* ]
|
||||
}
|
||||
}
|
||||
impl<T> TraversalOver<[T; $n]> for EachInner {
|
||||
fn over<F>(
|
||||
&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<Self::Field> {
|
||||
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<Self::Field> {
|
||||
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]);
|
98
src/traversals/mod.rs
Normal file
98
src/traversals/mod.rs
Normal file
|
@ -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<T>: OpticsTrait {
|
||||
type Field;
|
||||
|
||||
fn traverse(&self, thing: T) -> Vec<Self::Field>;
|
||||
}
|
||||
|
||||
/// For lenses that allow setting
|
||||
pub trait TraversalOver<T>: TraversalTraverse<T> {
|
||||
fn over<F>(&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<L, T> TraversalTraverse<T> for Optics<L>
|
||||
where
|
||||
L: TraversalTraverse<T>,
|
||||
{
|
||||
type Field = L::Field;
|
||||
|
||||
fn traverse(&self, thing: T) -> Vec<Self::Field> {
|
||||
L::traverse(&self.0, thing)
|
||||
}
|
||||
}
|
||||
impl<L, T> TraversalOver<T> for Optics<L>
|
||||
where
|
||||
L: TraversalOver<T>,
|
||||
{
|
||||
fn over<F>(&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<L, T> TraversalTraverse<T> for Optics<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 Optics<L>
|
||||
// where
|
||||
// L: 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> {
|
||||
L::traverse(&lens, thing)
|
||||
}
|
||||
pub fn set<T, L: TraversalOver<T>>(lens: L, thing: T, v: L::Field) -> T
|
||||
where
|
||||
<L as TraversalTraverse<T>>::Field: Clone,
|
||||
{
|
||||
L::set(&lens, thing, v)
|
||||
}
|
||||
pub fn over<T, L: TraversalOver<T>>(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]);
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue