use std::{
marker::PhantomData,
panic::{RefUnwindSafe, UnwindSafe},
};
mod sealed {
pub trait __SealMaybe {}
}
use sealed::*;
pub trait Maybe: Sized + __SealMaybe {
type Inner;
fn inner(&self) -> &Self::Inner;
fn inner_mut(&mut self) -> &mut Self::Inner;
fn unwrap(self) -> Self::Inner;
fn unwrap_try<F, T>(self, f: F) -> Result<T, Self>
where
F: FnOnce(Self::Inner) -> Result<T, Self::Inner>;
fn unwrap_try_x<F, T, E>(self, f: F) -> Result<T, (Self, E)>
where
F: FnOnce(Self::Inner) -> Result<T, (Self::Inner, E)>;
fn map<F, NewInner>(self, f: F) -> <Self as MaybeMap<NewInner>>::Out
where
Self: MaybeMap<NewInner>,
F: FnOnce(Self::Inner) -> NewInner,
{
<Self as MaybeMap<NewInner>>::do_map(self, f)
}
}
pub trait MaybeMap<NewInner>: Maybe {
type Out: Maybe<Inner = NewInner>;
fn do_map<F>(self, f: F) -> Self::Out
where
F: FnOnce(Self::Inner) -> NewInner;
}
pub trait Impossible {
fn absurd<T>(&self) -> T;
}
#[derive(Debug, Clone)]
#[repr(transparent)]
pub struct An<A>(pub A);
impl<A> __SealMaybe for An<A> {}
impl<A> Maybe for An<A> {
type Inner = A;
fn inner(&self) -> &A {
&self.0
}
fn inner_mut(&mut self) -> &mut A {
&mut self.0
}
fn unwrap(self) -> A {
self.0
}
fn unwrap_try<F, T>(self, f: F) -> Result<T, Self>
where
F: FnOnce(Self::Inner) -> Result<T, A>,
{
match f(self.unwrap()) {
Ok(r) => Ok(r),
Err(inner) => Err(An(inner)),
}
}
fn unwrap_try_x<F, T, E>(self, f: F) -> Result<T, (Self, E)>
where
F: FnOnce(Self::Inner) -> Result<T, (Self::Inner, E)>,
{
match f(self.unwrap()) {
Ok(r) => Ok(r),
Err((inner, e)) => Err((An(inner), e)),
}
}
fn map<F, B>(self, f: F) -> <Self as MaybeMap<B>>::Out
where
Self: MaybeMap<B>,
F: FnOnce(Self::Inner) -> B,
{
<Self as MaybeMap<B>>::do_map(self, f)
}
}
impl<A, B> MaybeMap<B> for An<A> {
type Out = An<B>;
#[inline]
fn do_map<F>(self, f: F) -> Self::Out
where
F: FnOnce(Self::Inner) -> B,
{
An(f(self.0))
}
}
#[derive(Debug, Clone)]
enum Nothing {}
#[derive(Debug)]
pub struct No<A> {
ghost: PhantomData<A>,
impossible: Nothing,
}
impl<A> Impossible for No<A> {
fn absurd<T>(&self) -> T {
match self.impossible {}
}
}
impl<A> __SealMaybe for No<A> {}
impl<A> Maybe for No<A> {
type Inner = A;
fn inner(&self) -> &A {
self.absurd()
}
fn inner_mut(&mut self) -> &mut Self::Inner {
self.absurd()
}
fn unwrap(self) -> A {
self.absurd()
}
fn unwrap_try<F, T>(self, _f: F) -> Result<T, Self>
where
F: FnOnce(Self::Inner) -> Result<T, A>,
{
self.absurd()
}
fn unwrap_try_x<F, T, E>(self, _f: F) -> Result<T, (Self, E)>
where
F: FnOnce(Self::Inner) -> Result<T, (Self::Inner, E)>,
{
self.absurd()
}
fn map<F, NewInner>(self, _: F) -> <Self as MaybeMap<NewInner>>::Out
where
Self: MaybeMap<NewInner>,
F: FnOnce(Self::Inner) -> NewInner,
{
self.absurd()
}
}
impl<A, B> MaybeMap<B> for No<A> {
type Out = No<B>;
fn do_map<F>(self, _: F) -> Self::Out
where
F: FnOnce(Self::Inner) -> B,
{
self.absurd()
}
}
impl<A> Clone for No<A> {
fn clone(&self) -> Self {
self.absurd()
}
}
impl<A> RefUnwindSafe for No<A> {}
#[cfg(feature = "allow-unsafe")]
#[allow(unsafe_code)]
unsafe impl<A> Send for No<A> {}
#[cfg(feature = "allow-unsafe")]
#[allow(unsafe_code)]
unsafe impl<A> Sync for No<A> {}
impl<A> Unpin for No<A> {}
impl<A> UnwindSafe for No<A> {}
pub trait Relax<Into>: Maybe {
fn relax(self) -> Into;
}
impl<A> Relax<An<A>> for An<A> {
fn relax(self) -> An<A> {
self
}
}
impl<A, B> Relax<An<B>> for No<A> {
fn relax(self) -> An<B> {
self.absurd()
}
}
impl<A, B> Relax<No<B>> for No<A> {
fn relax(self) -> No<B> {
self.absurd()
}
}