use std::any::Any; // NOTE: This is `pub`, but isn't actually exposed outside the crate. // NOTE: Marked as `#[doc(hidden)]` and underscored, because they can be quite difficult to use // correctly, see discussion in #4160. // FIXME: Remove and replace with a coercion once rust-lang/rust#65991 is in MSRV (1.86). #[doc(hidden)] pub trait AsAny: Any { #[doc(hidden)] fn __as_any(&self) -> &dyn Any; #[doc(hidden)] fn __as_any_mut(&mut self) -> &mut dyn Any; #[doc(hidden)] fn __into_any(self: Box) -> Box; } impl AsAny for T { #[inline(always)] fn __as_any(&self) -> &dyn Any { self } #[inline(always)] fn __as_any_mut(&mut self) -> &mut dyn Any { self } #[inline(always)] fn __into_any(self: Box) -> Box { self } } #[macro_export] macro_rules! impl_dyn_casting { ($trait:ident) => { impl dyn $trait + '_ { /// Downcast to the backend concrete type. /// /// Returns `None` if the object was not from that backend. pub fn cast_ref(&self) -> Option<&T> { let this: &dyn std::any::Any = self.__as_any(); this.downcast_ref::() } /// Mutable downcast to the backend concrete type. /// /// Returns `None` if the object was not from that backend. pub fn cast_mut(&mut self) -> Option<&mut T> { let this: &mut dyn std::any::Any = self.__as_any_mut(); this.downcast_mut::() } /// Owned downcast to the backend concrete type. /// /// Returns `Err` with `self` if the object was not from that backend. pub fn cast(self: Box) -> Result, Box> { let reference: &dyn std::any::Any = self.__as_any(); if reference.is::() { let this: Box = self.__into_any(); // Unwrap is okay, we just checked the type of `self` is `T`. Ok(this.downcast::().unwrap()) } else { Err(self) } } } }; } pub use impl_dyn_casting;