Compare commits

..

13 Commits

Author SHA1 Message Date
annieversary 3d82c58a51 prism + lens 2021-11-11 16:07:46 +00:00
annieversary 231f68970f move combination tests 2021-11-11 14:50:21 +00:00
annieversary bf85419c16 fix prisms 2021-11-11 14:47:55 +00:00
annieversary 529b628260 m 2021-11-11 14:16:37 +00:00
annieversary 6b339ddde1 combination of traversals 2021-11-11 13:50:54 +00:00
annieversary f73c2ad5b6 split optics wrapper type into Lens, Traversal, Prism 2021-11-11 13:29:43 +00:00
annieversary e5a9293ec2 add traversals 2021-11-11 12:56:54 +00:00
annieversary e6163ea626 examples and tests 2021-11-11 11:16:04 +00:00
annieversary 2c0a770f9f add to, lens 2021-11-11 11:08:29 +00:00
annieversary 61484339f9 change lenses to take a ref 2021-11-11 10:39:47 +00:00
annieversary ea617b8789 add prisms 2021-11-05 19:35:26 +00:00
annieversary 037440c845 rename lens to optics 2021-11-05 15:55:49 +00:00
annieversary 30996082ac uh 2021-11-05 15:28:34 +00:00
19 changed files with 1319 additions and 233 deletions

1
.gitignore vendored
View File

@ -1,2 +1,3 @@
/target
Cargo.lock
.DS_Store

View File

