use crate::coproduct::Coproduct;
use crate::hlist::HNil;
pub trait Generic {
type Repr;
fn into(self) -> Self::Repr;
fn from(repr: Self::Repr) -> Self;
fn convert_from<Src>(src: Src) -> Self
where
Self: Sized,
Src: Generic<Repr = Self::Repr>,
{
let repr = <Src as Generic>::into(src);
<Self as Generic>::from(repr)
}
fn map_repr<Mapper>(self, mapper: Mapper) -> Self
where
Self: Sized,
Mapper: FnOnce(Self::Repr) -> Self::Repr,
{
Self::from(mapper(self.into()))
}
fn map_inter<Inter, Mapper>(self, mapper: Mapper) -> Self
where
Self: Sized,
Inter: Generic<Repr = Self::Repr>,
Mapper: FnOnce(Inter) -> Inter,
{
Self::convert_from(mapper(Inter::convert_from(self)))
}
}
type UnaryVariant<T> = crate::HList!(T);
type GenericOptionRepr<T> = crate::Coprod!(HNil, UnaryVariant<T>);
type GenericResultRepr<T, E> = crate::Coprod!(UnaryVariant<T>, UnaryVariant<E>);
type GenericBoolRepr = crate::Coprod!(HNil, HNil);
impl<T> Generic for Option<T> {
type Repr = GenericOptionRepr<T>;
#[inline(always)]
fn into(self) -> Self::Repr {
match self {
None => Coproduct::Inl(crate::hlist![]),
Some(value) => Coproduct::Inr(Coproduct::Inl(crate::hlist![value])),
}
}
#[inline(always)]
fn from(repr: Self::Repr) -> Self {
match repr {
Coproduct::Inl(crate::hlist_pat![]) => None,
Coproduct::Inr(Coproduct::Inl(crate::hlist_pat![value])) => Some(value),
Coproduct::Inr(Coproduct::Inr(cnil)) => match cnil {},
}
}
}
impl<T, E> Generic for Result<T, E> {
type Repr = GenericResultRepr<T, E>;
#[inline(always)]
fn into(self) -> Self::Repr {
match self {
Ok(value) => Coproduct::Inl(crate::hlist![value]),
Err(value) => Coproduct::Inr(Coproduct::Inl(crate::hlist![value])),
}
}
#[inline(always)]
fn from(repr: Self::Repr) -> Self {
match repr {
Coproduct::Inl(crate::hlist_pat![value]) => Ok(value),
Coproduct::Inr(Coproduct::Inl(crate::hlist_pat![value])) => Err(value),
Coproduct::Inr(Coproduct::Inr(cnil)) => match cnil {},
}
}
}
impl Generic for bool {
type Repr = GenericBoolRepr;
#[inline(always)]
fn into(self) -> Self::Repr {
match self {
false => Coproduct::Inl(crate::hlist![]),
true => Coproduct::Inr(Coproduct::Inl(crate::hlist![])),
}
}
#[inline(always)]
fn from(repr: Self::Repr) -> Self {
match repr {
Coproduct::Inl(crate::hlist_pat![]) => false,
Coproduct::Inr(Coproduct::Inl(crate::hlist_pat![])) => true,
Coproduct::Inr(Coproduct::Inr(cnil)) => match cnil {},
}
}
}
pub fn from_generic<Dst, Repr>(repr: Repr) -> Dst
where
Dst: Generic<Repr = Repr>,
{
<Dst as Generic>::from(repr)
}
pub fn into_generic<Src, Repr>(src: Src) -> Repr
where
Src: Generic<Repr = Repr>,
{
<Src as Generic>::into(src)
}
pub fn convert_from<Src, Dst, Repr>(src: Src) -> Dst
where
Src: Generic<Repr = Repr>,
Dst: Generic<Repr = Repr>,
{
<Dst as Generic>::convert_from(src)
}
pub fn map_repr<Origin, Mapper>(val: Origin, mapper: Mapper) -> Origin
where
Origin: Generic,
Mapper: FnOnce(Origin::Repr) -> Origin::Repr,
{
<Origin as Generic>::map_repr(val, mapper)
}
pub fn map_inter<Inter, Origin, Mapper>(val: Origin, mapper: Mapper) -> Origin
where
Origin: Generic,
Inter: Generic<Repr = Origin::Repr>,
Mapper: FnOnce(Inter) -> Inter,
{
<Origin as Generic>::map_inter(val, mapper)
}