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));
+ }
}