@ -13,14 +13,21 @@ use bad_optics::{
fn main() {
let a = ((1, 2), 3);
// combine lenses
// use view to access inside the tuple
let res = view(_0, a);
assert_eq!(res, (1, 2));
let res = view(_1, a);
assert_eq!(res, 3);
// you can combine lenses
let lens = _0 + _1;
// use the view function to access
let res = view(lens, a);
assert_eq!(res, 2);
// call the lens as a function
// you can also call the lens as a function
let res = lens(a);
assert_eq!(res, 2);
@ -32,7 +39,7 @@ fn main() {
let a = set(lens, a, 5);
assert_eq!(a, ((1, 5), 3));
// call the lens as a function to modify the value
// you can also call the lens as a function to modify the value
let res = lens(a, |v| v + 1);
assert_eq!(res, ((1, 3), 3));
}

View File

@ -1,19 +1,23 @@
use bad_optics::{
lenses::{_0, _1},
*,
};
use bad_optics::lenses::*;
fn main() {
let a = ((1, 2), 3);
// combine lenses
// use view to access inside the tuple
let res = view(_0, a);
assert_eq!(res, (1, 2));
let res = view(_1, a);
assert_eq!(res, 3);
// you can combine lenses
let lens = _0 + _1;
// use the view function to access
let res = view(lens, a);
assert_eq!(res, 2);
// call the lens as a function
// you can also call the lens as a function
let res = lens(a);
assert_eq!(res, 2);
@ -25,7 +29,7 @@ fn main() {
let a = set(lens, a, 5);
assert_eq!(a, ((1, 5), 3));
// call the lens as a function to modify the value
// you can also call the lens as a function to modify the value
let res = lens(a, |v| v + 1);
assert_eq!(res, ((1, 3), 3));
assert_eq!(res, ((1, 6), 3));
}

27
examples/struct_fields.rs Normal file
View File

@ -0,0 +1,27 @@
use bad_optics::lenses::*;
#[derive(Debug, PartialEq, Clone)]
struct MyStruct {
hey: (u8, (u8, i32)),
}
fn main() {
// make a lens for Hello
let hey = lens(
|hello: MyStruct| hello.hey,
|mut hello: MyStruct, v| {
hello.hey = v;
hello
},
);
let my_struct = MyStruct { hey: (1, (2, -3)) };
// the thing we want to access
let thing = (my_struct, "hello");
// a lens that targets the -3 inside my_struct
let lens_that_targets_the_i32 = _0 + hey + _1 + _1;
assert_eq!(lens_that_targets_the_i32(thing), -3);
}

View File

@ -1,42 +1,324 @@
use crate::{Lens, LensOver, LensTrait, LensView};
use crate::{
lenses::{Lens, LensOver, LensView},
prisms::{Prism, PrismPreview},
traversals::{Traversal, TraversalOver, TraversalTraverse},
};
#[derive(Clone, Copy)]
pub struct Combination<A, B>(A, B);
impl<A, B> LensTrait for Combination<A, B> {}
impl<A, B> std::ops::Add<Lens<B>> for Lens<A>
where
A: LensTrait,
B: LensTrait,
{
// additions
// lens + lens
impl<A, B> std::ops::Add<Lens<B>> for Lens<A> {
type Output = Lens<Combination<Lens<A>, Lens<B>>>;
fn add(self, rhs: Lens<B>) -> Self::Output {
Lens(Combination(self, rhs))
}
}
// prism + prism
impl<A, B> std::ops::Add<Prism<B>> for Prism<A> {
type Output = Prism<Combination<Prism<A>, Prism<B>>>;
impl<A, B, T> LensView<T> for Combination<A, B>
fn add(self, rhs: Prism<B>) -> Self::Output {
Prism(Combination(self, rhs))
}
}
// traversal + traversal
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))
}
}
// traversal + lens
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()))
}
}
// lens + 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))
}
}
// traversal + prism
impl<A, B> std::ops::Add<Prism<B>> for Traversal<A> {
type Output = Traversal<Combination<Traversal<A>, Traversal<Prism<B>>>>;
fn add(self, rhs: Prism<B>) -> Self::Output {
Traversal(Combination(self, rhs.to_traversal()))
}
}
// prism + traversal
impl<A, B> std::ops::Add<Traversal<B>> for Prism<A> {
type Output = Traversal<Combination<Traversal<Prism<A>>, Traversal<B>>>;
fn add(self, rhs: Traversal<B>) -> Self::Output {
Traversal(Combination(self.to_traversal(), rhs))
}
}
// lens + prism
impl<A, B> std::ops::Add<Prism<B>> for Lens<A> {
type Output = Traversal<Combination<Traversal<Lens<A>>, Traversal<Prism<B>>>>;
fn add(self, rhs: Prism<B>) -> Self::Output {
Traversal(Combination(self.to_traversal(), rhs.to_traversal()))
}
}
// prism + traversal
impl<A, B> std::ops::Add<Lens<B>> for Prism<A> {
type Output = Traversal<Combination<Traversal<Prism<A>>, Traversal<Lens<B>>>>;
fn add(self, rhs: Lens<B>) -> Self::Output {
Traversal(Combination(self.to_traversal(), rhs.to_traversal()))
}
}
// trait impls for Combination
// lens + lens
impl<A, B, T> LensView<T> for Combination<Lens<A>, Lens<B>>
where
A: LensView<T>,
B: LensView<A::Field>,
{
type Field = B::Field;
fn view(thing: T) -> Self::Field {
B::view(A::view(thing))
fn view(&self, thing: T) -> Self::Field {
B::view(&self.1 .0, A::view(&self.0 .0, thing))
}
}
impl<A, B, T> LensOver<T> for Combination<A, B>
impl<A, B, T> LensOver<T> for Combination<Lens<A>, Lens<B>>
where
A: LensOver<T>,
B: LensOver<A::Field>,
{
fn over<F>(thing: T, f: F) -> T
fn over<F>(&self, thing: T, f: F) -> T
where
F: FnOnce(Self::Field) -> Self::Field,
{
A::over(thing, |b| B::over(b, f))
A::over(&self.0 .0, thing, |b| B::over(&self.1 .0, b, f))
}
}
// prism + prism
impl<A, B, T> PrismPreview<T> for Combination<Prism<A>, Prism<B>>
where
A: PrismPreview<T>,
B: PrismPreview<A::Field>,
{
type Field = B::Field;
fn preview(&self, thing: T) -> Option<Self::Field> {
A::preview(&self.0 .0, thing).and_then(|a| B::preview(&self.1 .0, a))
}
fn review(&self, thing: Self::Field) -> T {
A::review(&self.0 .0, B::review(&self.1 .0, thing))
}
}
// traversal + traversal
// lens + traversal
// traversal + lens
// prism + traversal
// traversal + prism
// prism + lens
// lens + prism
impl<A, B, T> TraversalTraverse<T> for Combination<Traversal<A>, Traversal<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 .0, thing);
a.into_iter()
.map(|v| B::traverse(&self.1 .0, v))
.flatten()
.collect()
}
}
impl<A, B, T> TraversalOver<T> for Combination<Traversal<A>, Traversal<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 .0, thing, |b| B::over(&self.1 .0, b, &mut f))
}
}
#[cfg(test)]
mod tests {
use crate::{
lenses::{_0, _1},
prisms::_Some,
traversals::each,
};
#[test]
fn can_view_lens_combination() {
let a = ((1, 2), 3);
let lens = _0 + _1;
let a = lens(a);
assert_eq!(a, 2);
}
#[test]
fn can_over_lens_combination() {
let a = ((1, 2), 3);
let lens = _0 + _1;
let a = lens(a, |v| v + 1);
assert_eq!(a, ((1, 3), 3));
}
#[test]
fn can_combine_prisms() {
let thing = Some(Some(3));
// combine two traversals
let res = (_Some + _Some)(thing, |v| v + 1);
assert_eq!(res, Some(Some(4)));
}
#[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)]);
}
#[test]
fn can_combine_prism_with_traversal() {
let array = [Some(1), None, Some(3), None, Some(5)];
// combine a traversal with a lens
let t = each + _Some;
// traverse
let res = t(array);
assert_eq!(res, vec![1, 3, 5]);
// over
let res = t(array, |v| v + 1);
assert_eq!(res, [Some(2), None, Some(4), None, Some(6)]);
}
#[test]
fn can_combine_traversal_with_prism() {
let array = Some([1, 2, 3]);
// combine a traversal with a lens
let t = _Some + each;
// traverse
let res = t(array);
assert_eq!(res, vec![1, 2, 3]);
// over
let res = t(array, |v| v + 1);
assert_eq!(res, Some([2, 3, 4]));
let array: Option<[i32; 3]> = None;
// traverse
let res = t(array);
assert_eq!(res, vec![]);
// over
let res = t(array, |v| v + 1);
assert_eq!(res, None);
}
#[test]
fn can_combine_prism_with_lens() {
let thing = Some((1, 2));
// combine a traversal with a lens
let t = _Some + _0;
// NOTE: combination of a prism and a lens is a traversal
//
// > The optic kind resulting from a composition is the least upper bound (join)
// > of the optic kinds being composed, if it exists.
// > The Join type family computes the least upper bound given two optic kind tags.
// > For example the Join of a Lens and a Prism is an AffineTraversal.
//
// from: https://hackage.haskell.org/package/optics-0.4/docs/Optics.html
// traversal
let res = t(thing);
assert_eq!(res, vec![1]);
// over
let res = t(thing, |v| v + 1);
assert_eq!(res, Some((2, 2)));
}
#[test]
fn can_combine_lens_with_prism() {
let thing = (Some(1), 2);
// combine a traversal with a lens
let t = _0 + _Some;
// NOTE: combination of a lens and a prism is a traversal
// see can_combine_prism_with_lens for more info
// traversal
let res = t(thing);
assert_eq!(res, vec![1]);
// over
let res = t(thing, |v| v + 1);
assert_eq!(res, (Some(2), 2));
}
}

