metatrait 0.0.0-alpha.1

RPITIT Monads
Documentation
use either::Either;

use crate::{
    base::{functor::*, morphism::*},
    existence::Sometimes,
};

pub struct Options;

impl<T> BaseUnwrap<Option<T>> for Options {
    type T = T;
}

impl BaseWrap for Options {
    type Wrap<T> = Option<T>;
}

impl BasePure for Options {
    fn pure<T>(x: T) -> Self::Wrap<T> {
        Some(x)
    }
}

impl BaseMap for Options {
    fn map<Out, In>(x: Self::Wrap<In>, f: impl FnOnce(In) -> Out) -> Self::Wrap<Out> {
        x.map(f)
    }
}

impl BaseMap2 for Options {
    fn map2<Out, In0, In1>(
        x0: Self::Wrap<In0>,
        x1: Self::Wrap<In1>,
        f: impl FnOnce(In0, In1) -> Out,
    ) -> Self::Wrap<Out> {
        x0.zip(x1).map(|(x0, x1)| f(x0, x1))
    }
}

impl BaseSelect for Options {
    fn select<In0, In1>(
        x0: Self::Wrap<In0>,
        x1: Self::Wrap<In1>,
    ) -> BaseSelectWrap<Self, In0, In1> {
        match (x0, x1) {
            (None, None) => None,
            (None, Some(x1)) => Some(Either::Right((x1, None))),
            (Some(x0), x1) => Some(Either::Left((x0, x1))),
        }
    }
}

impl BaseFlatten for Options {
    fn flatten<T>(x: Self::Wrap<Self::Wrap<T>>) -> Self::Wrap<T> {
        x.flatten()
    }
}

impl BaseIterate for Options {
    fn iterate<F: BaseIterateFn<Self>>(mut f: F) -> Self::Wrap<F::Out> {
        Some(loop {
            match f.run()? {
                Either::Left(next) => f = next,
                Either::Right(x) => break x,
            }
        })
    }
}

impl BaseToEither for Options {
    type L = Sometimes;
    type R = Sometimes;

    fn either<In, Out>(x: Self::Wrap<In>) -> BaseToEitherWrap<Self, In, Out> {
        match x {
            Some(x) => Either::Left((x, Sometimes)),
            None => Either::Right((None, Sometimes)),
        }
    }
}

impl BaseTranspose for Options {
    fn transpose<Wr: ?Sized + BasePure + BaseMap, T>(
        x: Self::Wrap<Wr::Wrap<T>>,
    ) -> Wr::Wrap<Self::Wrap<T>> {
        match x {
            Some(x) => x.b_map(Some),
            None => Wr::pure(None),
        }
    }
}

impl BaseInspect for Options {
    fn inspect<Out, In>(
        x: Self::Wrap<In>,
        f: impl FnOnce(&mut In) -> Self::Wrap<Out>,
    ) -> Self::Wrap<Out> {
        x.and_then(|mut x| f(&mut x))
    }
}