diff --git a/src/combinations.rs b/src/combinations.rs index ba8e3eb..7d815b9 100644 --- a/src/combinations.rs +++ b/src/combinations.rs @@ -1,5 +1,6 @@ use crate::{ lenses::{LensOver, LensView}, + prisms::PrismPreview, Optics, OpticsTrait, }; @@ -43,3 +44,15 @@ where A::over(thing, |b| B::over(b, f)) } } + +impl PrismPreview for Combination +where + A: LensView, + B: PrismPreview, +{ + type Field = B::Field; + + fn preview(thing: T) -> Option { + B::preview(A::view(thing)) + } +} diff --git a/src/lenses/mod.rs b/src/lenses/mod.rs index ce1d6dc..bb2152d 100644 --- a/src/lenses/mod.rs +++ b/src/lenses/mod.rs @@ -57,3 +57,106 @@ pub fn set>(_lens: L, thing: T, v: L::Field) -> T { pub fn over>(_lens: L, thing: T, f: impl FnOnce(L::Field) -> L::Field) -> T { L::over(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 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 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)); + } +} diff --git a/src/lenses/result.rs b/src/lenses/result.rs deleted file mode 100644 index 8b13789..0000000 --- a/src/lenses/result.rs +++ /dev/null @@ -1 +0,0 @@ - diff --git a/src/lib.rs b/src/lib.rs index fbe68bb..037cad1 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -21,106 +21,4 @@ impl OpticsTrait for Optics {} mod combinations; mod fns; pub mod lenses; - -#[cfg(test)] -mod tests { - use super::lenses::*; - - #[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 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)); - } -} +pub mod prisms; diff --git a/src/prisms/mod.rs b/src/prisms/mod.rs new file mode 100644 index 0000000..371f32b --- /dev/null +++ b/src/prisms/mod.rs @@ -0,0 +1,94 @@ +use crate::{Optics, OpticsTrait}; + +/// For lenses that allow viewing +pub trait PrismPreview: OpticsTrait { + type Field; + + fn preview(thing: T) -> Option; +} +pub trait PrismReview: PrismPreview { + fn review(thing: Self::Field) -> T; +} + +impl PrismPreview for Optics

+where + P: PrismPreview, +{ + type Field = P::Field; + + fn preview(thing: T) -> Option { + P::preview(thing) + } +} + +impl PrismReview for Optics

+where + P: PrismReview, +{ + fn review(thing: Self::Field) -> T { + P::review(thing) + } +} + +pub fn preview>(_prism: P, thing: T) -> Option { + P::preview(thing) +} +pub fn review>(_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::*; + + #[test] + fn preview_result() { + let a: Result = Ok(3); + assert_eq!(preview(_Ok, a), Some(3)); + + let a: Result = Err(3); + assert_eq!(preview(_Ok, a), None); + + let a: Result = Ok(3); + assert_eq!(preview(_Err, a), None); + + let a: Result = Err(3); + assert_eq!(preview(_Err, a), Some(3)); + } + + #[test] + fn preview_option() { + let a = Some(3); + assert_eq!(preview(_Some, a), Some(3)); + + let a = Some(3); + assert_eq!(preview(_None, a), Some(())); + + let a: Option = None; + assert_eq!(preview(_Some, a), None); + + let a: Option = None; + assert_eq!(preview(_None, a), Some(())); + } + + #[test] + fn review_result() { + assert_eq!(review(_Ok, 3), Ok::(3)); + assert_eq!(review(_Err, 3), Err::(3)); + } + + #[test] + fn review_option() { + assert_eq!(review(_Some, 3), Some(3)); + assert_eq!(review(_None, ()), None::<()>); + } + + #[test] + fn view_combination() {} +} diff --git a/src/prisms/option.rs b/src/prisms/option.rs new file mode 100644 index 0000000..ef287ef --- /dev/null +++ b/src/prisms/option.rs @@ -0,0 +1,39 @@ +use super::*; + +#[derive(Clone, Copy)] +pub struct SomeInner; +#[allow(non_upper_case_globals)] +pub const _Some: Optics = Optics(SomeInner); +impl OpticsTrait for SomeInner {} +impl PrismPreview> for SomeInner { + type Field = T; + + fn preview(thing: Option) -> Option { + thing + } +} + +impl PrismReview> for SomeInner { + fn review(thing: Self::Field) -> Option { + Some(thing) + } +} + +#[derive(Clone, Copy)] +pub struct NoneInner; +#[allow(non_upper_case_globals)] +pub const _None: Optics = Optics(NoneInner); +impl OpticsTrait for NoneInner {} +impl PrismPreview> for NoneInner { + type Field = (); + + fn preview(_thing: Option) -> Option { + Some(()) + } +} + +impl PrismReview> for NoneInner { + fn review(_thing: Self::Field) -> Option { + None + } +} diff --git a/src/prisms/result.rs b/src/prisms/result.rs new file mode 100644 index 0000000..061a227 --- /dev/null +++ b/src/prisms/result.rs @@ -0,0 +1,41 @@ +use super::*; + +#[derive(Clone, Copy)] +pub struct OkInner; +#[allow(non_upper_case_globals)] +pub const _Ok: Optics = Optics(OkInner); +impl OpticsTrait for OkInner {} +impl PrismPreview> for OkInner { + type Field = T; + + fn preview(thing: Result) -> Option { + thing.ok() + } +} + +impl PrismReview> for OkInner { + fn review(thing: Self::Field) -> Result { + Ok(thing) + } +} + +#[derive(Clone, Copy)] +pub struct ErrInner; +#[allow(non_upper_case_globals)] +pub const _Err: Optics = Optics(ErrInner); + +impl OpticsTrait for ErrInner {} + +impl PrismPreview> for ErrInner { + type Field = E; + + fn preview(thing: Result) -> Option { + thing.err() + } +} + +impl PrismReview> for ErrInner { + fn review(thing: Self::Field) -> Result { + Err(thing) + } +}