View File

@ -1,5 +1,10 @@
use crate::{Lens, LensOver, LensView};
use crate::{
lenses::{Lens, LensOver, LensView},
prisms::{Prism, PrismPreview},
traversals::{Traversal, TraversalOver, TraversalTraverse},
};
// lens view
impl<L, A> std::ops::FnOnce<(A,)> for Lens<L>
where
L: LensView<A>,
@ -7,7 +12,7 @@ where
type Output = L::Field;
extern "rust-call" fn call_once(self, args: (A,)) -> Self::Output {
L::view(args.0)
L::view(&self.0, args.0)
}
}
impl<L, A> std::ops::FnMut<(A,)> for Lens<L>
@ -15,7 +20,7 @@ where
L: LensView<A>,
{
extern "rust-call" fn call_mut(&mut self, args: (A,)) -> Self::Output {
L::view(args.0)
L::view(&self.0, args.0)
}
}
impl<L, A> std::ops::Fn<(A,)> for Lens<L>
@ -23,10 +28,11 @@ where
L: LensView<A>,
{
extern "rust-call" fn call(&self, args: (A,)) -> Self::Output {
L::view(args.0)
L::view(&self.0, args.0)
}
}
// lens over
impl<L, A, F> std::ops::FnOnce<(A, F)> for Lens<L>
where
L: LensOver<A>,
@ -35,7 +41,7 @@ where
type Output = A;
extern "rust-call" fn call_once(self, args: (A, F)) -> Self::Output {
L::over(args.0, args.1)
L::over(&self.0, args.0, args.1)
}
}
impl<L, A, F> std::ops::FnMut<(A, F)> for Lens<L>
@ -44,7 +50,7 @@ where
F: FnOnce(L::Field) -> L::Field,
{
extern "rust-call" fn call_mut(&mut self, args: (A, F)) -> Self::Output {
L::over(args.0, args.1)
L::over(&self.0, args.0, args.1)
}
}
impl<L, A, F> std::ops::Fn<(A, F)> for Lens<L>
@ -53,6 +59,127 @@ where
F: FnOnce(L::Field) -> L::Field,
{
extern "rust-call" fn call(&self, args: (A, F)) -> Self::Output {
L::over(args.0, args.1)
L::over(&self.0, args.0, args.1)
}
}
// traversal traverse
impl<L, A> std::ops::FnOnce<(A,)> for Traversal<L>
where
L: TraversalTraverse<A>,
{
type Output = Vec<L::Field>;
extern "rust-call" fn call_once(self, args: (A,)) -> Self::Output {
L::traverse(&self.0, args.0)
}
}
impl<L, A> std::ops::FnMut<(A,)> for Traversal<L>
where
L: TraversalTraverse<A>,
{
extern "rust-call" fn call_mut(&mut self, args: (A,)) -> Self::Output {
L::traverse(&self.0, args.0)
}
}
impl<L, A> std::ops::Fn<(A,)> for Traversal<L>
where
L: TraversalTraverse<A>,
{
extern "rust-call" fn call(&self, args: (A,)) -> Self::Output {
L::traverse(&self.0, args.0)
}
}
// traversal over
impl<L, A, F> std::ops::FnOnce<(A, F)> for Traversal<L>
where
L: TraversalOver<A>,
F: FnMut(L::Field) -> L::Field,
{
type Output = A;
extern "rust-call" fn call_once(self, args: (A, F)) -> Self::Output {
L::over(&self.0, args.0, args.1)
}
}
impl<L, A, F> std::ops::FnMut<(A, F)> for Traversal<L>
where
L: TraversalOver<A>,
F: FnMut(L::Field) -> L::Field,
{
extern "rust-call" fn call_mut(&mut self, args: (A, F)) -> Self::Output {
L::over(&self.0, args.0, args.1)
}
}
impl<L, A, F> std::ops::Fn<(A, F)> for Traversal<L>
where
L: TraversalOver<A>,
F: FnMut(L::Field) -> L::Field,
{
extern "rust-call" fn call(&self, args: (A, F)) -> Self::Output {
L::over(&self.0, args.0, args.1)
}
}
// prism preview
impl<L, A> std::ops::FnOnce<(A,)> for Prism<L>
where
L: PrismPreview<A>,
{
type Output = Option<L::Field>;
extern "rust-call" fn call_once(self, args: (A,)) -> Self::Output {
L::preview(&self.0, args.0)
}
}
impl<L, A> std::ops::FnMut<(A,)> for Prism<L>
where
L: PrismPreview<A>,
{
extern "rust-call" fn call_mut(&mut self, args: (A,)) -> Self::Output {
L::preview(&self.0, args.0)
}
}
impl<L, A> std::ops::Fn<(A,)> for Prism<L>
where
L: PrismPreview<A>,
{
extern "rust-call" fn call(&self, args: (A,)) -> Self::Output {
L::preview(&self.0, args.0)
}
}
// prism over
impl<L, A, F> std::ops::FnOnce<(A, F)> for Prism<L>
where
A: Clone,
L: PrismPreview<A>,
F: FnMut(L::Field) -> L::Field,
{
type Output = A;
extern "rust-call" fn call_once(self, args: (A, F)) -> Self::Output {
L::over(&self.0, args.0, args.1)
}
}
impl<L, A, F> std::ops::FnMut<(A, F)> for Prism<L>
where
A: Clone,
L: PrismPreview<A>,
F: FnMut(L::Field) -> L::Field,
{
extern "rust-call" fn call_mut(&mut self, args: (A, F)) -> Self::Output {
L::over(&self.0, args.0, args.1)
}
}
impl<L, A, F> std::ops::Fn<(A, F)> for Prism<L>
where
A: Clone,
L: PrismPreview<A>,
F: FnMut(L::Field) -> L::Field,
{
extern "rust-call" fn call(&self, args: (A, F)) -> Self::Output {
L::over(&self.0, args.0, args.1)
}
}

