rama_http_core/
service.rs

1use bytes::Bytes;
2use rama_core::{Context, Service, error::BoxError};
3use rama_http::service::web::response::IntoResponse;
4use rama_http_types::{Request, Response};
5use std::{convert::Infallible, fmt};
6
7pub trait HttpService<ReqBody>: sealed::Sealed<ReqBody> {
8    #[doc(hidden)]
9    fn serve_http(
10        &self,
11        req: Request<ReqBody>,
12    ) -> impl Future<Output = Result<Response, Infallible>> + Send + 'static;
13}
14
15pub struct RamaHttpService<S, State> {
16    svc: S,
17    ctx: Context<State>,
18}
19
20impl<S, State> RamaHttpService<S, State> {
21    pub fn new(ctx: Context<State>, svc: S) -> Self {
22        Self { svc, ctx }
23    }
24}
25
26impl<S, State> fmt::Debug for RamaHttpService<S, State>
27where
28    S: fmt::Debug,
29    State: fmt::Debug,
30{
31    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
32        f.debug_struct("RamaHttpService")
33            .field("svc", &self.svc)
34            .field("ctx", &self.ctx)
35            .finish()
36    }
37}
38
39impl<S, State> Clone for RamaHttpService<S, State>
40where
41    S: Clone,
42    State: Clone,
43{
44    fn clone(&self) -> Self {
45        Self {
46            svc: self.svc.clone(),
47            ctx: self.ctx.clone(),
48        }
49    }
50}
51
52impl<S, State, ReqBody, R> HttpService<ReqBody> for RamaHttpService<S, State>
53where
54    S: Service<State, Request, Response = R, Error = Infallible> + Clone,
55    State: Clone + Send + Sync + 'static,
56    ReqBody: rama_http_types::dep::http_body::Body<Data = Bytes, Error: Into<BoxError>>
57        + Send
58        + Sync
59        + 'static,
60    R: IntoResponse + Send + 'static,
61{
62    fn serve_http(
63        &self,
64        req: Request<ReqBody>,
65    ) -> impl Future<Output = Result<Response, Infallible>> + Send + 'static {
66        let RamaHttpService { svc, ctx } = self.clone();
67        async move {
68            let req = req.map(rama_http_types::Body::new);
69            Ok(svc.serve(ctx, req).await?.into_response())
70        }
71    }
72}
73
74#[derive(Debug, Default)]
75#[allow(dead_code)]
76pub(crate) struct VoidHttpService;
77
78impl<ReqBody> HttpService<ReqBody> for VoidHttpService
79where
80    ReqBody: rama_http_types::dep::http_body::Body<Data = Bytes, Error: Into<BoxError>>
81        + Send
82        + Sync
83        + 'static,
84{
85    #[allow(clippy::manual_async_fn)]
86    fn serve_http(
87        &self,
88        _req: Request<ReqBody>,
89    ) -> impl Future<Output = Result<Response, Infallible>> + Send + 'static {
90        async move { Ok(Response::new(rama_http_types::Body::empty())) }
91    }
92}
93
94mod sealed {
95    use super::*;
96
97    pub trait Sealed<T>: Send + Sync + 'static {}
98
99    impl<S, State, ReqBody, R> Sealed<ReqBody> for RamaHttpService<S, State>
100    where
101        S: Service<State, Request, Response = R, Error = Infallible> + Clone,
102        State: Clone + Send + Sync + 'static,
103        ReqBody: rama_http_types::dep::http_body::Body<Data = Bytes, Error: Into<BoxError>>
104            + Send
105            + Sync
106            + 'static,
107        R: IntoResponse + Send + 'static,
108    {
109    }
110
111    impl<ReqBody> Sealed<ReqBody> for VoidHttpService where
112        ReqBody: rama_http_types::dep::http_body::Body<Data = Bytes, Error: Into<BoxError>>
113            + Send
114            + Sync
115            + 'static
116    {
117    }
118}