diff --git a/src/combinations.rs b/src/combinations.rs new file mode 100644 index 0000000..a874963 --- /dev/null +++ b/src/combinations.rs @@ -0,0 +1,41 @@ +use crate::{Lens, LensOver, LensTrait, LensView}; + +pub struct Combination(A, B); +impl LensTrait for Combination {} + +impl std::ops::Add> for Lens +where + A: LensTrait, + B: LensTrait, +{ + type Output = Lens, Lens>>; + + fn add(self, rhs: Lens) -> Self::Output { + Lens(Combination(self, rhs)) + } +} + +impl LensView for Combination +where + A: LensView, + B: LensView, +{ + type Field = B::Field; + + fn view(thing: T) -> Self::Field { + B::view(A::view(thing)) + } +} + +impl LensOver for Combination +where + A: LensOver, + B: LensOver, +{ + fn over(thing: T, f: F) -> T + where + F: FnOnce(Self::Field) -> Self::Field, + { + A::over(thing, |b| B::over(b, f)) + } +} diff --git a/src/lenses/first.rs b/src/lenses/first.rs index 3c717b3..d8bd328 100644 --- a/src/lenses/first.rs +++ b/src/lenses/first.rs @@ -1,17 +1,19 @@ -use crate::{LensOver, LensView}; +use crate::{Lens, LensOver, LensTrait, LensView}; -pub struct _0; +pub struct _0Inner; +pub const _0: Lens<_0Inner> = Lens(_0Inner); +impl LensTrait for _0Inner {} macro_rules! make_tuples { ($f:ident, ( $( $v:ident ),* ), ( $( $t:ident ),* ) ) => { - impl< $($t,)* > LensView<( $($t,)* )> for _0 { + impl< $($t,)* > LensView<( $($t,)* )> for _0Inner { type Field = T; fn view(( $($v,)* ): ($($t,)*)) -> Self::Field { $f } } - impl< $($t,)* > LensOver<( $($t,)* )> for _0 { + impl< $($t,)* > LensOver<( $($t,)* )> for _0Inner { fn over( mut tup: ($($t,)*), f: F @@ -24,14 +26,14 @@ macro_rules! make_tuples { } } - impl<'a, $($t,)* > LensView<&'a ( $($t,)* )> for _0 { + impl<'a, $($t,)* > LensView<&'a ( $($t,)* )> for _0Inner { type Field = &'a T; fn view(( $($v,)* ): &'a ($($t,)*)) -> Self::Field { $f } } - impl<'a, $($t,)* > LensView<&'a mut ( $($t,)* )> for _0 { + impl<'a, $($t,)* > LensView<&'a mut ( $($t,)* )> for _0Inner { type Field = &'a mut T; fn view(( $($v,)* ): &'a mut ($($t,)*)) -> Self::Field { @@ -51,14 +53,14 @@ make_tuples!(t, (t, _u, _v, _w, _x, _y, _z), (T, U, V, W, X, Y, Z)); macro_rules! make_arrays { ($f:ident, $n:expr, [$( $v:ident ),*]) => { - impl LensView<[T; $n]> for _0 { + impl LensView<[T; $n]> for _0Inner { type Field = T; fn view([ $($v,)* ]: [T; $n]) -> Self::Field { $f } } - impl LensOver<[T; $n]> for _0 { + impl LensOver<[T; $n]> for _0Inner { fn over( tup: [T; $n], fun: F @@ -72,14 +74,14 @@ macro_rules! make_arrays { } } - impl<'a, T> LensView<&'a [T; $n]> for _0 { + impl<'a, T> LensView<&'a [T; $n]> for _0Inner { type Field = &'a T; fn view([ $($v,)* ]: &'a [T; $n]) -> Self::Field { $f } } - impl<'a, T> LensView<&'a mut [T; $n]> for _0 { + impl<'a, T> LensView<&'a mut [T; $n]> for _0Inner { type Field = &'a mut T; fn view([ $($v,)* ]: &'a mut [T; $n]) -> Self::Field { diff --git a/src/lenses/identity.rs b/src/lenses/identity.rs index d90c02f..e62f87c 100644 --- a/src/lenses/identity.rs +++ b/src/lenses/identity.rs @@ -1,16 +1,17 @@ -use crate::{LensOver, LensView}; +use crate::{LensOver, LensTrait, LensView}; #[allow(non_camel_case_types)] pub struct id; -impl LensView for T { +impl LensTrait for id {} +impl LensView for id { type Field = T; fn view(thing: T) -> Self::Field { thing } } -impl LensOver for T { +impl LensOver for id { fn over(thing: T, f: F) -> T where F: FnOnce(Self::Field) -> Self::Field, diff --git a/src/lenses/mod.rs b/src/lenses/mod.rs index 8b1989a..daadf20 100644 --- a/src/lenses/mod.rs +++ b/src/lenses/mod.rs @@ -1,4 +1,7 @@ mod identity; pub use identity::id; + mod first; pub use first::_0; +mod second; +pub use second::_1; diff --git a/src/lenses/second.rs b/src/lenses/second.rs new file mode 100644 index 0000000..506e78c --- /dev/null +++ b/src/lenses/second.rs @@ -0,0 +1,99 @@ +use crate::{Lens, LensOver, LensTrait, LensView}; + +pub struct _1Inner; +pub const _1: Lens<_1Inner> = Lens(_1Inner); +impl LensTrait for _1Inner {} + +macro_rules! make_tuples { + ($f:ident, ( $( $v:ident ),* ), ( $( $t:ident ),* ) ) => { + impl< $($t,)* > LensView<( $($t,)* )> for _1Inner { + type Field = T; + + fn view(( $($v,)* ): ($($t,)*)) -> Self::Field { + $f + } + } + impl< $($t,)* > LensOver<( $($t,)* )> for _1Inner { + fn over( + mut tup: ($($t,)*), + f: F + ) -> ( $($t,)* ) + where + F: FnOnce(Self::Field) -> Self::Field + { + tup.1 = f(tup.1); + tup + } + } + + impl<'a, $($t,)* > LensView<&'a ( $($t,)* )> for _1Inner { + type Field = &'a T; + + fn view(( $($v,)* ): &'a ($($t,)*)) -> Self::Field { + $f + } + } + impl<'a, $($t,)* > LensView<&'a mut ( $($t,)* )> for _1Inner { + type Field = &'a mut T; + + fn view(( $($v,)* ): &'a mut ($($t,)*)) -> Self::Field { + $f + } + } + }; +} + +make_tuples!(t, (_u, t), (U, T)); +make_tuples!(t, (_u, t, _v), (U, T, V)); +make_tuples!(t, (_u, t, _v, _w), (U, T, V, W)); +make_tuples!(t, (_u, t, _v, _w, _x), (U, T, V, W, X)); +make_tuples!(t, (_u, t, _v, _w, _x, _y), (U, T, V, W, X, Y)); +make_tuples!(t, (_u, t, _v, _w, _x, _y, _z), (U, T, V, W, X, Y, Z)); +// 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 LensView<[T; $n]> for _1Inner { + type Field = T; + + fn view([ $($v,)* ]: [T; $n]) -> Self::Field { + $f + } + } + impl LensOver<[T; $n]> for _1Inner { + fn over( + tup: [T; $n], + fun: F + ) -> [T; $n] + where + F: FnOnce(Self::Field) -> Self::Field + { + let [$($v,)*] = tup; + let $f = fun( $f ); + [$($v,)*] + } + } + + impl<'a, T> LensView<&'a [T; $n]> for _1Inner { + type Field = &'a T; + + fn view([ $($v,)* ]: &'a [T; $n]) -> Self::Field { + $f + } + } + impl<'a, T> LensView<&'a mut [T; $n]> for _1Inner { + type Field = &'a mut T; + + fn view([ $($v,)* ]: &'a mut [T; $n]) -> Self::Field { + $f + } + } + }; +} + +make_arrays!(t, 2, [_a, t]); +make_arrays!(t, 3, [_a, t, _b]); +make_arrays!(t, 4, [_a, t, _b, _c]); +make_arrays!(t, 5, [_a, t, _b, _c, _d]); +make_arrays!(t, 6, [_a, t, _b, _c, _d, _e]); +make_arrays!(t, 7, [_a, t, _b, _c, _d, _e, _g]); diff --git a/src/lib.rs b/src/lib.rs index 979a10c..f49eae2 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,9 +1,14 @@ -pub trait LensView { +/// Base trait +pub trait LensTrait {} + +/// For lenses that allow viewing +pub trait LensView: LensTrait { type Field; fn view(thing: T) -> Self::Field; } +/// For lenses that allow setting pub trait LensOver: LensView { fn over(thing: T, f: F) -> T where @@ -14,6 +19,32 @@ pub trait LensOver: LensView { } } +/// Wrapper type +pub struct Lens(T); + +impl LensTrait for Lens {} +impl LensView for Lens +where + L: LensView, +{ + type Field = L::Field; + + fn view(thing: T) -> Self::Field { + L::view(thing) + } +} +impl LensOver for Lens +where + L: LensOver, +{ + fn over(thing: T, f: F) -> T + where + F: FnOnce(Self::Field) -> Self::Field, + { + L::over(thing, f) + } +} + pub fn view>(_lens: L, thing: T) -> L::Field { L::view(thing) } @@ -24,11 +55,11 @@ pub fn over>(_lens: L, thing: T, f: impl FnOnce(L::Field) -> L L::over(thing, f) } -// TODO add Fn implementation for lenses -// with one param it should be view, with two it should be over -// TODO add std::ops::Add to combine lenses +mod combinations; -// TODO add second_from_tuple, etc +// TODO add fn impls + +// TODO add third_from_tuple, etc // TODO array traversals @@ -38,17 +69,16 @@ pub mod lenses; #[cfg(test)] mod tests { - use super::{lenses::_0, *}; + use super::{ + lenses::{_0, _1}, + *, + }; #[test] fn view_first_from_tuple() { let a = (1, 2); assert_eq!(view(_0, a), 1); - // you can call it both ways - let a = (1, 2); - assert_eq!(_0::view(a), 1); - let a = (1, 2); assert_eq!(view(_0, &a), &1); @@ -75,10 +105,6 @@ mod tests { let a = (1, 2); let a = set(_0, a, 3); assert_eq!(a, (3, 2)); - - let a = (1, 2); - let a = _0::set(a, 3); - assert_eq!(a, (3, 2)); } #[test] @@ -86,17 +112,42 @@ mod tests { let a = (1, 2); let a = over(_0, a, |v| v + 1); assert_eq!(a, (2, 2)); - - let a = (1, 2); - let a = _0::over(a, |v| v + 1); - assert_eq!(a, (2, 2)); } #[test] fn over_first_from_array() { let a = [1, 2, 3, 4]; - let a = _0::over(a, |v| v + 1); + let a = over(_0, a, |v| v + 1); assert_eq!(a, [2, 2, 3, 4]); } + + #[test] + fn second() { + let a = (1, 2); + let a = over(_1, a, |v| v + 1); + assert_eq!(a, (1, 3)); + + let a = [1, 2, 3, 4]; + let a = over(_1, a, |v| v + 1); + assert_eq!(a, [1, 3, 3, 4]); + } + + #[test] + fn view_combination() { + let a = ((1, 2), 3); + + let lens = _0 + _1; + let a = view(lens, a); + assert_eq!(a, 2); + } + + #[test] + fn over_combination() { + let a = ((1, 2), 3); + + let lens = _0 + _1; + let a = over(lens, a, |v| v + 1); + assert_eq!(a, ((1, 3), 3)); + } }