1#[macro_export]
2macro_rules! impl_dyn_casting {
3 ($trait:ident) => {
4 impl dyn $trait + '_ {
5 pub fn cast_ref<T: $trait>(&self) -> Option<&T> {
9 let this: &dyn std::any::Any = self;
10 this.downcast_ref::<T>()
11 }
12
13 pub fn cast_mut<T: $trait>(&mut self) -> Option<&mut T> {
17 let this: &mut dyn std::any::Any = self;
18 this.downcast_mut::<T>()
19 }
20
21 pub fn cast<T: $trait>(self: Box<Self>) -> Result<Box<T>, Box<Self>> {
25 if self.cast_ref::<T>().is_some() {
26 let this: Box<dyn std::any::Any> = self;
27 Ok(this.downcast::<T>().unwrap())
29 } else {
30 Err(self)
31 }
32 }
33 }
34 };
35}
36
37pub use impl_dyn_casting;
38
39#[cfg(test)]
40mod tests {
41 use std::any::Any;
42
43 struct Foo;
44 trait FooTrait: Any {}
45 impl FooTrait for Foo {}
46 impl_dyn_casting!(FooTrait);
47
48 #[test]
49 fn dyn_casting() {
50 let foo_owned: Box<dyn FooTrait> = Box::new(Foo);
51 assert!(foo_owned.cast::<Foo>().is_ok());
52
53 let mut foo = Foo;
54 let foo_ref: &mut dyn FooTrait = &mut foo;
55 assert!(foo_ref.cast_ref::<Foo>().is_some());
56 let nested_ref: &&&&&mut dyn FooTrait = &&&&foo_ref;
57 assert!(nested_ref.cast_ref::<Foo>().is_some());
58 assert!(foo_ref.cast_mut::<Foo>().is_some());
59 }
60}