#[cfg(not(feature = "std"))]
use alloc::boxed::Box;
use core::any::{Any, TypeId};
use core::fmt;
#[doc(hidden)]
pub trait CloneToAny {
fn clone_to_any(&self) -> Box<dyn CloneAny>;
}
impl<T: Any + Clone> CloneToAny for T {
#[inline]
fn clone_to_any(&self) -> Box<dyn CloneAny> {
Box::new(self.clone())
}
}
macro_rules! impl_clone {
($t:ty) => {
impl Clone for Box<$t> {
#[inline]
fn clone(&self) -> Box<$t> {
let clone: Box<dyn CloneAny> = (**self).clone_to_any();
let raw: *mut dyn CloneAny = Box::into_raw(clone);
unsafe { Box::from_raw(std::mem::transmute::<*mut dyn CloneAny, *mut _>(raw)) }
}
}
impl fmt::Debug for $t {
#[inline]
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.pad(stringify!($t))
}
}
};
}
pub trait Downcast {
fn type_id(&self) -> TypeId;
unsafe fn downcast_ref_unchecked<T: 'static>(&self) -> &T;
unsafe fn downcast_mut_unchecked<T: 'static>(&mut self) -> &mut T;
unsafe fn downcast_unchecked<T: 'static>(self: Box<Self>) -> Box<T>;
}
pub trait IntoBox<A: ?Sized + Downcast>: Any {
fn into_box(self) -> Box<A>;
}
macro_rules! implement {
($any_trait:ident $(+ $auto_traits:ident)*) => {
impl Downcast for dyn $any_trait $(+ $auto_traits)* {
#[inline]
fn type_id(&self) -> TypeId {
self.type_id()
}
#[inline]
unsafe fn downcast_ref_unchecked<T: 'static>(&self) -> &T {
&*(self as *const Self as *const T)
}
#[inline]
unsafe fn downcast_mut_unchecked<T: 'static>(&mut self) -> &mut T {
&mut *(self as *mut Self as *mut T)
}
#[inline]
unsafe fn downcast_unchecked<T: 'static>(self: Box<Self>) -> Box<T> {
Box::from_raw(Box::into_raw(self) as *mut T)
}
}
impl<T: $any_trait $(+ $auto_traits)*> IntoBox<dyn $any_trait $(+ $auto_traits)*> for T {
#[inline]
fn into_box(self) -> Box<dyn $any_trait $(+ $auto_traits)*> {
Box::new(self)
}
}
}
}
implement!(Any);
implement!(Any + Send);
implement!(Any + Send + Sync);
pub trait CloneAny: Any + CloneToAny {}
impl<T: Any + Clone> CloneAny for T {}
implement!(CloneAny);
implement!(CloneAny + Send);
implement!(CloneAny + Send + Sync);
impl_clone!(dyn CloneAny);
impl_clone!(dyn CloneAny + Send);
impl_clone!(dyn CloneAny + Send + Sync);