timvw_rust_runtime/
local_service.rs1use std::fmt;
2use std::future::Future;
3use std::pin::Pin;
4use std::task::{Context, Poll};
5
6use tower::{Service, ServiceExt};
7
8type LocalBoxFuture<T> = Pin<Box<dyn Future<Output = T>>>;
9
10pub struct LocalBoxCloneService<T, U, E>(
17 Box<dyn CloneService<T, Response = U, Error = E, Future = LocalBoxFuture<Result<U, E>>>>,
18);
19
20impl<T, U, E> LocalBoxCloneService<T, U, E> {
21 pub fn new<S>(inner: S) -> Self
23 where
24 S: Service<T, Response = U, Error = E> + Clone + 'static,
25 S::Future: 'static,
26 {
27 let inner = inner.map_future(|future| Box::pin(future) as LocalBoxFuture<_>);
28 Self(Box::new(inner))
29 }
30}
31
32impl<T, U, E> Service<T> for LocalBoxCloneService<T, U, E> {
33 type Response = U;
34 type Error = E;
35 type Future = LocalBoxFuture<Result<U, E>>;
36
37 fn poll_ready(&mut self, cx: &mut Context<'_>) -> Poll<Result<(), E>> {
38 self.0.poll_ready(cx)
39 }
40
41 fn call(&mut self, request: T) -> Self::Future {
42 self.0.call(request)
43 }
44}
45
46impl<T, U, E> Clone for LocalBoxCloneService<T, U, E> {
47 fn clone(&self) -> Self {
48 Self(self.0.clone_box())
49 }
50}
51
52impl<T, U, E> fmt::Debug for LocalBoxCloneService<T, U, E> {
53 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
54 f.debug_struct("LocalBoxCloneService")
55 .finish_non_exhaustive()
56 }
57}
58
59trait CloneService<R>: Service<R> {
60 #[allow(clippy::type_complexity)]
61 fn clone_box(
62 &self,
63 ) -> Box<
64 dyn CloneService<R, Response = Self::Response, Error = Self::Error, Future = Self::Future>,
65 >;
66}
67
68impl<R, S> CloneService<R> for S
69where
70 S: Service<R> + Clone + 'static,
71{
72 fn clone_box(
73 &self,
74 ) -> Box<dyn CloneService<R, Response = S::Response, Error = S::Error, Future = S::Future>>
75 {
76 Box::new(self.clone())
77 }
78}
79
80#[cfg(test)]
81mod tests {
82 use std::rc::Rc;
83
84 use super::*;
85
86 #[tokio::test]
87 async fn holds_and_clones_a_service_that_is_not_send() {
88 let shared = Rc::new(2);
89 let service = tower::service_fn(move |n: i32| {
90 let shared = shared.clone();
91 async move { Ok::<_, std::convert::Infallible>(n * *shared) }
92 });
93 let boxed = LocalBoxCloneService::new(service);
94 let copy = boxed.clone();
95 assert_eq!(boxed.oneshot(3).await.unwrap(), 6);
96 assert_eq!(copy.oneshot(4).await.unwrap(), 8);
97 }
98}