use std::convert::Infallible;
use crate::{all_the_tuples, BoxError};
use self::extractability::{Direct, Extractability};
mod private {
pub trait Sealed {}
}
pub mod extractability {
use super::private::Sealed;
pub trait Extractability: Sealed {}
pub enum Direct {}
impl Sealed for Direct {}
impl Extractability for Direct {}
pub enum Transitive {}
impl Sealed for Transitive {}
impl Extractability for Transitive {}
}
pub trait FromContext<C, E: Extractability = Direct>: Sized {
type Error: Into<BoxError>;
fn from_context(context: &C) -> Result<Self, Self::Error>;
fn from_context_always(context: &C) -> Self
where
Self: FromContext<C, E, Error = Infallible>,
{
Self::from_context(context).unwrap()
}
}
pub trait Extract<T> {
type Error;
fn extract(&self) -> Result<T, Self::Error>;
fn extract_always(&self) -> T
where
Self: Extract<T, Error = Infallible>,
{
self.extract().unwrap()
}
}
impl<C, T> Extract<T> for C
where
T: FromContext<C>,
{
type Error = T::Error;
fn extract(&self) -> Result<T, Self::Error> {
T::from_context(self)
}
}
impl<T, C> FromContext<C> for Option<T>
where
T: FromContext<C>,
{
type Error = Infallible;
fn from_context(context: &C) -> Result<Self, Self::Error> {
Ok(T::from_context(context).ok())
}
}
impl<T, C> FromContext<C> for Result<T, T::Error>
where
T: FromContext<C>,
{
type Error = Infallible;
fn from_context(context: &C) -> Result<Self, Self::Error> {
Ok(T::from_context(context))
}
}
impl<C> FromContext<C> for () {
type Error = Infallible;
fn from_context(_: &C) -> Result<Self, Self::Error> {
Ok(())
}
}
macro_rules! impl_from_context {
(
$($ty:ident),*
) => {
#[allow(non_snake_case)]
impl<C, $($ty, )* > FromContext<C> for ($($ty,)*)
where
$( $ty: FromContext<C>, )*
{
type Error = BoxError;
fn from_context(context: &C) -> Result<Self, Self::Error> {
$(
let $ty = $ty::from_context(context).map_err(|err| err.into())?;
)*
Ok(($($ty,)*))
}
}
}
}
all_the_tuples!(impl_from_context);