pub mod result;
pub use result::{_Err, _Ok};
pub mod option;
pub use option::{_None, _Some};
/// Wrapper type
#[derive(Clone, Copy)]
#[repr(transparent)]
pub struct Prism
(pub(crate) P);
pub trait PrismPreview {
type Field;
fn preview(&self, thing: T) -> Option;
fn review(&self, thing: Self::Field) -> T;
// TODO id like for this to not need clone
fn over(&self, thing: T, f: F) -> T
where
F: FnOnce(Self::Field) -> Self::Field,
T: Clone,
{
Self::preview(self, thing.clone()).map_or(thing, |a| Self::review(self, f(a)))
}
fn set(&self, thing: T, v: Self::Field) -> T
where
T: Clone,
Self::Field: Clone,
{
Self::over(self, thing, move |_| v)
}
}
impl PrismPreview for Prism
where
P: PrismPreview,
{
type Field = P::Field;
fn preview(&self, thing: T) -> Option {
P::preview(&self.0, thing)
}
fn review(&self, thing: Self::Field) -> T {
P::review(&self.0, thing)
}
}
pub fn preview>(prism: P, thing: T) -> Option {
P::preview(&prism, thing)
}
pub fn review>(prism: P, thing: P::Field) -> T {
P::review(&prism, thing)
}
pub fn over>(
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 = Ok(3);
assert_eq!(_Ok(a), Some(3));
let a: Result = Err(3);
assert_eq!(preview(_Ok, a), None);
let a: Result = Ok(3);
assert_eq!(_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!(_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 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::<()>);
}
}