1use std::{
2 future::Future,
3 marker::PhantomData,
4 pin::Pin,
5 task::{Context, Poll},
6};
7
8use pin_project::pin_project;
9
10use crate::Svc;
11
12pub type BoxFut<Res> = Pin<Box<dyn Future<Output = Res>>>;
13pub type BoxSvc<Req, Res> = Pin<Box<dyn Svc<Req, Res = Res, Fut = BoxFut<Res>>>>;
14
15impl<Req, Res> Svc<Req> for BoxSvc<Req, Res> {
16 type Res = Res;
17 type Fut = BoxFut<Res>;
18
19 fn poll_ready(mut self: Pin<&mut Self>, cx: Context<'_>) -> Poll<()> {
20 self.as_mut().poll_ready(cx)
21 }
22
23 fn exec(mut self: Pin<&mut Self>, req: Req) -> Self::Fut {
24 self.as_mut().exec(req)
25 }
26}
27
28pub fn box_svc<S, Req>(svc: S) -> BoxSvc<Req, S::Res>
29where
30 S: Svc<Req> + 'static,
31 Req: 'static,
32{
33 Box::pin(SvcWrapper::new(svc))
34}
35
36#[pin_project]
37struct SvcWrapper<S: Svc<Req>, Req> {
38 #[pin]
39 svc: S,
40 _req: PhantomData<Req>,
41}
42
43impl<S: Svc<Req>, Req> SvcWrapper<S, Req> {
44 fn new(svc: S) -> Self {
45 Self {
46 svc,
47 _req: PhantomData,
48 }
49 }
50}
51
52impl<S, Req> Svc<Req> for SvcWrapper<S, Req>
53where
54 S: Svc<Req>,
55 S::Fut: 'static,
56{
57 type Res = S::Res;
58 type Fut = BoxFut<S::Res>;
59
60 fn poll_ready(self: Pin<&mut Self>, cx: Context<'_>) -> Poll<()> {
61 let this = self.project();
62 this.svc.poll_ready(cx)
63 }
64
65 fn exec(self: Pin<&mut Self>, req: Req) -> Self::Fut {
66 let this = self.project();
67 Box::pin(this.svc.exec(req))
68 }
69}
70
71#[cfg(test)]
72mod tests {
73 use std::{cell::RefCell, rc::Rc};
74
75 use super::*;
76 use crate::FnSvc;
77
78 #[tokio::test]
79 async fn test_boxed() {
80 let sum = Rc::new(RefCell::new(0));
81 let sum2 = Rc::clone(&sum);
82 let running_sum = move |n: u64| {
83 let sum = Rc::clone(&sum2);
84 Box::pin(async move {
85 *sum.borrow_mut() += n;
86 *sum.borrow()
87 })
88 };
89
90 let svc = FnSvc::new(running_sum);
91 let mut boxed_srv = box_svc(svc);
92
93 let res = boxed_srv.as_mut().exec(20).await;
94 assert_eq!(res, 20);
95
96 let res = boxed_srv.as_mut().exec(14).await;
97 assert_eq!(res, 34);
98 }
99}