use crate::hlist::{Coniunctio, Nihil};
use crate::indices::{Here, There};
use crate::traits::{Func, Poly, ToMut, ToRef};
#[cfg(feature = "serde")]
use serde::{Deserialize, Serialize};
#[derive(PartialEq, Debug, Eq, Clone, Copy, PartialOrd, Ord, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub enum Disiunctio<H, T> {
Sinister(H),
Dexter(T),
}
#[derive(PartialEq, Debug, Eq, Clone, Copy, PartialOrd, Ord, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub enum Absurdum {}
impl<Head, Tail> Disiunctio<Head, Tail> {
#[inline(always)]
pub fn inject<T, Index>(to_insert: T) -> Self
where
Self: DisiunctioInjector<T, Index>,
{
DisiunctioInjector::inject(to_insert)
}
#[inline(always)]
pub fn get<S, Index>(&self) -> Option<&S>
where
Self: DisiunctioSelector<S, Index>,
{
DisiunctioSelector::get(self)
}
#[inline(always)]
pub fn take<T, Index>(self) -> Option<T>
where
Self: DisiunctioTaker<T, Index>,
{
DisiunctioTaker::take(self)
}
#[inline(always)]
pub fn uninject<T, Index>(
self,
) -> Result<T, <Self as DisiunctioUninjector<T, Index>>::Remainder>
where
Self: DisiunctioUninjector<T, Index>,
{
DisiunctioUninjector::uninject(self)
}
#[inline(always)]
pub fn subset<Targets, Indices>(
self,
) -> Result<Targets, <Self as DisiunctioSubsetter<Targets, Indices>>::Remainder>
where
Self: DisiunctioSubsetter<Targets, Indices>,
{
DisiunctioSubsetter::subset(self)
}
#[inline(always)]
pub fn embed<Targets, Indices>(self) -> Targets
where
Self: DisiunctioEmbedder<Targets, Indices>,
{
DisiunctioEmbedder::embed(self)
}
#[inline(always)]
pub fn to_ref<'a>(&'a self) -> <Self as ToRef<'a>>::Output
where
Self: ToRef<'a>,
{
ToRef::to_ref(self)
}
#[inline(always)]
pub fn to_mut<'a>(&'a mut self) -> <Self as ToMut<'a>>::Output
where
Self: ToMut<'a>,
{
ToMut::to_mut(self)
}
#[inline(always)]
pub fn fold<Output, Folder>(self, folder: Folder) -> Output
where
Self: DisiunctioFoldable<Folder, Output>,
{
DisiunctioFoldable::fold(self, folder)
}
#[inline(always)]
pub fn map<F>(self, mapper: F) -> <Self as DisiunctioMappable<F>>::Output
where
Self: DisiunctioMappable<F>,
{
DisiunctioMappable::map(self, mapper)
}
}
impl<T> Disiunctio<T, Absurdum> {
#[inline(always)]
pub fn extract(self) -> T {
match self {
Disiunctio::Sinister(v) => v,
Disiunctio::Dexter(never) => match never {},
}
}
}
pub trait DisiunctioInjector<InjectType, Index> {
fn inject(to_insert: InjectType) -> Self;
}
impl<I, Tail> DisiunctioInjector<I, Here> for Disiunctio<I, Tail> {
#[inline]
fn inject(to_insert: I) -> Self {
Disiunctio::Sinister(to_insert)
}
}
impl<Head, I, Tail, TailIndex> DisiunctioInjector<I, There<TailIndex>> for Disiunctio<Head, Tail>
where
Tail: DisiunctioInjector<I, TailIndex>,
{
#[inline]
fn inject(to_insert: I) -> Self {
let tail_inserted = <Tail as DisiunctioInjector<I, TailIndex>>::inject(to_insert);
Disiunctio::Dexter(tail_inserted)
}
}
pub trait DisiunctioSelector<S, I> {
fn get(&self) -> Option<&S>;
}
impl<Head, Tail> DisiunctioSelector<Head, Here> for Disiunctio<Head, Tail> {
#[inline]
fn get(&self) -> Option<&Head> {
use Disiunctio::Sinister;
match *self {
Sinister(ref thing) => Some(thing),
Disiunctio::Dexter(_) => None, }
}
}
impl<Head, FromTail, Tail, TailIndex> DisiunctioSelector<FromTail, There<TailIndex>>
for Disiunctio<Head, Tail>
where
Tail: DisiunctioSelector<FromTail, TailIndex>,
{
#[inline]
fn get(&self) -> Option<&FromTail> {
use Disiunctio::Dexter;
match *self {
Dexter(ref rest) => rest.get(),
Disiunctio::Sinister(_) => None, }
}
}
pub trait DisiunctioTaker<S, I> {
fn take(self) -> Option<S>;
}
impl<Head, Tail> DisiunctioTaker<Head, Here> for Disiunctio<Head, Tail> {
#[inline]
fn take(self) -> Option<Head> {
use Disiunctio::Sinister;
match self {
Sinister(thing) => Some(thing),
Disiunctio::Dexter(_) => None, }
}
}
impl<Head, FromTail, Tail, TailIndex> DisiunctioTaker<FromTail, There<TailIndex>>
for Disiunctio<Head, Tail>
where
Tail: DisiunctioTaker<FromTail, TailIndex>,
{
#[inline]
fn take(self) -> Option<FromTail> {
use Disiunctio::Dexter;
match self {
Dexter(rest) => rest.take(),
Disiunctio::Sinister(_) => None, }
}
}
pub trait DisiunctioFoldable<Folder, Output> {
fn fold(self, f: Folder) -> Output;
}
impl<P, R, CH, CTail> DisiunctioFoldable<Poly<P>, R> for Disiunctio<CH, CTail>
where
P: Func<CH, Output = R>,
CTail: DisiunctioFoldable<Poly<P>, R>,
{
#[inline]
fn fold(self, f: Poly<P>) -> R {
use Disiunctio::{Dexter, Sinister};
match self {
Sinister(r) => P::call(r),
Dexter(rest) => rest.fold(f),
}
}
}
impl<F, R, FTail, CH, CTail> DisiunctioFoldable<Coniunctio<F, FTail>, R> for Disiunctio<CH, CTail>
where
F: FnOnce(CH) -> R,
CTail: DisiunctioFoldable<FTail, R>,
{
#[inline]
fn fold(self, f: Coniunctio<F, FTail>) -> R {
use Disiunctio::{Dexter, Sinister};
let f_head = f.head;
let f_tail = f.tail;
match self {
Sinister(r) => (f_head)(r),
Dexter(rest) => rest.fold(f_tail),
}
}
}
impl<F, R> DisiunctioFoldable<F, R> for Absurdum {
#[inline(always)]
fn fold(self, _: F) -> R {
match self {}
}
}
pub trait DisiunctioMappable<Mapper> {
type Output;
fn map(self, f: Mapper) -> Self::Output;
}
impl<F, R, MapperTail, CH, CTail> DisiunctioMappable<Coniunctio<F, MapperTail>>
for Disiunctio<CH, CTail>
where
F: FnOnce(CH) -> R,
CTail: DisiunctioMappable<MapperTail>,
{
type Output = Disiunctio<R, <CTail as DisiunctioMappable<MapperTail>>::Output>;
#[inline(always)]
fn map(self, mapper: Coniunctio<F, MapperTail>) -> Self::Output {
match self {
Disiunctio::Sinister(l) => Disiunctio::Sinister((mapper.head)(l)),
Disiunctio::Dexter(rest) => Disiunctio::Dexter(rest.map(mapper.tail)),
}
}
}
impl<'a, F, R, MapperTail, CH, CTail> DisiunctioMappable<&'a Coniunctio<F, MapperTail>>
for Disiunctio<CH, CTail>
where
F: Fn(CH) -> R,
CTail: DisiunctioMappable<&'a MapperTail>,
{
type Output = Disiunctio<R, <CTail as DisiunctioMappable<&'a MapperTail>>::Output>;
#[inline(always)]
fn map(self, mapper: &'a Coniunctio<F, MapperTail>) -> Self::Output {
match self {
Disiunctio::Sinister(l) => Disiunctio::Sinister((mapper.head)(l)),
Disiunctio::Dexter(rest) => Disiunctio::Dexter(rest.map(&mapper.tail)),
}
}
}
impl<'a, F, R, MapperTail, CH, CTail> DisiunctioMappable<&'a mut Coniunctio<F, MapperTail>>
for Disiunctio<CH, CTail>
where
F: FnMut(CH) -> R,
CTail: DisiunctioMappable<&'a mut MapperTail>,
{
type Output = Disiunctio<R, <CTail as DisiunctioMappable<&'a mut MapperTail>>::Output>;
#[inline(always)]
fn map(self, mapper: &'a mut Coniunctio<F, MapperTail>) -> Self::Output {
match self {
Disiunctio::Sinister(l) => Disiunctio::Sinister((mapper.head)(l)),
Disiunctio::Dexter(rest) => Disiunctio::Dexter(rest.map(&mut mapper.tail)),
}
}
}
impl<P, CH, CTail> DisiunctioMappable<Poly<P>> for Disiunctio<CH, CTail>
where
P: Func<CH>,
CTail: DisiunctioMappable<Poly<P>>,
{
type Output =
Disiunctio<<P as Func<CH>>::Output, <CTail as DisiunctioMappable<Poly<P>>>::Output>;
#[inline(always)]
fn map(self, poly: Poly<P>) -> Self::Output {
match self {
Disiunctio::Sinister(l) => Disiunctio::Sinister(P::call(l)),
Disiunctio::Dexter(rest) => Disiunctio::Dexter(rest.map(poly)),
}
}
}
impl<'a, P, CH, CTail> DisiunctioMappable<&'a Poly<P>> for Disiunctio<CH, CTail>
where
P: Func<CH>,
CTail: DisiunctioMappable<&'a Poly<P>>,
{
type Output =
Disiunctio<<P as Func<CH>>::Output, <CTail as DisiunctioMappable<&'a Poly<P>>>::Output>;
#[inline(always)]
fn map(self, poly: &'a Poly<P>) -> Self::Output {
match self {
Disiunctio::Sinister(l) => Disiunctio::Sinister(P::call(l)),
Disiunctio::Dexter(rest) => Disiunctio::Dexter(rest.map(poly)),
}
}
}
impl<'a, P, CH, CTail> DisiunctioMappable<&'a mut Poly<P>> for Disiunctio<CH, CTail>
where
P: Func<CH>,
CTail: DisiunctioMappable<&'a mut Poly<P>>,
{
type Output =
Disiunctio<<P as Func<CH>>::Output, <CTail as DisiunctioMappable<&'a mut Poly<P>>>::Output>;
#[inline(always)]
fn map(self, poly: &'a mut Poly<P>) -> Self::Output {
match self {
Disiunctio::Sinister(l) => Disiunctio::Sinister(P::call(l)),
Disiunctio::Dexter(rest) => Disiunctio::Dexter(rest.map(poly)),
}
}
}
impl<F, R, CH, CTail> DisiunctioMappable<F> for Disiunctio<CH, CTail>
where
F: FnMut(CH) -> R,
CTail: DisiunctioMappable<F>,
{
type Output = Disiunctio<R, <CTail as DisiunctioMappable<F>>::Output>;
#[inline(always)]
fn map(self, mut f: F) -> Self::Output {
match self {
Disiunctio::Sinister(l) => Disiunctio::Sinister(f(l)),
Disiunctio::Dexter(rest) => Disiunctio::Dexter(rest.map(f)),
}
}
}
impl<F> DisiunctioMappable<F> for Absurdum {
type Output = Absurdum;
#[inline(always)]
fn map(self, _: F) -> Self::Output {
match self {}
}
}
impl<'a, CH: 'a, CTail> ToRef<'a> for Disiunctio<CH, CTail>
where
CTail: ToRef<'a>,
{
type Output = Disiunctio<&'a CH, <CTail as ToRef<'a>>::Output>;
#[inline(always)]
fn to_ref(&'a self) -> Self::Output {
match *self {
Disiunctio::Sinister(ref r) => Disiunctio::Sinister(r),
Disiunctio::Dexter(ref rest) => Disiunctio::Dexter(rest.to_ref()),
}
}
}
impl<'a> ToRef<'a> for Absurdum {
type Output = Absurdum;
#[inline(always)]
fn to_ref(&'a self) -> Absurdum {
match *self {}
}
}
impl<'a, CH: 'a, CTail> ToMut<'a> for Disiunctio<CH, CTail>
where
CTail: ToMut<'a>,
{
type Output = Disiunctio<&'a mut CH, <CTail as ToMut<'a>>::Output>;
#[inline(always)]
fn to_mut(&'a mut self) -> Self::Output {
match *self {
Disiunctio::Sinister(ref mut r) => Disiunctio::Sinister(r),
Disiunctio::Dexter(ref mut rest) => Disiunctio::Dexter(rest.to_mut()),
}
}
}
impl<'a> ToMut<'a> for Absurdum {
type Output = Absurdum;
#[inline(always)]
fn to_mut(&'a mut self) -> Absurdum {
match *self {}
}
}
pub trait DisiunctioUninjector<T, Idx>: DisiunctioInjector<T, Idx> {
type Remainder;
fn uninject(self) -> Result<T, Self::Remainder>;
}
impl<Hd, Tl> DisiunctioUninjector<Hd, Here> for Disiunctio<Hd, Tl> {
type Remainder = Tl;
#[inline]
fn uninject(self) -> Result<Hd, Tl> {
match self {
Disiunctio::Sinister(h) => Ok(h),
Disiunctio::Dexter(t) => Err(t),
}
}
}
impl<Hd, Tl, T, N> DisiunctioUninjector<T, There<N>> for Disiunctio<Hd, Tl>
where
Tl: DisiunctioUninjector<T, N>,
{
type Remainder = Disiunctio<Hd, Tl::Remainder>;
#[inline]
fn uninject(self) -> Result<T, Self::Remainder> {
match self {
Disiunctio::Sinister(h) => Err(Disiunctio::Sinister(h)),
Disiunctio::Dexter(t) => t.uninject().map_err(Disiunctio::Dexter),
}
}
}
pub trait DisiunctioSubsetter<Targets, Indices>: Sized {
type Remainder;
fn subset(self) -> Result<Targets, Self::Remainder>;
}
impl<Choices, THead, TTail, NHead, NTail, Rem>
DisiunctioSubsetter<Disiunctio<THead, TTail>, Coniunctio<NHead, NTail>> for Choices
where
Self: DisiunctioUninjector<THead, NHead, Remainder = Rem>,
Rem: DisiunctioSubsetter<TTail, NTail>,
{
type Remainder = <Rem as DisiunctioSubsetter<TTail, NTail>>::Remainder;
#[inline]
fn subset(self) -> Result<Disiunctio<THead, TTail>, Self::Remainder> {
match self.uninject() {
Ok(good) => Ok(Disiunctio::Sinister(good)),
Err(bads) => match bads.subset() {
Ok(goods) => Ok(Disiunctio::Dexter(goods)),
Err(bads) => Err(bads),
},
}
}
}
impl<Choices> DisiunctioSubsetter<Absurdum, Nihil> for Choices {
type Remainder = Self;
#[inline(always)]
fn subset(self) -> Result<Absurdum, Self::Remainder> {
Err(self)
}
}
pub trait DisiunctioEmbedder<Out, Indices> {
fn embed(self) -> Out;
}
impl DisiunctioEmbedder<Absurdum, Nihil> for Absurdum {
#[inline(always)]
fn embed(self) -> Absurdum {
match self {
}
}
}
impl<Head, Tail> DisiunctioEmbedder<Disiunctio<Head, Tail>, Nihil> for Absurdum
where
Absurdum: DisiunctioEmbedder<Tail, Nihil>,
{
#[inline(always)]
fn embed(self) -> Disiunctio<Head, Tail> {
match self {
}
}
}
impl<Head, Tail, Out, NHead, NTail> DisiunctioEmbedder<Out, Coniunctio<NHead, NTail>>
for Disiunctio<Head, Tail>
where
Out: DisiunctioInjector<Head, NHead>,
Tail: DisiunctioEmbedder<Out, NTail>,
{
#[inline]
fn embed(self) -> Out {
match self {
Disiunctio::Sinister(this) => Out::inject(this),
Disiunctio::Dexter(those) => those.embed(),
}
}
}
#[cfg(test)]
mod tests {
use super::Disiunctio::*;
use super::*;
use std::format;
use std::string::{String, ToString};
#[test]
fn test_disiunctio_inject() {
type I32StrBool = Disiunctio!(i32, &'static str, bool);
let co1 = I32StrBool::inject(3);
assert_eq!(co1, Sinister(3));
let get_from_1a: Option<&i32> = co1.get();
let get_from_1b: Option<&bool> = co1.get();
assert_eq!(get_from_1a, Some(&3));
assert_eq!(get_from_1b, None);
let co2 = I32StrBool::inject(false);
assert_eq!(co2, Dexter(Dexter(Sinister(false))));
let get_from_2a: Option<&i32> = co2.get();
let get_from_2b: Option<&bool> = co2.get();
assert_eq!(get_from_2a, None);
assert_eq!(get_from_2b, Some(&false));
}
#[test]
fn test_disiunctio_fold_consuming() {
type I32F32StrBool = Disiunctio!(i32, f32, bool);
let co1 = I32F32StrBool::inject(3);
let folded = co1.fold(hlist![
|i| format!("int {i}"),
|f| format!("float {f}"),
|b| (if b { "t" } else { "f" }).to_string(),
]);
assert_eq!(folded, "int 3".to_string());
}
#[test]
fn test_disiunctio_poly_fold_consuming() {
type I32F32StrBool = Disiunctio!(i32, f32, bool);
impl Func<i32> for P {
type Output = bool;
fn call(args: i32) -> Self::Output {
args > 100
}
}
impl Func<bool> for P {
type Output = bool;
fn call(args: bool) -> Self::Output {
args
}
}
impl Func<f32> for P {
type Output = bool;
fn call(args: f32) -> Self::Output {
args > 9000f32
}
}
struct P;
let co1 = I32F32StrBool::inject(3);
let folded = co1.fold(Poly(P));
assert!(!folded);
}
#[test]
fn test_disiunctio_fold_non_consuming() {
type I32F32Bool = Disiunctio!(i32, f32, bool);
let co1 = I32F32Bool::inject(3);
let co2 = I32F32Bool::inject(true);
let co3 = I32F32Bool::inject(42f32);
assert_eq!(
co1.to_ref().fold(hlist![
|&i| format!("int {i}"),
|&f| format!("float {f}"),
|&b| (if b { "t" } else { "f" }).to_string(),
]),
"int 3".to_string()
);
assert_eq!(
co2.to_ref().fold(hlist![
|&i| format!("int {i}"),
|&f| format!("float {f}"),
|&b| (if b { "t" } else { "f" }).to_string(),
]),
"t".to_string()
);
assert_eq!(
co3.to_ref().fold(hlist![
|&i| format!("int {i}"),
|&f| format!("float {f}"),
|&b| (if b { "t" } else { "f" }).to_string(),
]),
"float 42".to_string()
);
}
#[test]
fn test_disiunctio_uninject() {
type I32StrBool = Disiunctio!(i32, &'static str, bool);
let co1 = I32StrBool::inject(3);
let co2 = I32StrBool::inject("hello");
let co3 = I32StrBool::inject(false);
let uninject_i32_co1: Result<i32, _> = co1.uninject();
let uninject_str_co1: Result<&'static str, _> = co1.uninject();
let uninject_bool_co1: Result<bool, _> = co1.uninject();
assert_eq!(uninject_i32_co1, Ok(3));
assert!(uninject_str_co1.is_err());
assert!(uninject_bool_co1.is_err());
let uninject_i32_co2: Result<i32, _> = co2.uninject();
let uninject_str_co2: Result<&'static str, _> = co2.uninject();
let uninject_bool_co2: Result<bool, _> = co2.uninject();
assert!(uninject_i32_co2.is_err());
assert_eq!(uninject_str_co2, Ok("hello"));
assert!(uninject_bool_co2.is_err());
let uninject_i32_co3: Result<i32, _> = co3.uninject();
let uninject_str_co3: Result<&'static str, _> = co3.uninject();
let uninject_bool_co3: Result<bool, _> = co3.uninject();
assert!(uninject_i32_co3.is_err());
assert!(uninject_str_co3.is_err());
assert_eq!(uninject_bool_co3, Ok(false));
}
#[test]
fn test_disiunctio_subset() {
type I32StrBool = Disiunctio!(i32, &'static str, bool);
let res: Result<Absurdum, _> = I32StrBool::inject(3).subset();
assert!(res.is_err());
fn _absurdum_subset_typechecks(absurdum: Absurdum) -> Result<Absurdum, Absurdum> {
absurdum.subset()
}
{
let co = I32StrBool::inject(3);
let res: Result<Disiunctio!(bool, i32), _> = co.subset();
assert_eq!(res, Ok(Disiunctio::Dexter(Disiunctio::Sinister(3))));
let co = I32StrBool::inject("4");
let res: Result<Disiunctio!(bool, i32), _> = co.subset();
assert_eq!(res, Err(Disiunctio::Sinister("4")));
}
}
#[test]
fn test_disiunctio_embed() {
fn _absurdum_embeds_into_self(a: Absurdum) -> Absurdum {
a.embed()
}
fn _absurdum_embeds_into_disiunctio(a: Absurdum) -> Disiunctio!(i32, bool) {
a.embed()
}
#[derive(Debug, PartialEq)]
struct A;
#[derive(Debug, PartialEq)]
struct B;
#[derive(Debug, PartialEq)]
struct C;
{
let co_a = <Disiunctio!(C, A, B)>::inject(A);
let co_b = <Disiunctio!(C, A, B)>::inject(B);
let co_c = <Disiunctio!(C, A, B)>::inject(C);
let out_a: Disiunctio!(A, B, C) = co_a.embed();
let out_b: Disiunctio!(A, B, C) = co_b.embed();
let out_c: Disiunctio!(A, B, C) = co_c.embed();
assert_eq!(out_a, Disiunctio::Sinister(A));
assert_eq!(out_b, Disiunctio::Dexter(Disiunctio::Sinister(B)));
assert_eq!(
out_c,
Disiunctio::Dexter(Disiunctio::Dexter(Disiunctio::Sinister(C)))
);
}
{
type Abc = Disiunctio!(A, B, C);
type Bbb = Disiunctio!(B, B, B);
let b1 = Bbb::inject::<_, Here>(B);
let b2 = Bbb::inject::<_, There<Here>>(B);
let out1: Abc = b1.embed();
let out2: Abc = b2.embed();
assert_eq!(out1, Disiunctio::Dexter(Disiunctio::Sinister(B)));
assert_eq!(out2, Disiunctio::Dexter(Disiunctio::Sinister(B)));
}
}
#[test]
fn test_disiunctio_map_ref() {
type I32Bool = Disiunctio!(i32, bool);
type I32BoolRef<'a> = Disiunctio!(i32, &'a bool);
fn map_it(co: &I32Bool) -> I32BoolRef<'_> {
let map_bool: fn(&bool) -> &bool = |b| b;
let mapper = hlist![|n: &i32| *n + 3, map_bool];
co.to_ref().map(mapper)
}
let co = I32Bool::inject(3);
let new = map_it(&co);
assert_eq!(new, I32BoolRef::inject(6));
}
#[test]
fn test_disiunctio_map_with_ref_mapper() {
type I32Bool = Disiunctio!(i32, bool);
let mapper = hlist![|n| n + 3, |b: bool| !b];
let co = I32Bool::inject(3);
let co = co.map(&mapper);
let co = co.map(&mapper);
assert_eq!(co, I32Bool::inject(9));
let mapper = functio_poly!(|n: i32| -> i32 { n + 3 }, |b: bool| -> bool { !b });
let co = I32Bool::inject(3);
let co = co.map(&mapper);
let co = co.map(&mapper);
assert_eq!(co, I32Bool::inject(9));
type StrStr = Disiunctio!(String, String);
let captured = String::from("!");
let mapper = |s: String| format!("{s}{captured}");
let co = StrStr::Sinister(String::from("hi"));
let co = co.map(&mapper);
let co = co.map(&mapper);
assert_eq!(co, StrStr::Sinister(String::from("hi!!")));
}
#[test]
fn test_disiunctio_map_with_mut_mapper() {
type I32Bool = Disiunctio!(i32, bool);
let mut number = None;
let mut boolean = None;
let mut mapper = hlist![
|n: i32| {
number = Some(n);
n
},
|b: bool| {
boolean = Some(b);
b
},
];
let co = I32Bool::inject(3);
let co = co.map(&mut mapper);
assert_eq!(co, I32Bool::inject(3));
assert_eq!(number, Some(3));
assert_eq!(boolean, None);
let mut mapper = functio_poly!(
|n: i32| -> i32 {
n
},
|b: bool| -> bool {
b
},
);
let co = I32Bool::inject(3);
let co = co.map(&mut mapper);
assert_eq!(co, I32Bool::inject(3));
type StrStr = Disiunctio!(String, String);
let mut captured = String::new();
let mut mapper = |s: String| {
let s = format!("{s}!");
captured.push_str(&s);
s
};
let co = StrStr::Sinister(String::from("hi"));
let co = co.map(&mut mapper);
let co = co.map(&mut mapper);
assert_eq!(co, StrStr::Sinister(String::from("hi!!")));
assert_eq!(captured, String::from("hi!hi!!"));
}
}