use core::marker::PhantomData;
use crate::{
access::Access,
extract::{Extract, TryExtract},
};
pub struct Present;
pub struct Optional;
pub struct Absent;
pub trait Presence {
type OptionOrSelf: Presence;
type Or<Other: Presence>: Presence;
type Output<T>: Access<T>
+ Extract<PhantomData<T>, T>
+ Extract<Option<T>, T>
+ Extract<Self::Output<T>, T>
+ TryExtract<Option<T>, T>
+ InferPresence<T, Presence = Self>;
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 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 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 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
}
}