#![deny(missing_docs, warnings)]
extern crate destructure_traitobject;
use std::any::Any;
use std::mem;
pub trait UnsafeAny: Any {}
impl<T: Any> UnsafeAny for T {}
impl dyn UnsafeAny {
pub unsafe fn downcast_ref_unchecked<T: Any>(&self) -> &T {
&*(destructure_traitobject::data(self) as *const T)
}
pub unsafe fn downcast_mut_unchecked<T: Any>(&mut self) -> &mut T {
&mut *(destructure_traitobject::data_mut(self) as *mut T)
}
pub unsafe fn downcast_unchecked<T: Any>(self: Box<dyn UnsafeAny>) -> Box<T> {
let raw: *mut dyn UnsafeAny = mem::transmute(self);
mem::transmute(destructure_traitobject::data_mut(raw))
}
}
pub unsafe trait UnsafeAnyExt {
unsafe fn downcast_ref_unchecked<T: Any>(&self) -> &T {
&*(destructure_traitobject::data(self) as *const T)
}
unsafe fn downcast_mut_unchecked<T: Any>(&mut self) -> &mut T {
&mut *(destructure_traitobject::data_mut(self) as *mut T)
}
unsafe fn downcast_unchecked<T: Any>(self: Box<Self>) -> Box<T> {
let raw: *mut Self = mem::transmute(self);
mem::transmute(destructure_traitobject::data_mut(raw))
}
}
unsafe impl UnsafeAnyExt for dyn Any {}
unsafe impl UnsafeAnyExt for dyn UnsafeAny {}
unsafe impl UnsafeAnyExt for dyn Any + Send {}
unsafe impl UnsafeAnyExt for dyn Any + Sync {}
unsafe impl UnsafeAnyExt for dyn Any + Send + Sync {}
unsafe impl UnsafeAnyExt for dyn UnsafeAny + Send {}
unsafe impl UnsafeAnyExt for dyn UnsafeAny + Sync {}
unsafe impl UnsafeAnyExt for dyn UnsafeAny + Send + Sync {}
#[cfg(test)]
mod test {
use super::{UnsafeAny, UnsafeAnyExt};
use std::any::Any;
#[allow(unstable_name_collisions)]
#[test]
fn test_simple_downcast_ext() {
let a = Box::new(7usize) as Box<dyn Any>;
unsafe {
assert_eq!(*a.downcast_ref_unchecked::<usize>(), 7);
}
let mut a = Box::new(7usize) as Box<dyn Any>;
unsafe {
assert_eq!(*a.downcast_mut_unchecked::<usize>(), 7);
}
let mut a = Box::new(7usize) as Box<dyn Any>;
unsafe {
*a.downcast_mut_unchecked::<usize>() = 8;
assert_eq!(*a.downcast_mut_unchecked::<usize>(), 8);
}
}
#[allow(unstable_name_collisions)]
#[test]
fn test_simple_downcast_inherent() {
let a = Box::new(7usize) as Box<dyn UnsafeAny>;
unsafe {
assert_eq!(*a.downcast_ref_unchecked::<usize>(), 7);
}
let mut a = Box::new(7usize) as Box<dyn UnsafeAny>;
unsafe {
assert_eq!(*a.downcast_mut_unchecked::<usize>(), 7);
}
let mut a = Box::new(7usize) as Box<dyn UnsafeAny>;
unsafe {
*a.downcast_mut_unchecked::<usize>() = 8;
assert_eq!(*a.downcast_mut_unchecked::<usize>(), 8);
}
}
#[allow(unstable_name_collisions)]
#[test]
fn test_box_downcast_no_double_free() {
use std::sync::atomic::{AtomicUsize, Ordering};
use std::sync::Arc;
struct Dropper {
x: Arc<AtomicUsize>,
}
impl Drop for Dropper {
fn drop(&mut self) {
self.x.fetch_add(1, Ordering::SeqCst);
}
}
let x = Arc::new(AtomicUsize::new(0));
let a = Box::new(Dropper { x: x.clone() }) as Box<dyn UnsafeAny>;
let dropper = unsafe { a.downcast_unchecked::<Dropper>() };
drop(dropper);
assert_eq!(x.load(Ordering::SeqCst), 1);
let x = Arc::new(AtomicUsize::new(0));
let a = Box::new(Dropper { x: x.clone() }) as Box<dyn Any>;
let dropper = unsafe { a.downcast_unchecked::<Dropper>() };
drop(dropper);
assert_eq!(x.load(Ordering::SeqCst), 1);
}
}