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