use std::error::Error;
use std::fmt::Debug;
use std::future::{Future, IntoFuture};
use std::marker::PhantomData;
use std::pin::Pin;
use http::HeaderMap;
use crate::api::reply::Reply;
use crate::api::{Body, Client, Provider};
pub type Request<R, P> = RequestHandler<RequestSet<R, P>, NoOwner, NoProvider>;
pub trait Handler<P: Provider>: Sized {
type Input;
type Output: Body;
type Error: Error + Send + Sync;
fn from_input(input: Self::Input) -> Result<Self, Self::Error>;
fn handler(
input: Self::Input,
) -> Result<RequestHandler<RequestSet<Self, P>, NoOwner, NoProvider>, Self::Error> {
let request = Self::from_input(input)?;
let handler = RequestHandler::new().request(request);
Ok(handler)
}
fn handle(
self, ctx: Context<P>,
) -> impl Future<Output = Result<Reply<Self::Output>, Self::Error>> + Send;
}
pub struct NoOwner;
pub struct OwnerSet<'a>(&'a str);
pub struct NoProvider;
pub struct ProviderSet<'a, P: Provider>(&'a P);
pub struct NoRequest;
pub struct RequestSet<R: Handler<P>, P: Provider>(R, PhantomData<P>);
#[derive(Debug)]
pub struct RequestHandler<R, O, P> {
request: R,
headers: HeaderMap<String>,
owner: O,
provider: P,
}
impl Default for RequestHandler<NoRequest, NoOwner, NoProvider> {
fn default() -> Self {
Self {
request: NoRequest,
headers: HeaderMap::default(),
owner: NoOwner,
provider: NoProvider,
}
}
}
impl RequestHandler<NoRequest, NoOwner, NoProvider> {
#[must_use]
pub fn new() -> Self {
Self::default()
}
pub(crate) fn from_client<R, P>(
client: &Client<P>, request: R,
) -> RequestHandler<RequestSet<R, P>, OwnerSet<'_>, ProviderSet<'_, P>>
where
R: Handler<P>,
P: Provider,
{
RequestHandler {
request: RequestSet(request, PhantomData),
headers: HeaderMap::default(),
owner: OwnerSet(&client.owner),
provider: ProviderSet(&client.provider),
}
}
}
impl<R, P> RequestHandler<R, NoOwner, P> {
#[must_use]
pub fn owner(self, owner: &str) -> RequestHandler<R, OwnerSet<'_>, P> {
RequestHandler {
request: self.request,
headers: self.headers,
owner: OwnerSet(owner),
provider: self.provider,
}
}
}
impl<R, O> RequestHandler<R, O, NoProvider> {
pub fn provider<P: Provider>(self, provider: &P) -> RequestHandler<R, O, ProviderSet<'_, P>> {
RequestHandler {
request: self.request,
headers: self.headers,
owner: self.owner,
provider: ProviderSet(provider),
}
}
}
impl<O, P> RequestHandler<NoRequest, O, P> {
pub fn request<R, Pr>(self, request: R) -> RequestHandler<RequestSet<R, Pr>, O, P>
where
R: Handler<Pr>,
Pr: Provider,
{
RequestHandler {
request: RequestSet(request, PhantomData),
headers: self.headers,
owner: self.owner,
provider: self.provider,
}
}
}
impl<R, O, P> RequestHandler<R, O, P> {
#[must_use]
pub fn headers(mut self, headers: HeaderMap<String>) -> Self {
self.headers = headers;
self
}
}
impl<R, P> RequestHandler<RequestSet<R, P>, OwnerSet<'_>, ProviderSet<'_, P>>
where
R: Handler<P>,
P: Provider,
{
#[inline]
pub async fn handle(self) -> Result<Reply<R::Output>, <R as Handler<P>>::Error> {
let ctx = Context {
owner: self.owner.0,
provider: self.provider.0,
headers: &self.headers,
};
self.request.0.handle(ctx).await
}
}
impl<'a, R, P> IntoFuture for RequestHandler<RequestSet<R, P>, OwnerSet<'a>, ProviderSet<'a, P>>
where
P: Provider + 'a,
R: Handler<P> + Send + 'a,
{
type IntoFuture = Pin<Box<dyn Future<Output = Self::Output> + Send + 'a>>;
type Output = Result<Reply<R::Output>, <R as Handler<P>>::Error>;
fn into_future(self) -> Self::IntoFuture
where
R::Output: Body,
<R as Handler<P>>::Error: Send,
{
Box::pin(self.handle())
}
}
#[derive(Clone, Copy, Debug)]
pub struct Context<'a, P: Provider> {
pub owner: &'a str,
pub provider: &'a P,
pub headers: &'a HeaderMap<String>,
}