split optics wrapper type into Lens, Traversal, Prism

main
annieversary 2021-11-11 13:29:43 +00:00
parent e5a9293ec2
commit f73c2ad5b6
15 changed files with 156 additions and 139 deletions

View File

@ -1,21 +1,13 @@
use crate::{
lenses::{LensOver, LensView},
Optics, OpticsTrait,
};
use crate::lenses::{Lens, LensOver, LensView};
#[derive(Clone, Copy)]
pub struct Combination<A, B>(A, B);
impl<A, B> OpticsTrait for Combination<A, B> {}
impl<A, B> std::ops::Add<Optics<B>> for Optics<A>
where
A: OpticsTrait,
B: OpticsTrait,
{
type Output = Optics<Combination<Optics<A>, Optics<B>>>;
impl<A, B> std::ops::Add<Lens<B>> for Lens<A> {
type Output = Lens<Combination<Lens<A>, Lens<B>>>;
fn add(self, rhs: Optics<B>) -> Self::Output {
Optics(Combination(self, rhs))
fn add(self, rhs: Lens<B>) -> Self::Output {
Lens(Combination(self, rhs))
}
}

View File

@ -1,9 +1,10 @@
use crate::{
lenses::{LensOver, LensView},
Optics,
lenses::{Lens, LensOver, LensView},
traversals::{Traversal, TraversalOver, TraversalTraverse},
};
impl<L, A> std::ops::FnOnce<(A,)> for Optics<L>
// lens view
impl<L, A> std::ops::FnOnce<(A,)> for Lens<L>
where
L: LensView<A>,
{
@ -13,7 +14,7 @@ where
L::view(&self.0, args.0)
}
}
impl<L, A> std::ops::FnMut<(A,)> for Optics<L>
impl<L, A> std::ops::FnMut<(A,)> for Lens<L>
where
L: LensView<A>,
{
@ -21,7 +22,7 @@ where
L::view(&self.0, args.0)
}
}
impl<L, A> std::ops::Fn<(A,)> for Optics<L>
impl<L, A> std::ops::Fn<(A,)> for Lens<L>
where
L: LensView<A>,
{
@ -30,7 +31,8 @@ where
}
}
impl<L, A, F> std::ops::FnOnce<(A, F)> for Optics<L>
// lens over
impl<L, A, F> std::ops::FnOnce<(A, F)> for Lens<L>
where
L: LensOver<A>,
F: FnOnce(L::Field) -> L::Field,
@ -41,7 +43,7 @@ where
L::over(&self.0, args.0, args.1)
}
}
impl<L, A, F> std::ops::FnMut<(A, F)> for Optics<L>
impl<L, A, F> std::ops::FnMut<(A, F)> for Lens<L>
where
L: LensOver<A>,
F: FnOnce(L::Field) -> L::Field,
@ -50,7 +52,7 @@ where
L::over(&self.0, args.0, args.1)
}
}
impl<L, A, F> std::ops::Fn<(A, F)> for Optics<L>
impl<L, A, F> std::ops::Fn<(A, F)> for Lens<L>
where
L: LensOver<A>,
F: FnOnce(L::Field) -> L::Field,
@ -59,3 +61,62 @@ where
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)
}
}

View File

