metatrait 0.0.0-alpha.1

RPITIT Monads
Documentation
use std::convert::identity;

use either::Either;
use ghost::phantom;

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

#[phantom]
pub struct Results<E>;

impl<T, E> BaseUnwrap<Result<T, E>> for Results<E> {
    type T = T;
}

impl<E> BaseWrap for Results<E> {
    type Wrap<T> = Result<T, E>;
}

impl<E> BasePure for Results<E> {
    fn pure<T>(x: T) -> Self::Wrap<T> {
        Ok(x)
    }
}

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

impl<E> BaseMap2 for Results<E> {
    fn map2<Out, In0, In1>(
        x0: Self::Wrap<In0>,
        x1: Self::Wrap<In1>,
        f: impl FnOnce(In0, In1) -> Out,
    ) -> Self::Wrap<Out> {
        Ok(f(x0?, x1?))
    }
}

impl<E> BaseSelect for Results<E> {
    fn select<In0, In1>(
        x0: Self::Wrap<In0>,
        x1: Self::Wrap<In1>,
    ) -> BaseSelectWrap<Self, In0, In1> {
        match (x0, x1) {
            (Err(e), Err(_)) => Err(e),
            (Err(e), Ok(x1)) => Ok(Either::Right((x1, Err(e)))),
            (Ok(x0), x1) => Ok(Either::Left((x0, x1))),
        }
    }
}

impl<E> BaseFlatten for Results<E> {
    fn flatten<T>(x: Self::Wrap<Self::Wrap<T>>) -> Self::Wrap<T> {
        x.and_then(identity)
    }
}

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

impl<E> BaseToEither for Results<E> {
    type L = Sometimes;
    type R = Sometimes;

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

impl<E> BaseTranspose for Results<E> {
    fn transpose<Wr: ?Sized + BasePure + BaseMap, T>(
        x: Self::Wrap<Wr::Wrap<T>>,
    ) -> Wr::Wrap<Self::Wrap<T>> {
        match x {
            Ok(x) => x.b_map(Ok),
            Err(e) => Wr::pure(Err(e)),
        }
    }
}

impl<E> BaseInspect for Results<E> {
    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))
    }
}