1 | #![cfg_attr (not(feature = "std" ), no_std)] |
2 | |
3 | #[cfg (not(feature = "std" ))] |
4 | mod std { |
5 | pub use core::*; |
6 | } |
7 | |
8 | use std::any::{Any as StdAny, TypeId, type_name}; |
9 | use std::fmt::{self, Debug, Display}; |
10 | |
11 | #[cfg (feature = "std" )] |
12 | use std::{error::Error, rc::Rc, sync::Arc}; |
13 | |
14 | // ++++++++++++++++++++ Any ++++++++++++++++++++ |
15 | |
16 | pub trait Any: StdAny { |
17 | #[doc (hidden)] |
18 | fn as_any(&self) -> &dyn StdAny; |
19 | |
20 | #[doc (hidden)] |
21 | fn as_any_mut(&mut self) -> &mut dyn StdAny; |
22 | |
23 | #[doc (hidden)] |
24 | #[cfg (feature = "std" )] |
25 | fn into_any(self: Box<Self>) -> Box<dyn StdAny>; |
26 | |
27 | #[doc (hidden)] |
28 | #[cfg (feature = "std" )] |
29 | fn into_any_rc(self: Rc<Self>) -> Rc<dyn StdAny>; |
30 | |
31 | fn type_name(&self) -> &'static str; |
32 | } |
33 | |
34 | impl<T> Any for T where T: StdAny { |
35 | #[doc (hidden)] |
36 | fn as_any(&self) -> &dyn StdAny { self } |
37 | |
38 | #[doc (hidden)] |
39 | fn as_any_mut(&mut self) -> &mut dyn StdAny { self } |
40 | |
41 | #[cfg (feature = "std" )] |
42 | fn into_any(self: Box<Self>) -> Box<dyn StdAny> { self } |
43 | |
44 | #[cfg (feature = "std" )] |
45 | fn into_any_rc(self: Rc<Self>) -> Rc<dyn StdAny> { self } |
46 | |
47 | fn type_name(&self) -> &'static str { type_name::<Self>() } |
48 | } |
49 | |
50 | #[cfg (feature = "std" )] |
51 | pub trait AnySync: Any + Send + Sync { |
52 | fn into_any_arc(self: Arc<Self>) -> Arc<dyn StdAny + Send + Sync>; |
53 | } |
54 | |
55 | #[cfg (feature = "std" )] |
56 | impl<T> AnySync for T where T: Any + Send + Sync { |
57 | fn into_any_arc(self: Arc<Self>) -> Arc<dyn StdAny + Send + Sync> { self } |
58 | } |
59 | |
60 | // ++++++++++++++++++++ TypeMismatch ++++++++++++++++++++ |
61 | |
62 | #[derive(Debug, Clone, Copy)] |
63 | pub struct TypeMismatch { |
64 | pub expected: &'static str, |
65 | pub found: &'static str, |
66 | } |
67 | |
68 | impl TypeMismatch { |
69 | pub fn new<T, O>(found_obj: &O) -> Self |
70 | where T: Any + ?Sized, O: Any + ?Sized |
71 | { |
72 | TypeMismatch { |
73 | expected: type_name::<T>(), |
74 | found: found_obj.type_name(), |
75 | } |
76 | } |
77 | } |
78 | |
79 | impl Display for TypeMismatch { |
80 | fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { |
81 | write!(fmt, "Type mismatch: Expected '{}', found '{}'!" , self.expected, self.found) |
82 | } |
83 | } |
84 | |
85 | #[cfg (feature = "std" )] |
86 | impl Error for TypeMismatch {} |
87 | |
88 | // ++++++++++++++++++++ DowncastError ++++++++++++++++++++ |
89 | |
90 | pub struct DowncastError<O> { |
91 | mismatch: TypeMismatch, |
92 | object: O, |
93 | } |
94 | |
95 | impl<O> DowncastError<O> { |
96 | pub fn new(mismatch: TypeMismatch, object: O) -> Self { |
97 | Self{ mismatch, object } |
98 | } |
99 | pub fn type_mismatch(&self) -> TypeMismatch { self.mismatch } |
100 | pub fn into_object(self) -> O { self.object } |
101 | } |
102 | |
103 | impl<O> Debug for DowncastError<O> { |
104 | fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { |
105 | fmt.debug_struct("DowncastError" ) |
106 | .field("mismatch" , &self.mismatch) |
107 | .finish() |
108 | } |
109 | } |
110 | |
111 | impl<O> Display for DowncastError<O> { |
112 | fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { |
113 | Display::fmt(&self.mismatch, fmt) |
114 | } |
115 | } |
116 | |
117 | #[cfg (feature = "std" )] |
118 | impl<O> Error for DowncastError<O> {} |
119 | |
120 | // ++++++++++++++++++++ Downcast ++++++++++++++++++++ |
121 | |
122 | pub trait Downcast<T>: Any |
123 | where T: Any |
124 | { |
125 | fn is_type(&self) -> bool { self.type_id() == TypeId::of::<T>() } |
126 | |
127 | fn downcast_ref(&self) -> Result<&T, TypeMismatch> { |
128 | if self.is_type() { |
129 | Ok(self.as_any().downcast_ref().unwrap()) |
130 | } else { |
131 | Err(TypeMismatch::new::<T, Self>(self)) |
132 | } |
133 | } |
134 | |
135 | fn downcast_mut(&mut self) -> Result<&mut T, TypeMismatch> { |
136 | if self.is_type() { |
137 | Ok(self.as_any_mut().downcast_mut().unwrap()) |
138 | } else { |
139 | Err(TypeMismatch::new::<T, Self>(self)) |
140 | } |
141 | } |
142 | |
143 | #[cfg (feature = "std" )] |
144 | fn downcast(self: Box<Self>) -> Result<Box<T>, DowncastError<Box<Self>>> { |
145 | if self.is_type() { |
146 | Ok(self.into_any().downcast().unwrap()) |
147 | } else { |
148 | let mismatch = TypeMismatch::new::<T, Self>(&*self); |
149 | Err(DowncastError::new(mismatch, self)) |
150 | } |
151 | } |
152 | |
153 | #[cfg (feature = "std" )] |
154 | fn downcast_rc(self: Rc<Self>) -> Result<Rc<T>, DowncastError<Rc<Self>>> { |
155 | if self.is_type() { |
156 | Ok(self.into_any_rc().downcast().unwrap()) |
157 | } else { |
158 | let mismatch = TypeMismatch::new::<T, Self>(&*self); |
159 | Err(DowncastError::new(mismatch, self)) |
160 | } |
161 | } |
162 | } |
163 | |
164 | #[cfg (feature = "std" )] |
165 | pub trait DowncastSync<T>: Downcast<T> + AnySync |
166 | where T: AnySync |
167 | { |
168 | fn downcast_arc(self: Arc<Self>) -> Result<Arc<T>, DowncastError<Arc<Self>>> { |
169 | if self.is_type() { |
170 | Ok(self.into_any_arc().downcast().unwrap()) |
171 | } else { |
172 | let mismatch = TypeMismatch::new::<T, Self>(&*self); |
173 | Err(DowncastError::new(mismatch, self)) |
174 | } |
175 | } |
176 | } |
177 | |
178 | // ++++++++++++++++++++ macros ++++++++++++++++++++ |
179 | |
180 | #[doc (hidden)] |
181 | pub mod _std { |
182 | #[cfg (feature = "std" )] |
183 | pub use std::*; |
184 | #[cfg (not(feature = "std" ))] |
185 | pub use core::*; |
186 | } |
187 | |
188 | /// Implements [`Downcast`](trait.Downcast.html) for your trait-object-type. |
189 | /// |
190 | /// ```ignore |
191 | /// impl_downcast!(Foo); |
192 | /// impl_downcast!(<B> Foo<B> where B: Bar); |
193 | /// impl_downcast!(<B> Foo<Bar = B>); |
194 | /// ``` |
195 | /// |
196 | /// expands to |
197 | /// |
198 | /// ```ignore |
199 | /// impl<T> Downcast<T> for Foo |
200 | /// where T: Any |
201 | /// {} |
202 | /// |
203 | /// impl<T, B> Downcast<T> for Foo<B> |
204 | /// where T: Any, B: Bar |
205 | /// {} |
206 | /// |
207 | /// impl<T, B> Downcast<T> for Foo<Bar = B> |
208 | /// where T: Any |
209 | /// {} |
210 | /// ``` |
211 | #[macro_export ] |
212 | macro_rules! impl_downcast { |
213 | (<$($params:ident),+ $(,)*> $base:ty $(where $($bounds:tt)+)*) => { |
214 | impl<_T, $($params),+> $crate::Downcast<_T> for $base |
215 | where _T: $crate::Any, $($params: 'static,)* $($($bounds)+)* |
216 | {} |
217 | }; |
218 | ($base:ty) => { |
219 | impl<_T> $crate::Downcast<_T> for $base |
220 | where _T: $crate::Any |
221 | {} |
222 | }; |
223 | } |
224 | |
225 | /// Implements [`Downcast`](trait.Downcast.html) and [`DowncastSync`](trait.DowncastSync.html) for your trait-object-type. |
226 | #[cfg (feature = "std" )] |
227 | #[macro_export ] |
228 | macro_rules! impl_downcast_sync { |
229 | (<$($params:ident),+ $(,)*> $base:ty $(where $($bounds:tt)+)*) => { |
230 | impl<_T, $($params),+> $crate::Downcast<_T> for $base |
231 | where _T: $crate::Any, $($params: 'static,)* $($($bounds)+)* |
232 | {} |
233 | |
234 | impl<_T, $($params),+> $crate::DowncastSync<_T> for $base |
235 | where _T: $crate::AnySync, $($params: 'static,)* $($($bounds)+)* |
236 | {} |
237 | }; |
238 | ($base:ty) => { |
239 | impl<_T> $crate::Downcast<_T> for $base |
240 | where _T: $crate::Any |
241 | {} |
242 | |
243 | impl<_T> $crate::DowncastSync<_T> for $base |
244 | where _T: $crate::AnySync |
245 | {} |
246 | }; |
247 | } |
248 | |
249 | #[doc (hidden)] |
250 | #[macro_export ] |
251 | macro_rules! downcast_methods_core { |
252 | (@items) => { |
253 | #[allow(unused, missing_docs)] |
254 | pub fn is<_T>(&self) -> bool |
255 | where _T: $crate::Any, Self: $crate::Downcast<_T> |
256 | { |
257 | $crate::Downcast::<_T>::is_type(self) |
258 | } |
259 | |
260 | #[allow(unused, missing_docs)] |
261 | pub fn downcast_ref<_T>(&self) -> $crate::_std::result::Result<&_T, $crate::TypeMismatch> |
262 | where _T: $crate::Any, Self: $crate::Downcast<_T> |
263 | { |
264 | $crate::Downcast::<_T>::downcast_ref(self) |
265 | } |
266 | |
267 | #[allow(unused, missing_docs)] |
268 | pub fn downcast_mut<_T>(&mut self) -> $crate::_std::result::Result<&mut _T, $crate::TypeMismatch> |
269 | where _T: $crate::Any, Self: $crate::Downcast<_T> |
270 | { |
271 | $crate::Downcast::<_T>::downcast_mut(self) |
272 | } |
273 | }; |
274 | (<$($params:ident),+ $(,)*> $base:ty $(where $($bounds:tt)+)*) => { |
275 | impl<$($params),+> $base |
276 | where $($params: 'static,)* $($($bounds)+)* |
277 | { |
278 | $crate::downcast_methods_core!(@items); |
279 | } |
280 | }; |
281 | ($base:ty) => { |
282 | impl $base { |
283 | $crate::downcast_methods_core!(@items); |
284 | } |
285 | }; |
286 | } |
287 | |
288 | #[doc (hidden)] |
289 | #[macro_export ] |
290 | macro_rules! downcast_methods_std { |
291 | (@items) => { |
292 | $crate::downcast_methods_core!(@items); |
293 | |
294 | #[allow(unused, missing_docs)] |
295 | pub fn downcast<_T>(self: $crate::_std::boxed::Box<Self>) -> $crate::_std::result::Result<$crate::_std::boxed::Box<_T>, $crate::DowncastError<$crate::_std::boxed::Box<Self>>> |
296 | where _T: $crate::Any, Self: $crate::Downcast<_T> |
297 | { |
298 | $crate::Downcast::<_T>::downcast(self) |
299 | } |
300 | |
301 | #[allow(unused, missing_docs)] |
302 | pub fn downcast_rc<_T>(self: $crate::_std::rc::Rc<Self>) -> $crate::_std::result::Result<$crate::_std::rc::Rc<_T>, $crate::DowncastError<$crate::_std::rc::Rc<Self>>> |
303 | where _T: $crate::Any, Self: $crate::Downcast<_T> |
304 | { |
305 | $crate::Downcast::<_T>::downcast_rc(self) |
306 | } |
307 | }; |
308 | (<$($params:ident),+ $(,)*> $base:ty $(where $($bounds:tt)+)*) => { |
309 | impl<$($params),+> $base |
310 | $(where $($bounds)+)* |
311 | { |
312 | $crate::downcast_methods_std!(@items); |
313 | } |
314 | }; |
315 | ($base:ty) => { |
316 | impl $base { |
317 | $crate::downcast_methods_std!(@items); |
318 | } |
319 | }; |
320 | } |
321 | |
322 | #[doc (hidden)] |
323 | #[cfg (feature = "std" )] |
324 | #[macro_export ] |
325 | macro_rules! downcast_sync_methods { |
326 | (@items) => { |
327 | $crate::downcast_methods_std!(@items); |
328 | |
329 | #[allow(unused, missing_docs)] |
330 | pub fn downcast_arc<_T>(self: $crate::_std::sync::Arc<Self>) -> $crate::_std::result::Result<$crate::_std::sync::Arc<_T>, $crate::DowncastError<$crate::_std::sync::Arc<Self>>> |
331 | where _T: $crate::AnySync, Self: $crate::DowncastSync<_T> |
332 | { |
333 | $crate::DowncastSync::<_T>::downcast_arc(self) |
334 | } |
335 | }; |
336 | (<$($params:ident),+ $(,)*> $base:ty $(where $($bounds:tt)+)*) => { |
337 | impl<$($params),+> $base |
338 | $(where $($bounds)+)* |
339 | { |
340 | $crate::downcast_sync_methods!(@items); |
341 | } |
342 | }; |
343 | ($base:ty) => { |
344 | impl $base { |
345 | $crate::downcast_sync_methods!(@items); |
346 | } |
347 | }; |
348 | } |
349 | |
350 | |
351 | /// Generate `downcast`-methods for your trait-object-type. |
352 | /// |
353 | /// ```ignore |
354 | /// downcast_methods!(Foo); |
355 | /// downcast_methods!(<B> Foo<B> where B: Bar); |
356 | /// downcast_methods!(<B> Foo<Bar = B>); |
357 | /// ``` |
358 | /// |
359 | /// ```ignore |
360 | /// impl dyn Foo { |
361 | /// /* impl<B> dyn Foo<B> where B: Bar { */ |
362 | /// /* impl<B> dyn Foo<Bar = B> { */ |
363 | /// |
364 | /// pub fn is<T>(&self) -> bool |
365 | /// where T: Any, Self: Downcast<T> |
366 | /// { ... } |
367 | /// |
368 | /// pub fn downcast_ref<T>(&self) -> Result<&T, TypeMismatch> |
369 | /// where T: Any, Self: Downcast<T> |
370 | /// { ... } |
371 | /// |
372 | /// pub fn downcast_mut<T>(&mut self) -> Result<&mut T, TypeMismatch> |
373 | /// where T: Any, Self: Downcast<T> |
374 | /// { ... } |
375 | /// } |
376 | /// ``` |
377 | #[cfg (not(feature = "std" ))] |
378 | #[macro_export ] |
379 | macro_rules! downcast_methods { |
380 | ($($tt:tt)+) => { $crate::downcast_methods_core!($($tt)+); } |
381 | } |
382 | |
383 | /// Generate `downcast`-methods for your trait-object-type. |
384 | /// |
385 | /// ```ignore |
386 | /// downcast_methods!(Foo); |
387 | /// downcast_methods!(<B> Foo<B> where B: Bar); |
388 | /// downcast_methods!(<B> Foo<Bar = B>); |
389 | /// ``` |
390 | /// |
391 | /// ```ignore |
392 | /// impl dyn Foo { |
393 | /// /* impl<B> dyn Foo<B> where B: Bar { */ |
394 | /// /* impl<B> dyn Foo<Bar = B> { */ |
395 | /// |
396 | /// pub fn is<T>(&self) -> bool |
397 | /// where T: Any, Self: Downcast<T> |
398 | /// { ... } |
399 | /// |
400 | /// pub fn downcast_ref<T>(&self) -> Result<&T, TypeMismatch> |
401 | /// where T: Any, Self: Downcast<T> |
402 | /// { ... } |
403 | /// |
404 | /// pub fn downcast_mut<T>(&mut self) -> Result<&mut T, TypeMismatch> |
405 | /// where T: Any, Self: Downcast<T> |
406 | /// { ... } |
407 | /// |
408 | /// pub fn downcast<T>(self: Box<Self>) -> Result<Box<T>, DowncastError<Box<T>>> |
409 | /// where T: Any, Self: Downcast<T> |
410 | /// { ... } |
411 | /// } |
412 | /// ``` |
413 | #[cfg (feature = "std" )] |
414 | #[macro_export ] |
415 | macro_rules! downcast_methods { |
416 | ($($tt:tt)+) => { $crate::downcast_methods_std!($($tt)+); } |
417 | } |
418 | |
419 | /// Implements [`Downcast`](trait.Downcast.html) and generates |
420 | /// `downcast`-methods for your trait-object-type. |
421 | /// |
422 | /// See [`impl_downcast`](macro.impl_downcast.html), |
423 | /// [`downcast_methods`](macro.downcast_methods.html). |
424 | #[macro_export ] |
425 | macro_rules! downcast { |
426 | ($($tt:tt)+) => { |
427 | $crate::impl_downcast!($($tt)+); |
428 | $crate::downcast_methods!($($tt)+); |
429 | } |
430 | } |
431 | |
432 | /// Implements [`DowncastSync`](trait.DowncastSync.html) and generates |
433 | /// `downcast`-methods for your trait-object-type. |
434 | /// |
435 | /// See [`impl_downcast_sync`](macro.impl_downcast.html), |
436 | /// [`downcast_sync_methods`](macro.downcast_methods.html). |
437 | #[cfg (feature = "std" )] |
438 | #[macro_export ] |
439 | macro_rules! downcast_sync { |
440 | ($($tt:tt)+) => { |
441 | $crate::impl_downcast_sync!($($tt)+); |
442 | $crate::downcast_sync_methods!($($tt)+); |
443 | } |
444 | } |
445 | |
446 | // NOTE: We only implement the trait, because implementing the methods won't |
447 | // be possible when we replace downcast::Any by std::any::Any. |
448 | downcast!(dyn Any); |
449 | downcast!((dyn Any + Send)); |
450 | downcast!((dyn Any + Sync)); |
451 | #[cfg (feature = "std" )] |
452 | downcast_sync!(dyn AnySync); |
453 | |
454 | |