@ -1,12 +1,8 @@
use crate::{
lenses::{LensOver, LensView},
Optics, OpticsTrait,
};
use crate::lenses::{Lens, LensOver, LensView};
#[derive(Clone, Copy)]
pub struct _0Inner;
pub const _0: Optics<_0Inner> = Optics(_0Inner);
impl OpticsTrait for _0Inner {}
pub const _0: Lens<_0Inner> = Lens(_0Inner);
macro_rules! make_tuples {
($f:ident, ( $( $v:ident ),* ), ( $( $t:ident ),* ) ) => {

View File

@ -1,21 +1,18 @@
use crate::{
lenses::{LensOver, LensView},
OpticsTrait,
};
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 OpticsTrait for id {}
impl<T> LensView<T> for id {
impl<T> LensView<T> for IdInner {
type Field = T;
fn view(&self, thing: T) -> Self::Field {
thing
}
}
impl<T> LensOver<T> for id {
impl<T> LensOver<T> for IdInner {
fn over<F>(&self, thing: T, f: F) -> T
where
F: FnOnce(Self::Field) -> Self::Field,

View File

@ -1,13 +1,9 @@
use crate::{
lenses::{LensOver, LensView},
Optics, OpticsTrait,
};
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 LensInner<T, U>(pub(crate) Box<Getter<T, U>>, pub(crate) Box<Setter<T, U>>);
impl<T, U> OpticsTrait for LensInner<T, U> {}
impl<T, U> LensView<T> for LensInner<T, U> {
type Field = U;
@ -34,13 +30,13 @@ impl<T: Clone, U> LensOver<T> for LensInner<T, U> {
pub fn lens_from_boxed<T, U>(
getter: Box<Getter<T, U>>,
setter: Box<Setter<T, U>>,
) -> Optics<LensInner<T, U>> {
Optics(LensInner(getter, setter))
) -> Lens<LensInner<T, U>> {
Lens(LensInner(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,
) -> Optics<LensInner<T, U>> {
Optics(LensInner(Box::new(getter), Box::new(setter)))
) -> Lens<LensInner<T, U>> {
Lens(LensInner(Box::new(getter), Box::new(setter)))
}

View File

@ -11,10 +11,30 @@ pub use to::{to, to_from_boxed};
mod lens;
pub use lens::{lens, lens_from_boxed};
use crate::{Optics, OpticsTrait};
use crate::traversals::Traversal;
/// Wrapper type
#[derive(Clone, Copy)]
#[repr(transparent)]
pub struct Lens<L>(pub(crate) L);
// 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
}
}
/// For lenses that allow viewing
pub trait LensView<T>: OpticsTrait {
pub trait LensView<T> {
type Field;
fn view(&self, thing: T) -> Self::Field;
@ -31,7 +51,7 @@ pub trait LensOver<T>: LensView<T> {
}
}
impl<L, T> LensView<T> for Optics<L>
impl<L, T> LensView<T> for Lens<L>
where
L: LensView<T>,
{
@ -41,7 +61,7 @@ where
L::view(&self.0, thing)
}
}
impl<L, T> LensOver<T> for Optics<L>
impl<L, T> LensOver<T> for Lens<L>
where
L: LensOver<T>,
{

View File

@ -1,23 +1,19 @@
use crate::{
lenses::{LensOver, LensView},
Optics, OpticsTrait,
};
use crate::lenses::{Lens, LensOver, LensView};
#[derive(Clone, Copy)]
pub struct _1Inner;
pub const _1: Optics<_1Inner> = Optics(_1Inner);
impl OpticsTrait for _1Inner {}
pub const _1: Lens<_1Inner> = Lens(_1Inner);
macro_rules! make_tuples {
($f:ident, ( $( $v:ident ),* ), ( $( $t:ident ),* ) ) => {
impl< $($t,)* > LensView<( $($t,)* )> for _1Inner {
impl< $($t,)* > LensView<( $($t,)* )> for _1Inner {
type Field = T;
fn view(&self, ( $($v,)* ): ($($t,)*)) -> Self::Field {
$f
}
}
impl< $($t,)* > LensOver<( $($t,)* )> for _1Inner {
impl< $($t,)* > LensOver<( $($t,)* )> for _1Inner {
fn over<F>(
&self,
mut tup: ($($t,)*),
@ -31,14 +27,14 @@ macro_rules! make_tuples {
}
}
impl<'a, $($t,)* > LensView<&'a ( $($t,)* )> for _1Inner {
impl<'a, $($t,)* > LensView<&'a ( $($t,)* )> for _1Inner {
type Field = &'a T;
fn view(&self, ( $($v,)* ): &'a ($($t,)*)) -> Self::Field {
$f
}
}
impl<'a, $($t,)* > LensView<&'a mut ( $($t,)* )> for _1Inner {
impl<'a, $($t,)* > LensView<&'a mut ( $($t,)* )> for _1Inner {
type Field = &'a mut T;
fn view(&self, ( $($v,)* ): &'a mut ($($t,)*)) -> Self::Field {

View File

@ -1,9 +1,8 @@
use crate::{lenses::LensView, Optics, OpticsTrait};
use crate::lenses::{Lens, LensView};
use super::lens::LensInner;
pub struct ToInner<T, U>(Box<dyn Fn(T) -> U>);
impl<T, U> OpticsTrait for ToInner<T, U> {}
impl<T, U> LensView<T> for ToInner<T, U> {
type Field = U;
@ -14,17 +13,17 @@ impl<T, U> LensView<T> for ToInner<T, U> {
}
/// Makes a lens that implements `LensView<T>` with the provided function
pub fn to_from_boxed<T, U>(f: Box<dyn Fn(T) -> U>) -> Optics<ToInner<T, U>> {
Optics(ToInner(f))
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) -> Optics<ToInner<T, U>> {
Optics(ToInner(Box::new(f)))
pub fn to<T, U>(f: impl Fn(T) -> U + 'static) -> Lens<ToInner<T, U>> {
Lens(ToInner(Box::new(f)))
}
impl<T, U> Optics<ToInner<T, U>> {
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) -> Optics<LensInner<T, U>> {
Optics(LensInner((self.0).0, Box::new(setter)))
pub fn make_lens(self, setter: impl Fn(T, U) -> T + 'static) -> Lens<LensInner<T, U>> {
Lens(LensInner((self.0).0, Box::new(setter)))
}
}

View File

@ -1,14 +1,5 @@
#![feature(unboxed_closures, fn_traits)]
/// Base trait
pub trait OpticsTrait {}
/// Wrapper type
#[derive(Clone, Copy)]
#[repr(transparent)]
pub struct Optics<T: OpticsTrait>(pub(crate) T);
impl<L: OpticsTrait> OpticsTrait for Optics<L> {}
mod combinations;
mod fns;
pub mod lenses;

View File

@ -1,6 +1,15 @@
use crate::{Optics, OpticsTrait};
mod result;
pub use result::{_Err, _Ok};
pub trait PrismPreview<T>: OpticsTrait {
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(thing: T) -> Option<Self::Field>;
@ -9,7 +18,7 @@ pub trait PrismReview<T>: PrismPreview<T> {
fn review(thing: Self::Field) -> T;
}
impl<P, T> PrismPreview<T> for Optics<P>
impl<P, T> PrismPreview<T> for Prism<P>
where
P: PrismPreview<T>,
{
@ -20,7 +29,7 @@ where
}
}
impl<P, T> PrismReview<T> for Optics<P>
impl<P, T> PrismReview<T> for Prism<P>
where
P: PrismReview<T>,
{
@ -36,12 +45,6 @@ pub fn review<T, P: PrismReview<T>>(_prism: P, thing: P::Field) -> T {
P::review(thing)
}
mod result;
pub use result::{_Err, _Ok};
mod option;
pub use option::{_None, _Some};
#[cfg(test)]
mod tests {
use super::*;

View File

@ -3,8 +3,8 @@ use super::*;
#[derive(Clone, Copy)]
pub struct SomeInner;
#[allow(non_upper_case_globals)]
pub const _Some: Optics<SomeInner> = Optics(SomeInner);
impl OpticsTrait for SomeInner {}
pub const _Some: Prism<SomeInner> = Prism(SomeInner);
impl<T> PrismPreview<Option<T>> for SomeInner {
type Field = T;
@ -22,8 +22,7 @@ impl<T> PrismReview<Option<T>> for SomeInner {
#[derive(Clone, Copy)]
pub struct NoneInner;
#[allow(non_upper_case_globals)]
pub const _None: Optics<NoneInner> = Optics(NoneInner);
impl OpticsTrait for NoneInner {}
pub const _None: Prism<NoneInner> = Prism(NoneInner);
impl<T> PrismPreview<Option<T>> for NoneInner {
type Field = ();

View File

@ -3,8 +3,7 @@ use super::*;
#[derive(Clone, Copy)]
pub struct OkInner;
#[allow(non_upper_case_globals)]
pub const _Ok: Optics<OkInner> = Optics(OkInner);
impl OpticsTrait for OkInner {}
pub const _Ok: Prism<OkInner> = Prism(OkInner);
impl<T, E> PrismPreview<Result<T, E>> for OkInner {
type Field = T;
@ -22,9 +21,7 @@ impl<T, E> PrismReview<Result<T, E>> for OkInner {
#[derive(Clone, Copy)]
pub struct ErrInner;
#[allow(non_upper_case_globals)]
pub const _Err: Optics<ErrInner> = Optics(ErrInner);
impl OpticsTrait for ErrInner {}
pub const _Err: Prism<ErrInner> = Prism(ErrInner);
impl<T, E> PrismPreview<Result<T, E>> for ErrInner {
type Field = E;

View File

@ -1,13 +1,9 @@
use crate::{
traversals::{TraversalOver, TraversalTraverse},
Optics, OpticsTrait,
};
use crate::traversals::{Traversal, TraversalOver, TraversalTraverse};
#[derive(Clone, Copy)]
pub struct BothInner;
#[allow(non_upper_case_globals)]
pub const both: Optics<BothInner> = Optics(BothInner);
impl OpticsTrait for BothInner {}
pub const both: Traversal<BothInner> = Traversal(BothInner);
impl<T> TraversalTraverse<(T, T)> for BothInner {
type Field = T;

View File

@ -1,13 +1,9 @@
use crate::{
traversals::{TraversalOver, TraversalTraverse},
Optics, OpticsTrait,
};
use crate::traversals::{Traversal, TraversalOver, TraversalTraverse};
#[derive(Clone, Copy)]
pub struct EachInner;
#[allow(non_upper_case_globals)]
pub const each: Optics<EachInner> = Optics(EachInner);
impl OpticsTrait for EachInner {}
pub const each: Traversal<EachInner> = Traversal(EachInner);
impl<T> TraversalTraverse<Vec<T>> for EachInner {
type Field = T;

View File

@ -1,19 +1,20 @@
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 {
/// 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>;
}
/// For lenses that allow setting
pub trait TraversalOver<T>: TraversalTraverse<T> {
fn over<F>(&self, thing: T, f: F) -> T
where
@ -26,7 +27,7 @@ pub trait TraversalOver<T>: TraversalTraverse<T> {
Self::over(self, thing, move |_| v.clone())
}
}
impl<L, T> TraversalTraverse<T> for Optics<L>
impl<L, T> TraversalTraverse<T> for Traversal<L>
where
L: TraversalTraverse<T>,
{
@ -36,7 +37,7 @@ where
L::traverse(&self.0, thing)
}
}
impl<L, T> TraversalOver<T> for Optics<L>
impl<L, T> TraversalOver<T> for Traversal<L>
where
L: TraversalOver<T>,
{
@ -48,29 +49,6 @@ where
}
}
// // 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)
}
@ -92,7 +70,7 @@ mod tests {
fn traverse_each_works_on_arrays() {
let array = [1, 2, 3, 4];
let res = over(each, array, |v| v + 1);
let res = each(array, |v| v + 1);
assert_eq!(res, [2, 3, 4, 5]);
}
}