View File

@ -1,21 +1,21 @@
use crate::{Lens, LensOver, LensTrait, LensView};
use crate::lenses::{Lens, LensOver, LensView};
#[derive(Clone, Copy)]
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 _0Inner {
type Field = T;
fn view(( $($v,)* ): ($($t,)*)) -> Self::Field {
fn view(&self, ( $($v,)* ): ($($t,)*)) -> Self::Field {
$f
}
}
impl< $($t,)* > LensOver<( $($t,)* )> for _0Inner {
fn over<F>(
&self,
mut tup: ($($t,)*),
f: F
) -> ( $($t,)* )
@ -30,14 +30,14 @@ macro_rules! make_tuples {
impl<'a, $($t,)* > LensView<&'a ( $($t,)* )> for _0Inner {
type Field = &'a T;
fn view(( $($v,)* ): &'a ($($t,)*)) -> Self::Field {
fn view(&self, ( $($v,)* ): &'a ($($t,)*)) -> Self::Field {
$f
}
}
impl<'a, $($t,)* > LensView<&'a mut ( $($t,)* )> for _0Inner {
type Field = &'a mut T;
fn view(( $($v,)* ): &'a mut ($($t,)*)) -> Self::Field {
fn view(&self, ( $($v,)* ): &'a mut ($($t,)*)) -> Self::Field {
$f
}
}
@ -57,12 +57,13 @@ macro_rules! make_arrays {
impl<T> LensView<[T; $n]> for _0Inner {
type Field = T;
fn view([ $($v,)* ]: [T; $n]) -> Self::Field {
fn view(&self, [ $($v,)* ]: [T; $n]) -> Self::Field {
$f
}
}
impl<T> LensOver<[T; $n]> for _0Inner {
fn over<F>(
&self,
tup: [T; $n],
fun: F
) -> [T; $n]
@ -78,14 +79,14 @@ macro_rules! make_arrays {
impl<'a, T> LensView<&'a [T; $n]> for _0Inner {
type Field = &'a T;
fn view([ $($v,)* ]: &'a [T; $n]) -> Self::Field {
fn view(&self, [ $($v,)* ]: &'a [T; $n]) -> Self::Field {
$f
}
}
impl<'a, T> LensView<&'a mut [T; $n]> for _0Inner {
type Field = &'a mut T;
fn view([ $($v,)* ]: &'a mut [T; $n]) -> Self::Field {
fn view(&self, [ $($v,)* ]: &'a mut [T; $n]) -> Self::Field {
$f
}
}

View File

@ -1,19 +1,19 @@
use crate::{LensOver, LensTrait, LensView};
use crate::lenses::{Lens, LensOver, LensView};
#[allow(non_camel_case_types)]
#[derive(Clone, Copy)]
pub struct id;
pub struct IdInner;
#[allow(non_upper_case_globals)]
pub const id: Lens<IdInner> = Lens(IdInner);
impl LensTrait for id {}
impl<T> LensView<T> for id {
impl<T> LensView<T> for IdInner {
type Field = T;
fn view(thing: T) -> Self::Field {
fn view(&self, thing: T) -> Self::Field {
thing
}
}
impl<T> LensOver<T> for id {
fn over<F>(thing: T, f: F) -> T
impl<T> LensOver<T> for IdInner {
fn over<F>(&self, thing: T, f: F) -> T
where
F: FnOnce(Self::Field) -> Self::Field,
{

42
src/lenses/lens.rs Normal file
View File

@ -0,0 +1,42 @@
use crate::lenses::{Lens, LensOver, LensView};
type Getter<T, U> = dyn Fn(T) -> U;
type Setter<T, U> = dyn Fn(T, U) -> T;
pub struct FuncLens<T, U>(pub(crate) Box<Getter<T, U>>, pub(crate) Box<Setter<T, U>>);
impl<T, U> LensView<T> for FuncLens<T, U> {
type Field = U;
fn view(&self, thing: T) -> Self::Field {
(self.0)(thing)
}
}
impl<T: Clone, U> LensOver<T> for FuncLens<T, U> {
fn over<F>(&self, thing: T, f: F) -> T
where
F: FnOnce(Self::Field) -> Self::Field,
{
let v = f((self.0)(thing.clone()));
(self.1)(thing, v)
}
fn set(&self, thing: T, v: Self::Field) -> T {
(self.1)(thing, v)
}
}
/// Makes a lens that implements `LensView<T>` and `LensOver<T>` with the provided functions
pub fn lens_from_boxed<T, U>(
getter: Box<Getter<T, U>>,
setter: Box<Setter<T, U>>,
) -> Lens<FuncLens<T, U>> {
Lens(FuncLens(getter, setter))
}
/// Makes a lens that implements `LensView<T>` and `LensOver<T>` with the provided functions
pub fn lens<T, U>(
getter: impl Fn(T) -> U + 'static,
setter: impl Fn(T, U) -> T + 'static,
) -> Lens<FuncLens<T, U>> {
Lens(FuncLens(Box::new(getter), Box::new(setter)))
}

View File

@ -5,3 +5,221 @@ mod first;
pub use first::_0;
mod second;
pub use second::_1;
mod to;
pub use to::{to, to_from_boxed};
mod lens;
pub use lens::{lens, lens_from_boxed};
/// Wrapper type
#[derive(Clone, Copy)]
#[repr(transparent)]
pub struct Lens<L>(pub(crate) L);
/// For lenses that allow viewing
pub trait LensView<T> {
type Field;
fn view(&self, thing: T) -> Self::Field;
}
/// For lenses that allow setting
pub trait LensOver<T>: LensView<T> {
fn over<F>(&self, thing: T, f: F) -> T
where
F: FnOnce(Self::Field) -> Self::Field;
fn set(&self, thing: T, v: Self::Field) -> T {
Self::over(self, thing, |_| v)
}
}
impl<L, T> LensView<T> for Lens<L>
where
L: LensView<T>,
{
type Field = L::Field;
fn view(&self, thing: T) -> Self::Field {
L::view(&self.0, thing)
}
}
impl<L, T> LensOver<T> for Lens<L>
where
L: LensOver<T>,
{
fn over<F>(&self, thing: T, f: F) -> T
where
F: FnOnce(Self::Field) -> Self::Field,
{
L::over(&self.0, thing, f)
}
}
pub fn view<T, L: LensView<T>>(lens: L, thing: T) -> L::Field {
L::view(&lens, thing)
}
pub fn set<T, L: LensOver<T>>(lens: L, thing: T, v: L::Field) -> T {
L::set(&lens, thing, v)
}
pub fn over<T, L: LensOver<T>>(lens: L, thing: T, f: impl FnOnce(L::Field) -> L::Field) -> T {
L::over(&lens, thing, f)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn view_first_from_tuple() {
let a = (1, 2);
assert_eq!(view(_0, a), 1);
let a = (1, 2);
assert_eq!(view(_0, &a), &1);
let mut a = (1, 2);
assert_eq!(view(_0, &mut a), &mut 1);
let a = (1, 2, 3);
assert_eq!(view(_0, a), 1);
let a = (1, 2, 3);
assert_eq!(view(_0, &a), &1);
}
#[test]
fn view_first_from_tuple_mut_works() {
let mut a = (1, 2);
*view(_0, &mut a) += 1;
assert_eq!(a, (2, 2));
}
#[test]
fn set_first_from_tuple() {
let a = (1, 2);
let a = set(_0, a, 3);
assert_eq!(a, (3, 2));
}
#[test]
fn over_first_from_tuple() {
let a = (1, 2);
let a = over(_0, a, |v| v + 1);
assert_eq!(a, (2, 2));
}
#[test]
fn over_first_from_array() {
let a = [1, 2, 3, 4];
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 call_as_funcs() {
let a = (1, 2);
assert_eq!(_0(a), 1);
let a = (1, 2);
assert_eq!(_0(a, |v| v + 1), (2, 2));
let a = ((1, 2), 3);
let res = _0(a);
assert_eq!(res, (1, 2));
let lens = _0 + _1;
let res = lens(a);
assert_eq!(res, 2);
let res = lens(a, |v| v + 1);
assert_eq!(res, ((1, 3), 3));
}
#[derive(Debug, PartialEq, Clone)]
struct Hello {
hey: u8,
}
#[test]
fn can_use_to() {
// making a getter
let l = to(|hello: Hello| hello.hey);
let hello = Hello { hey: 8 };
assert_eq!(l(hello), 8);
}
#[test]
fn can_make_lens_out_of_funcs() {
// making a lens
let l = lens(
|hello: Hello| hello.hey,
|mut hello: Hello, v: u8| {
hello.hey = v;
hello
},
);
let hello = Hello { hey: 8 };
assert_eq!(l(hello), 8);
let hello = Hello { hey: 8 };
assert_eq!(l(hello, |v| v + 1), Hello { hey: 9 });
}
#[test]
fn can_make_lens_out_of_to() {
// we first use to, and then use that to make a full lens
let l = to(|hello: Hello| hello.hey);
let l = l.make_lens(|mut hello: Hello, v: u8| {
hello.hey = v;
hello
});
let hello = Hello { hey: 8 };
assert_eq!(l(hello), 8);
let hello = Hello { hey: 8 };
assert_eq!(l(hello, |v| v + 1), Hello { hey: 9 });
}
#[test]
fn convoluted_example() {
#[derive(Debug, PartialEq, Clone)]
struct Hello2 {
hey: (u8, (u8, i32)),
}
// make a lens for Hello
let l = lens(
|hello: Hello2| hello.hey,
|mut hello: Hello2, v| {
hello.hey = v;
hello
},
);
let thing = Hello2 { hey: (1, (2, -3)) };
let thing = (thing, "hello");
let lens_that_targets_the_i32 = _0 + l + _1 + _1;
assert_eq!(lens_that_targets_the_i32(thing), -3);
}
}

View File

@ -1,21 +1,21 @@
use crate::{Lens, LensOver, LensTrait, LensView};
use crate::lenses::{Lens, LensOver, LensView};
#[derive(Clone, Copy)]
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 {
fn view(&self, ( $($v,)* ): ($($t,)*)) -> Self::Field {
$f
}
}
impl< $($t,)* > LensOver<( $($t,)* )> for _1Inner {
fn over<F>(
&self,
mut tup: ($($t,)*),
f: F
) -> ( $($t,)* )
@ -30,14 +30,14 @@ macro_rules! make_tuples {
impl<'a, $($t,)* > LensView<&'a ( $($t,)* )> for _1Inner {
type Field = &'a T;
fn view(( $($v,)* ): &'a ($($t,)*)) -> Self::Field {
fn view(&self, ( $($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 {
fn view(&self, ( $($v,)* ): &'a mut ($($t,)*)) -> Self::Field {
$f
}
}
@ -57,12 +57,13 @@ macro_rules! make_arrays {
impl<T> LensView<[T; $n]> for _1Inner {
type Field = T;
fn view([ $($v,)* ]: [T; $n]) -> Self::Field {
fn view(&self, [ $($v,)* ]: [T; $n]) -> Self::Field {
$f
}
}
impl<T> LensOver<[T; $n]> for _1Inner {
fn over<F>(
&self,
tup: [T; $n],
fun: F
) -> [T; $n]
@ -78,14 +79,14 @@ macro_rules! make_arrays {
impl<'a, T> LensView<&'a [T; $n]> for _1Inner {
type Field = &'a T;
fn view([ $($v,)* ]: &'a [T; $n]) -> Self::Field {
fn view(&self, [ $($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 {
fn view(&self, [ $($v,)* ]: &'a mut [T; $n]) -> Self::Field {
$f
}
}

29
src/lenses/to.rs Normal file
View File

@ -0,0 +1,29 @@
use crate::lenses::{Lens, LensView};
use super::lens::FuncLens;
pub struct ToInner<T, U>(Box<dyn Fn(T) -> U>);
impl<T, U> LensView<T> for ToInner<T, U> {
type Field = U;
fn view(&self, thing: T) -> Self::Field {
(self.0)(thing)
}
}
/// Makes a lens that implements `LensView<T>` with the provided function
pub fn to_from_boxed<T, U>(f: Box<dyn Fn(T) -> U>) -> Lens<ToInner<T, U>> {
Lens(ToInner(f))
}
/// Makes a lens that implements `LensView<T>` with the provided function
pub fn to<T, U>(f: impl Fn(T) -> U + 'static) -> Lens<ToInner<T, U>> {
Lens(ToInner(Box::new(f)))
}
impl<T, U> Lens<ToInner<T, U>> {
/// 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<FuncLens<T, U>> {
Lens(FuncLens((self.0).0, Box::new(setter)))
}
}

View File

@ -1,173 +1,7 @@
#![feature(unboxed_closures, fn_traits)]
/// Base trait
pub trait LensTrait {}
/// For lenses that allow viewing
pub trait LensView<T>: LensTrait {
type Field;
fn view(thing: T) -> Self::Field;
}
/// For lenses that allow setting
pub trait LensOver<T>: LensView<T> {
fn over<F>(thing: T, f: F) -> T
where
F: FnOnce(Self::Field) -> Self::Field;
fn set(thing: T, v: Self::Field) -> T {
Self::over(thing, |_| v)
}
}
/// Wrapper type
#[derive(Clone, Copy)]
pub struct Lens<T: LensTrait>(T);
impl<L: LensTrait> LensTrait for Lens<L> {}
impl<L, T> LensView<T> for Lens<L>
where
L: LensView<T>,
{
type Field = L::Field;
fn view(thing: T) -> Self::Field {
L::view(thing)
}
}
impl<L, T> LensOver<T> for Lens<L>
where
L: LensOver<T>,
{
fn over<F>(thing: T, f: F) -> T
where
F: FnOnce(Self::Field) -> Self::Field,
{
L::over(thing, f)
}
}
pub fn view<T, L: LensView<T>>(_lens: L, thing: T) -> L::Field {
L::view(thing)
}
pub fn set<T, L: LensOver<T>>(_lens: L, thing: T, v: L::Field) -> T {
L::set(thing, v)
}
pub fn over<T, L: LensOver<T>>(_lens: L, thing: T, f: impl FnOnce(L::Field) -> L::Field) -> T {
L::over(thing, f)
}
// TODO add fn impls
// TODO add third_from_tuple, etc
// TODO array traversals
// TODO make over work with changing types
mod combinations;
mod fns;
pub mod lenses;
#[cfg(test)]
mod tests {
use super::{
lenses::{_0, _1},
*,
};
#[test]
fn view_first_from_tuple() {
let a = (1, 2);
assert_eq!(view(_0, a), 1);
let a = (1, 2);
assert_eq!(view(_0, &a), &1);
let mut a = (1, 2);
assert_eq!(view(_0, &mut a), &mut 1);
let a = (1, 2, 3);
assert_eq!(view(_0, a), 1);
let a = (1, 2, 3);
assert_eq!(view(_0, &a), &1);
}
#[test]
fn view_first_from_tuple_mut_works() {
let mut a = (1, 2);
*view(_0, &mut a) += 1;
assert_eq!(a, (2, 2));
}
#[test]
fn set_first_from_tuple() {
let a = (1, 2);
let a = set(_0, a, 3);
assert_eq!(a, (3, 2));
}
#[test]
fn over_first_from_tuple() {
let a = (1, 2);
let a = over(_0, a, |v| v + 1);
assert_eq!(a, (2, 2));
}
#[test]
fn over_first_from_array() {
let a = [1, 2, 3, 4];
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));
}
#[test]
fn call_as_funcs() {
let a = (1, 2);
assert_eq!(_0(a), 1);
let a = (1, 2);
assert_eq!(_0(a, |v| v + 1), (2, 2));
let a = ((1, 2), 3);
let lens = _0 + _1;
let res = lens(a);
assert_eq!(res, 2);
let res = lens(a, |v| v + 1);
assert_eq!(res, ((1, 3), 3));
}
}
pub mod prisms;
pub mod traversals;

121
src/prisms/mod.rs Normal file
View File

@ -0,0 +1,121 @@
mod result;
pub use result::{_Err, _Ok};
mod option;
pub use option::{_None, _Some};
/// Wrapper type
#[derive(Clone, Copy)]
#[repr(transparent)]
pub struct Prism<P>(pub(crate) P);
pub trait PrismPreview<T> {
type Field;
fn preview(&self, thing: T) -> Option<Self::Field>;
fn review(&self, thing: Self::Field) -> T;
// TODO id like for this to not need clone
fn over<F>(&self, thing: T, f: F) -> T
where
F: FnOnce(Self::Field) -> Self::Field,
T: Clone,
{
if let Some(a) = Self::preview(&self, thing.clone()) {
Self::review(&self, f(a))
} else {
thing
}
}
fn set(&self, thing: T, v: Self::Field) -> T
where
T: Clone,
Self::Field: Clone,
{
Self::over(self, thing, move |_| v.clone())
}
}
impl<P, T> PrismPreview<T> for Prism<P>
where
P: PrismPreview<T>,
{
type Field = P::Field;
fn preview(&self, thing: T) -> Option<Self::Field> {
P::preview(&self.0, thing)
}
fn review(&self, thing: Self::Field) -> T {
P::review(&self.0, thing)
}
}
pub fn preview<T, P: PrismPreview<T>>(prism: P, thing: T) -> Option<P::Field> {
P::preview(&prism, thing)
}
pub fn review<T, P: PrismPreview<T>>(prism: P, thing: P::Field) -> T {
P::review(&prism, thing)
}
pub fn over<T: Clone, P: PrismPreview<T>>(
prism: P,
thing: T,
f: impl FnOnce(P::Field) -> P::Field,
) -> T {
P::over(&prism, thing, f)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn preview_result() {
let a: Result<i32, i32> = Ok(3);
assert_eq!(_Ok(a), Some(3));
let a: Result<i32, i32> = Err(3);
assert_eq!(preview(_Ok, a), None);
let a: Result<i32, i32> = Ok(3);
assert_eq!(_Err(a), None);
let a: Result<i32, i32> = Err(3);
assert_eq!(preview(_Err, a), Some(3));
}
#[test]
fn preview_option() {
let a = Some(3);
assert_eq!(_Some(a), Some(3));
let a = Some(3);
assert_eq!(preview(_None, a), Some(()));
let a: Option<i32> = None;
assert_eq!(preview(_Some, a), None);
let a: Option<i32> = None;
assert_eq!(preview(_None, a), Some(()));
}
#[test]
fn review_result() {
assert_eq!(review(_Ok, 3), Ok::<i32, i32>(3));
assert_eq!(review(_Err, 3), Err::<i32, i32>(3));
}
#[test]
fn review_option() {
assert_eq!(review(_Some, 3), Some(3));
assert_eq!(review(_None, ()), None::<()>);
}
#[test]
fn over_option() {
assert_eq!(over(_Some, Some(3), |v| v + 1), Some(4));
assert_eq!(_Some(Some(3), |v| v + 1), Some(4));
assert_eq!(over(_None, None, |_v: ()| ()), None::<()>);
}
}

34
src/prisms/option.rs Normal file
View File

@ -0,0 +1,34 @@
use super::*;
#[derive(Clone, Copy)]
pub struct SomeInner;
#[allow(non_upper_case_globals)]
pub const _Some: Prism<SomeInner> = Prism(SomeInner);
impl<T> PrismPreview<Option<T>> for SomeInner {
type Field = T;
fn preview(&self, thing: Option<T>) -> Option<Self::Field> {
thing
}
fn review(&self, thing: Self::Field) -> Option<T> {
Some(thing)
}
}
#[derive(Clone, Copy)]
pub struct NoneInner;
#[allow(non_upper_case_globals)]
pub const _None: Prism<NoneInner> = Prism(NoneInner);
impl<T> PrismPreview<Option<T>> for NoneInner {
type Field = ();
fn preview(&self, _thing: Option<T>) -> Option<Self::Field> {
Some(())
}
fn review(&self, _thing: Self::Field) -> Option<T> {
None
}
}

32
src/prisms/result.rs Normal file
View File

@ -0,0 +1,32 @@
use super::*;
#[derive(Clone, Copy)]
pub struct OkInner;
#[allow(non_upper_case_globals)]
pub const _Ok: Prism<OkInner> = Prism(OkInner);
impl<T, E> PrismPreview<Result<T, E>> for OkInner {
type Field = T;
fn preview(&self, thing: Result<T, E>) -> Option<Self::Field> {
thing.ok()
}
fn review(&self, thing: Self::Field) -> Result<T, E> {
Ok(thing)
}
}
#[derive(Clone, Copy)]
pub struct ErrInner;
#[allow(non_upper_case_globals)]
pub const _Err: Prism<ErrInner> = Prism(ErrInner);
impl<T, E> PrismPreview<Result<T, E>> for ErrInner {
type Field = E;
fn preview(&self, thing: Result<T, E>) -> Option<Self::Field> {
thing.err()
}
fn review(&self, thing: Self::Field) -> Result<T, E> {
Err(thing)
}
}

23
src/traversals/both.rs Normal file
View File

@ -0,0 +1,23 @@
use crate::traversals::{Traversal, TraversalOver, TraversalTraverse};
#[derive(Clone, Copy)]
pub struct BothInner;
#[allow(non_upper_case_globals)]
pub const both: Traversal<BothInner> = Traversal(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))
}
}

146
src/traversals/each.rs Normal file
View File

@ -0,0 +1,146 @@
use crate::traversals::{Traversal, TraversalOver, TraversalTraverse};
#[derive(Clone, Copy)]
pub struct EachInner;
#[allow(non_upper_case_globals)]
pub const each: Traversal<EachInner> = Traversal(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()
}
}
// TODO i'd like to have this so we get it for free on any iterable
// problem is, arrays/tuples don't implement FromIter
// and having both the blanket implementation and the one below complains cause
// other crates could add the trait in the future
// impl<I, T> TraversalTraverse<I> for EachInner
// where
// I: IntoIterator<Item = T>,
// {
// type Field = T;
// fn traverse(&self, thing: I) -> Vec<Self::Field> {
// thing.into_iter().collect()
// }
// }
// impl<I, T> TraversalOver<I> for EachInner
// where
// I: IntoIterator<Item = T> + FromIterator<T>,
// {
// fn over<F>(&self, thing: I, f: F) -> I
// 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]);

157
src/traversals/mod.rs Normal file
View File

@ -0,0 +1,157 @@
mod both;
pub use both::both;
mod each;
pub use each::each;
use crate::{
lenses::{Lens, LensOver, LensView},
prisms::{Prism, PrismPreview},
};
/// Wrapper type
#[derive(Clone, Copy)]
#[repr(transparent)]
pub struct Traversal<T>(pub(crate) T);
pub trait TraversalTraverse<T> {
type Field;
fn traverse(&self, thing: T) -> Vec<Self::Field>;
}
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 Traversal<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 Traversal<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)
}
}
// 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)
}
}
// all prisms are traversals, so we can freely transform them into a traversal
impl<L> Prism<L> {
/// Returns this lens as a traversal
pub fn to_traversal(self) -> Traversal<Prism<L>> {
Traversal(self)
}
}
// we can go back to a lens from a "traversal-ed" lens
impl<L> Traversal<Prism<L>> {
/// Returns the wrapped lens
pub fn to_prism(self) -> Prism<L> {
self.0
}
}
impl<L, T> TraversalTraverse<T> for Prism<L>
where
L: PrismPreview<T>,
{
type Field = L::Field;
fn traverse(&self, thing: T) -> Vec<Self::Field> {
L::preview(&self.0, thing).into_iter().collect()
}
}
impl<L, T> TraversalOver<T> for Prism<L>
where
T: Clone,
L: PrismPreview<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 = each(array);
assert_eq!(res, vec![1, 2, 3, 4,]);
let res = each(array, |v| v + 1);
assert_eq!(res, [2, 3, 4, 5]);
}
}