use std::marker::PhantomData;
use std::sync::Arc;
use std::task::{Context, Poll};
use http::{Request, Response};
use paste::paste;
use tower_service::Service;
use super::Handler;
use crate::macros::all_events;
use crate::{Error, Event, RequestParser};
mod future;
#[allow(clippy::module_name_repetitions)]
pub use future::{HandlerCall, WrapErrorFuture};
#[must_use]
#[derive(Debug, Clone, Copy, Default, Hash)]
pub struct Sink {
_priv: PhantomData<()>,
}
impl Sink {
fn new() -> Self {
Self { _priv: PhantomData }
}
}
impl<T> Service<T> for Sink {
type Response = ();
type Error = Error;
type Future = futures_util::future::Ready<Result<(), Error>>;
fn poll_ready(&mut self, _cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
Poll::Ready(Ok(()))
}
#[inline]
fn call(&mut self, _request: T) -> Self::Future {
futures_util::future::ready(Ok(()))
}
}
#[must_use]
#[derive(Debug, Clone)]
pub struct WithState<State, Service> {
state: Arc<State>,
service: Service,
}
impl<State, Srv> WithState<State, Srv> {
fn new(state: State, service: Srv) -> Self {
let state = Arc::new(state);
Self { state, service }
}
fn clone_state(&self) -> State
where
State: Clone,
{
State::clone(&*self.state)
}
}
impl<State, Srv> Service<Event> for WithState<State, Srv>
where
Srv: Service<(State, Event)>,
State: Clone,
{
type Response = Srv::Response;
type Error = Srv::Error;
type Future = Srv::Future;
fn poll_ready(&mut self, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
self.service.poll_ready(cx)
}
#[inline]
fn call(&mut self, request: Event) -> Self::Future {
self.service.call((self.clone_state(), request))
}
}
impl<OState, State, Srv> Service<(OState, Event)> for WithState<State, Srv>
where
Srv: Service<(State, Event)>,
State: Clone,
{
type Response = Srv::Response;
type Error = Srv::Error;
type Future = Srv::Future;
fn poll_ready(&mut self, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
self.service.poll_ready(cx)
}
#[inline]
fn call(&mut self, (_, request): (OState, Event)) -> Self::Future {
self.service.call((self.clone_state(), request))
}
}
macro_rules! all_event_service {
(
$( $e:ident ),*
) => {
$( $crate::macros::event_service! {
#[doc = paste! { concat!(
"[`", stringify!([< $e:camel Payload >]), "`]をhandleする[`Service`]です。\n\n",
"[`Service`]: tower::Service\n",
"[`", stringify!([< $e:camel Payload >]), "`]: ",
"crate::payloads::", stringify!([< $e:camel Payload >]),
)}]
#[must_use]
#[derive(Debug, Clone)]
pub $e
} )*
};
}
all_events! {all_event_service}
impl<Service> Handler<Service> {
fn new(parser: crate::RequestParser, service: Service) -> Self {
Self { service, parser }
}
pub fn with_state<State>(self, state: State) -> Handler<WithState<State, Service>> {
let Self { service, parser } = self;
Handler {
service: WithState::new(state, service),
parser,
}
}
}
impl RequestParser {
pub fn into_handler(self) -> Handler<Sink> {
Handler::new(self, Sink::new())
}
}
macro_rules! all_handler_on_events {
(
$( $e:ident ),*
) => {
$crate::macros::handler_on_events! { $(
#[doc = paste! { concat!(
"[`", stringify!([< $e:camel Payload >]), "`]をhandleする[`Service`]を登録します。\n\n",
"引数の型`Service2`は`Service<Req>` traitを実装し、さらに以下の条件を満たす必要があります。\n\n",
"- [`Clone`]を実装している\n",
"- `Req`が次のうちいずれかと等しい\n",
" - [`", stringify!([< $e:camel Payload >]), "`]\n",
" - `(", stringify!([< $e:camel Payload >]), ",)`\n",
" - `(State, ", stringify!([< $e:camel Payload >]), ")` ",
"(`State`に関しては[`Handler::with_state`]を参照してください)\n",
"- `Service2::Response`が`()`と等しい\n",
"- `Service2::Error`が<code>Into<Box<dyn [Error] + [Send] + [Sync] + 'static>></code>を実装している\n\n",
"[`Service`]: tower::Service\n",
"[`", stringify!([< $e:camel Payload >]), "`]: ",
"crate::payloads::", stringify!([< $e:camel Payload >]), "\n",
"[`Clone`]: std::clone::Clone\n",
"[`Handler::with_state`]: crate::Handler::with_state\n",
"[Error]: std::error::Error\n",
"[Send]: std::marker::Send\n",
"[Sync]: std::marker::Sync\n",
)}]
pub $e;
)* }
};
}
all_events! {all_handler_on_events}
impl<Srv, Body> Service<Request<Body>> for Handler<Srv>
where
Srv: Service<Event, Response = (), Error = Error>,
Srv: Clone,
Body: http_body::Body,
Body::Error: Into<Box<dyn std::error::Error + Send + Sync + 'static>>,
{
type Response = Response<String>;
type Error = Error;
type Future = HandlerCall<Body, Srv>;
fn poll_ready(&mut self, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
self.service.poll_ready(cx).map_err(Error::handler)
}
fn call(&mut self, req: Request<Body>) -> Self::Future {
let parse_request = self.parser.parse_request(req);
let mut s = self.service.clone();
std::mem::swap(&mut self.service, &mut s);
HandlerCall::new(parse_request, s)
}
}