add traversals

main
annieversary 2021-11-11 12:56:54 +00:00
parent e6163ea626
commit e5a9293ec2
5 changed files with 250 additions and 1 deletions

View File

@ -5,6 +5,7 @@ pub trait OpticsTrait {}
/// Wrapper type /// Wrapper type
#[derive(Clone, Copy)] #[derive(Clone, Copy)]
#[repr(transparent)]
pub struct Optics<T: OpticsTrait>(pub(crate) T); pub struct Optics<T: OpticsTrait>(pub(crate) T);
impl<L: OpticsTrait> OpticsTrait for Optics<L> {} impl<L: OpticsTrait> OpticsTrait for Optics<L> {}
@ -12,3 +13,4 @@ mod combinations;
mod fns; mod fns;
pub mod lenses; pub mod lenses;
pub mod prisms; pub mod prisms;
pub mod traversals;

View File

@ -1,6 +1,5 @@
use crate::{Optics, OpticsTrait}; use crate::{Optics, OpticsTrait};
/// For lenses that allow viewing
pub trait PrismPreview<T>: OpticsTrait { pub trait PrismPreview<T>: OpticsTrait {
type Field; type Field;

27
src/traversals/both.rs Normal file
View 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
View 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
View 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]);
}
}