Skip to main content

trillium/
boxed_handler.rs

1use crate::{Conn, Handler, Info, Upgrade};
2use std::{
3    any::Any,
4    borrow::Cow,
5    fmt::{self, Debug, Formatter},
6    future::Future,
7    pin::Pin,
8};
9
10trait ObjectSafeHandler: Any + Send + Sync + 'static {
11    #[must_use]
12    fn run<'handler, 'fut>(
13        &'handler self,
14        conn: Conn,
15    ) -> Pin<Box<dyn Future<Output = Conn> + Send + 'fut>>
16    where
17        'handler: 'fut,
18        Self: 'fut;
19    #[must_use]
20    fn init<'handler, 'info, 'fut>(
21        &'handler mut self,
22        info: &'info mut Info,
23    ) -> Pin<Box<dyn Future<Output = ()> + Send + 'fut>>
24    where
25        'handler: 'fut,
26        'info: 'fut,
27        Self: 'fut;
28    #[must_use]
29    fn before_send<'handler, 'fut>(
30        &'handler self,
31        conn: Conn,
32    ) -> Pin<Box<dyn Future<Output = Conn> + Send + 'fut>>
33    where
34        'handler: 'fut,
35        Self: 'fut;
36    fn has_upgrade(&self, upgrade: &Upgrade) -> bool;
37    #[must_use]
38    fn upgrade<'handler, 'fut>(
39        &'handler self,
40        upgrade: Upgrade,
41    ) -> Pin<Box<dyn Future<Output = ()> + Send + 'fut>>
42    where
43        'handler: 'fut,
44        Self: 'fut;
45    fn name(&self) -> Cow<'static, str>;
46    fn as_box_any(self: Box<Self>) -> Box<dyn Any>;
47    fn as_any(&self) -> &dyn Any;
48    fn as_mut_any(&mut self) -> &mut dyn Any;
49}
50impl<H: Handler> ObjectSafeHandler for H {
51    fn run<'handler, 'fut>(
52        &'handler self,
53        conn: Conn,
54    ) -> Pin<Box<dyn Future<Output = Conn> + Send + 'fut>>
55    where
56        'handler: 'fut,
57        Self: 'fut,
58    {
59        Box::pin(async move { Handler::run(self, conn).await })
60    }
61
62    fn init<'handler, 'info, 'fut>(
63        &'handler mut self,
64        info: &'info mut Info,
65    ) -> Pin<Box<dyn Future<Output = ()> + Send + 'fut>>
66    where
67        'handler: 'fut,
68        'info: 'fut,
69        Self: 'fut,
70    {
71        Box::pin(async move {
72            Handler::init(self, info).await;
73        })
74    }
75
76    fn before_send<'handler, 'fut>(
77        &'handler self,
78        conn: Conn,
79    ) -> Pin<Box<dyn Future<Output = Conn> + Send + 'fut>>
80    where
81        'handler: 'fut,
82        Self: 'fut,
83    {
84        Box::pin(async move { Handler::before_send(self, conn).await })
85    }
86
87    fn has_upgrade(&self, upgrade: &Upgrade) -> bool {
88        Handler::has_upgrade(self, upgrade)
89    }
90
91    fn upgrade<'handler, 'fut>(
92        &'handler self,
93        upgrade: Upgrade,
94    ) -> Pin<Box<dyn Future<Output = ()> + Send + 'fut>>
95    where
96        'handler: 'fut,
97        Self: 'fut,
98    {
99        Box::pin(async move {
100            Handler::upgrade(self, upgrade).await;
101        })
102    }
103
104    fn name(&self) -> Cow<'static, str> {
105        Handler::name(self)
106    }
107
108    fn as_box_any(self: Box<Self>) -> Box<dyn Any> {
109        self
110    }
111
112    fn as_any(&self) -> &dyn Any {
113        self
114    }
115
116    fn as_mut_any(&mut self) -> &mut dyn Any {
117        self
118    }
119}
120
121/// A type-erased handler
122pub struct BoxedHandler(Box<dyn ObjectSafeHandler>);
123impl Debug for BoxedHandler {
124    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
125        f.debug_tuple("BoxedHandler").field(&self.0.name()).finish()
126    }
127}
128
129impl BoxedHandler {
130    /// Constructs a new `BoxedHandler`
131    #[must_use]
132    pub fn new(handler: impl Handler) -> Self {
133        Self(Box::new(handler))
134    }
135
136    /// Determine if this `BoxedHandler` is the specified type
137    pub fn is<T: Any + 'static>(&self) -> bool {
138        self.as_any().is::<T>()
139    }
140
141    /// Attempt to transform this `BoxedHandler` into the specified type
142    ///
143    /// # Errors
144    ///
145    /// Downcast returns the `BoxedHandler` as an error if it does not contain the provided type
146    #[must_use = "downcast takes the handler, so you must use it"]
147    #[allow(clippy::missing_panics_doc)]
148    pub fn downcast<T: Any + 'static>(self) -> Result<T, Self> {
149        if self.0.as_any().is::<T>() {
150            Ok(*self.0.as_box_any().downcast().unwrap())
151        } else {
152            Err(self)
153        }
154    }
155
156    /// Attempt to borrow this `BoxedHandler` as the provided type, returning None if it does not
157    /// contain the type
158    pub fn downcast_ref<T: Any + 'static>(&self) -> Option<&T> {
159        self.0.as_any().downcast_ref()
160    }
161
162    /// Attempt to mutably borrow this `BoxedHandler` as the provided type, returning None if it
163    /// does not contain the type
164    pub fn downcast_mut<T: Any + 'static>(&mut self) -> Option<&mut T> {
165        self.0.as_mut_any().downcast_mut()
166    }
167}
168
169impl Handler for BoxedHandler {
170    async fn run(&self, conn: Conn) -> Conn {
171        self.0.run(conn).await
172    }
173
174    async fn init(&mut self, info: &mut Info) {
175        self.0.init(info).await;
176    }
177
178    async fn before_send(&self, conn: Conn) -> Conn {
179        self.0.before_send(conn).await
180    }
181
182    fn has_upgrade(&self, upgrade: &Upgrade) -> bool {
183        self.0.has_upgrade(upgrade)
184    }
185
186    async fn upgrade(&self, upgrade: Upgrade) {
187        self.0.upgrade(upgrade).await;
188    }
189
190    fn name(&self) -> Cow<'static, str> {
191        self.0.name()
192    }
193}