use core::marker::PhantomData;
use crate::access::Access;
pub struct Present;
pub struct Optional;
pub struct Absent;
pub trait Presence {
type OptionOrSelf: Presence;
type Or<Other: Presence>: Presence;
type RemainderFrom<Source: Presence>: Presence;
type Output<T>: Access<T>;
fn or<T, Other: Presence>(
self_: <Self as Presence>::Output<T>,
other: Other::Output<T>,
) -> <<Self as Presence>::Or<Other> as Presence>::Output<T>;
fn option_or_self<T>(
option: Option<T>,
self_: <Self as Presence>::Output<T>,
) -> <<Self as Presence>::OptionOrSelf as Presence>::Output<T>;
}
pub trait InferPresence<T> {
type Presence: Presence<Output<T> = Self>;
}
impl<T> InferPresence<T> for T {
type Presence = Present;
}
impl<T> InferPresence<T> for Option<T> {
type Presence = Optional;
}
impl<T> InferPresence<T> for PhantomData<T> {
type Presence = Absent;
}
impl Presence for Present {
type OptionOrSelf = Present;
type Or<Other: Presence> = Present;
type RemainderFrom<Source: Presence> = Absent;
type Output<T> = T;
#[inline]
fn or<T, Other: Presence>(
self_: <Self as Presence>::Output<T>,
_other: Other::Output<T>,
) -> <<Self as Presence>::Or<Other> as Presence>::Output<T> {
self_
}
#[inline]
fn option_or_self<T>(
option: Option<T>,
self_: <Self as Presence>::Output<T>,
) -> <<Self as Presence>::OptionOrSelf as Presence>::Output<T> {
option.unwrap_or(self_)
}
}
impl Presence for Optional {
type OptionOrSelf = Optional;
type Or<Other: Presence> = Other::OptionOrSelf;
type RemainderFrom<Source: Presence> = Absent;
type Output<T> = Option<T>;
#[inline]
fn or<T, Other: Presence>(
self_: <Self as Presence>::Output<T>,
other: Other::Output<T>,
) -> <<Self as Presence>::Or<Other> as Presence>::Output<T> {
Other::option_or_self(self_, other)
}
#[inline]
fn option_or_self<T>(
option: Option<T>,
self_: <Self as Presence>::Output<T>,
) -> <<Self as Presence>::OptionOrSelf as Presence>::Output<T> {
option.or(self_)
}
}
impl Presence for Absent {
type OptionOrSelf = Optional;
type Or<Other: Presence> = Other;
type RemainderFrom<Source: Presence> = Source;
type Output<T> = PhantomData<T>;
#[inline]
fn or<T, Other: Presence>(
_self: <Self as Presence>::Output<T>,
other: Other::Output<T>,
) -> <<Self as Presence>::Or<Other> as Presence>::Output<T> {
other
}
#[inline]
fn option_or_self<T>(
option: Option<T>,
_self_: <Self as Presence>::Output<T>,
) -> <<Self as Presence>::OptionOrSelf as Presence>::Output<T> {
option
}
}