fix prisms
parent
529b628260
commit
bf85419c16
|
@ -1,5 +1,6 @@
|
||||||
use crate::{
|
use crate::{
|
||||||
lenses::{Lens, LensOver, LensView},
|
lenses::{Lens, LensOver, LensView},
|
||||||
|
prisms::Prism,
|
||||||
traversals::{Traversal, TraversalOver, TraversalTraverse},
|
traversals::{Traversal, TraversalOver, TraversalTraverse},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -8,6 +9,7 @@ pub struct Combination<A, B>(A, B);
|
||||||
|
|
||||||
// additions
|
// additions
|
||||||
|
|
||||||
|
// lens + lens
|
||||||
impl<A, B> std::ops::Add<Lens<B>> for Lens<A> {
|
impl<A, B> std::ops::Add<Lens<B>> for Lens<A> {
|
||||||
type Output = Lens<Combination<Lens<A>, Lens<B>>>;
|
type Output = Lens<Combination<Lens<A>, Lens<B>>>;
|
||||||
|
|
||||||
|
@ -15,6 +17,7 @@ impl<A, B> std::ops::Add<Lens<B>> for Lens<A> {
|
||||||
Lens(Combination(self, rhs))
|
Lens(Combination(self, rhs))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// traversal + traversal
|
||||||
impl<A, B> std::ops::Add<Traversal<B>> for Traversal<A> {
|
impl<A, B> std::ops::Add<Traversal<B>> for Traversal<A> {
|
||||||
type Output = Traversal<Combination<Traversal<A>, Traversal<B>>>;
|
type Output = Traversal<Combination<Traversal<A>, Traversal<B>>>;
|
||||||
|
|
||||||
|
@ -22,6 +25,7 @@ impl<A, B> std::ops::Add<Traversal<B>> for Traversal<A> {
|
||||||
Traversal(Combination(self, rhs))
|
Traversal(Combination(self, rhs))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// traversal + lens
|
||||||
impl<A, B> std::ops::Add<Lens<B>> for Traversal<A> {
|
impl<A, B> std::ops::Add<Lens<B>> for Traversal<A> {
|
||||||
type Output = Traversal<Combination<Traversal<A>, Traversal<Lens<B>>>>;
|
type Output = Traversal<Combination<Traversal<A>, Traversal<Lens<B>>>>;
|
||||||
|
|
||||||
|
@ -29,6 +33,7 @@ impl<A, B> std::ops::Add<Lens<B>> for Traversal<A> {
|
||||||
Traversal(Combination(self, rhs.to_traversal()))
|
Traversal(Combination(self, rhs.to_traversal()))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// lens + traversal
|
||||||
impl<A, B> std::ops::Add<Traversal<B>> for Lens<A> {
|
impl<A, B> std::ops::Add<Traversal<B>> for Lens<A> {
|
||||||
type Output = Traversal<Combination<Traversal<Lens<A>>, Traversal<B>>>;
|
type Output = Traversal<Combination<Traversal<Lens<A>>, Traversal<B>>>;
|
||||||
|
|
||||||
|
@ -36,6 +41,22 @@ impl<A, B> std::ops::Add<Traversal<B>> for Lens<A> {
|
||||||
Traversal(Combination(self.to_traversal(), rhs))
|
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))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// trait impls for Combination
|
// trait impls for Combination
|
||||||
|
|
||||||
|
|
63
src/fns.rs
63
src/fns.rs
|
@ -1,5 +1,6 @@
|
||||||
use crate::{
|
use crate::{
|
||||||
lenses::{Lens, LensOver, LensView},
|
lenses::{Lens, LensOver, LensView},
|
||||||
|
prisms::{Prism, PrismPreview},
|
||||||
traversals::{Traversal, TraversalOver, TraversalTraverse},
|
traversals::{Traversal, TraversalOver, TraversalTraverse},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -120,3 +121,65 @@ where
|
||||||
L::over(&self.0, args.0, args.1)
|
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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -12,10 +12,28 @@ pub struct Prism<P>(pub(crate) P);
|
||||||
pub trait PrismPreview<T> {
|
pub trait PrismPreview<T> {
|
||||||
type Field;
|
type Field;
|
||||||
|
|
||||||
fn preview(thing: T) -> Option<Self::Field>;
|
fn preview(&self, thing: T) -> Option<Self::Field>;
|
||||||
}
|
fn review(&self, thing: Self::Field) -> T;
|
||||||
pub trait PrismReview<T>: PrismPreview<T> {
|
// TODO id like for this to not need clone
|
||||||
fn review(thing: Self::Field) -> T;
|
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>
|
impl<P, T> PrismPreview<T> for Prism<P>
|
||||||
|
@ -24,25 +42,27 @@ where
|
||||||
{
|
{
|
||||||
type Field = P::Field;
|
type Field = P::Field;
|
||||||
|
|
||||||
fn preview(thing: T) -> Option<Self::Field> {
|
fn preview(&self, thing: T) -> Option<Self::Field> {
|
||||||
P::preview(thing)
|
P::preview(&self.0, thing)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn review(&self, thing: Self::Field) -> T {
|
||||||
|
P::review(&self.0, thing)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<P, T> PrismReview<T> for Prism<P>
|
pub fn preview<T, P: PrismPreview<T>>(prism: P, thing: T) -> Option<P::Field> {
|
||||||
where
|
P::preview(&prism, thing)
|
||||||
P: PrismReview<T>,
|
|
||||||
{
|
|
||||||
fn review(thing: Self::Field) -> T {
|
|
||||||
P::review(thing)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
pub fn review<T, P: PrismPreview<T>>(prism: P, thing: P::Field) -> T {
|
||||||
pub fn preview<T, P: PrismPreview<T>>(_prism: P, thing: T) -> Option<P::Field> {
|
P::review(&prism, thing)
|
||||||
P::preview(thing)
|
|
||||||
}
|
}
|
||||||
pub fn review<T, P: PrismReview<T>>(_prism: P, thing: P::Field) -> T {
|
pub fn over<T: Clone, P: PrismPreview<T>>(
|
||||||
P::review(thing)
|
prism: P,
|
||||||
|
thing: T,
|
||||||
|
f: impl FnOnce(P::Field) -> P::Field,
|
||||||
|
) -> T {
|
||||||
|
P::over(&prism, thing, f)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
|
@ -52,13 +72,13 @@ mod tests {
|
||||||
#[test]
|
#[test]
|
||||||
fn preview_result() {
|
fn preview_result() {
|
||||||
let a: Result<i32, i32> = Ok(3);
|
let a: Result<i32, i32> = Ok(3);
|
||||||
assert_eq!(preview(_Ok, a), Some(3));
|
assert_eq!(_Ok(a), Some(3));
|
||||||
|
|
||||||
let a: Result<i32, i32> = Err(3);
|
let a: Result<i32, i32> = Err(3);
|
||||||
assert_eq!(preview(_Ok, a), None);
|
assert_eq!(preview(_Ok, a), None);
|
||||||
|
|
||||||
let a: Result<i32, i32> = Ok(3);
|
let a: Result<i32, i32> = Ok(3);
|
||||||
assert_eq!(preview(_Err, a), None);
|
assert_eq!(_Err(a), None);
|
||||||
|
|
||||||
let a: Result<i32, i32> = Err(3);
|
let a: Result<i32, i32> = Err(3);
|
||||||
assert_eq!(preview(_Err, a), Some(3));
|
assert_eq!(preview(_Err, a), Some(3));
|
||||||
|
@ -67,7 +87,7 @@ mod tests {
|
||||||
#[test]
|
#[test]
|
||||||
fn preview_option() {
|
fn preview_option() {
|
||||||
let a = Some(3);
|
let a = Some(3);
|
||||||
assert_eq!(preview(_Some, a), Some(3));
|
assert_eq!(_Some(a), Some(3));
|
||||||
|
|
||||||
let a = Some(3);
|
let a = Some(3);
|
||||||
assert_eq!(preview(_None, a), Some(()));
|
assert_eq!(preview(_None, a), Some(()));
|
||||||
|
@ -90,4 +110,11 @@ mod tests {
|
||||||
assert_eq!(review(_Some, 3), Some(3));
|
assert_eq!(review(_Some, 3), Some(3));
|
||||||
assert_eq!(review(_None, ()), None::<()>);
|
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::<()>);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,13 +8,11 @@ pub const _Some: Prism<SomeInner> = Prism(SomeInner);
|
||||||
impl<T> PrismPreview<Option<T>> for SomeInner {
|
impl<T> PrismPreview<Option<T>> for SomeInner {
|
||||||
type Field = T;
|
type Field = T;
|
||||||
|
|
||||||
fn preview(thing: Option<T>) -> Option<Self::Field> {
|
fn preview(&self, thing: Option<T>) -> Option<Self::Field> {
|
||||||
thing
|
thing
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
impl<T> PrismReview<Option<T>> for SomeInner {
|
fn review(&self, thing: Self::Field) -> Option<T> {
|
||||||
fn review(thing: Self::Field) -> Option<T> {
|
|
||||||
Some(thing)
|
Some(thing)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -26,13 +24,11 @@ pub const _None: Prism<NoneInner> = Prism(NoneInner);
|
||||||
impl<T> PrismPreview<Option<T>> for NoneInner {
|
impl<T> PrismPreview<Option<T>> for NoneInner {
|
||||||
type Field = ();
|
type Field = ();
|
||||||
|
|
||||||
fn preview(_thing: Option<T>) -> Option<Self::Field> {
|
fn preview(&self, _thing: Option<T>) -> Option<Self::Field> {
|
||||||
Some(())
|
Some(())
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
impl<T> PrismReview<Option<T>> for NoneInner {
|
fn review(&self, _thing: Self::Field) -> Option<T> {
|
||||||
fn review(_thing: Self::Field) -> Option<T> {
|
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,13 +7,10 @@ pub const _Ok: Prism<OkInner> = Prism(OkInner);
|
||||||
impl<T, E> PrismPreview<Result<T, E>> for OkInner {
|
impl<T, E> PrismPreview<Result<T, E>> for OkInner {
|
||||||
type Field = T;
|
type Field = T;
|
||||||
|
|
||||||
fn preview(thing: Result<T, E>) -> Option<Self::Field> {
|
fn preview(&self, thing: Result<T, E>) -> Option<Self::Field> {
|
||||||
thing.ok()
|
thing.ok()
|
||||||
}
|
}
|
||||||
}
|
fn review(&self, thing: Self::Field) -> Result<T, E> {
|
||||||
|
|
||||||
impl<T, E> PrismReview<Result<T, E>> for OkInner {
|
|
||||||
fn review(thing: Self::Field) -> Result<T, E> {
|
|
||||||
Ok(thing)
|
Ok(thing)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -26,13 +23,10 @@ pub const _Err: Prism<ErrInner> = Prism(ErrInner);
|
||||||
impl<T, E> PrismPreview<Result<T, E>> for ErrInner {
|
impl<T, E> PrismPreview<Result<T, E>> for ErrInner {
|
||||||
type Field = E;
|
type Field = E;
|
||||||
|
|
||||||
fn preview(thing: Result<T, E>) -> Option<Self::Field> {
|
fn preview(&self, thing: Result<T, E>) -> Option<Self::Field> {
|
||||||
thing.err()
|
thing.err()
|
||||||
}
|
}
|
||||||
}
|
fn review(&self, thing: Self::Field) -> Result<T, E> {
|
||||||
|
|
||||||
impl<T, E> PrismReview<Result<T, E>> for ErrInner {
|
|
||||||
fn review(thing: Self::Field) -> Result<T, E> {
|
|
||||||
Err(thing)
|
Err(thing)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,7 +4,10 @@ pub use both::both;
|
||||||
mod each;
|
mod each;
|
||||||
pub use each::each;
|
pub use each::each;
|
||||||
|
|
||||||
use crate::lenses::{Lens, LensOver, LensView};
|
use crate::{
|
||||||
|
lenses::{Lens, LensOver, LensView},
|
||||||
|
prisms::{Prism, PrismPreview},
|
||||||
|
};
|
||||||
|
|
||||||
/// Wrapper type
|
/// Wrapper type
|
||||||
#[derive(Clone, Copy)]
|
#[derive(Clone, Copy)]
|
||||||
|
@ -87,6 +90,43 @@ where
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 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> {
|
pub fn traverse<T, L: TraversalTraverse<T>>(lens: L, thing: T) -> Vec<L::Field> {
|
||||||
L::traverse(&lens, thing)
|
L::traverse(&lens, thing)
|
||||||
}
|
}
|
||||||
|
@ -102,7 +142,7 @@ pub fn over<T, L: TraversalOver<T>>(lens: L, thing: T, f: impl FnMut(L::Field) -
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use crate::lenses::_0;
|
use crate::{lenses::_0, prisms::_Some};
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
|
@ -157,4 +197,45 @@ mod tests {
|
||||||
let res = t(array, |v| v + 1);
|
let res = t(array, |v| v + 1);
|
||||||
assert_eq!(res, [(2, 3), (3, 4), (5, 6)]);
|
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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue