pub use std::any::Any;
use std::marker::PhantomData;
use std::ops::{Deref, DerefMut};
use std::sync::{Arc, RwLock, RwLockReadGuard, RwLockWriteGuard};
pub struct AnyHandle<T: ?Sized>(Arc<RwLock<Box<dyn Any>>>, PhantomData<T>);
impl AnyHandle<dyn Any> {
pub fn new(inner: Box<dyn Any>) -> Self {
Self(Arc::new(RwLock::new(inner)), PhantomData)
}
pub fn downcast<Y: 'static>(self) -> Result<AnyHandle<Y>, Self> {
if self.0.read().unwrap().is::<Y>() {
Ok(AnyHandle::<Y>(self.0, PhantomData))
} else {
Err(self)
}
}
}
impl<T: ?Sized> AnyHandle<T> {
#[inline(always)]
pub fn read(&self) -> AnyHandleReadGuard<'_, T> {
AnyHandleReadGuard(self.0.read().unwrap(), PhantomData)
}
#[inline(always)]
pub fn write(&mut self) -> AnyHandleWriteGuard<'_, T> {
AnyHandleWriteGuard(self.0.write().unwrap(), PhantomData)
}
#[inline(always)]
pub fn reference_count(&self) -> usize {
Arc::strong_count(&self.0)
}
}
impl<T: Sized + 'static> From<AnyHandle<dyn Any>> for Option<AnyHandle<T>> {
fn from(item: AnyHandle<dyn Any>) -> Option<AnyHandle<T>> {
item.downcast().ok()
}
}
impl<T: ?Sized> Clone for AnyHandle<T> {
#[inline(always)]
fn clone(&self) -> Self {
Self(self.0.clone(), PhantomData)
}
}
pub struct AnyHandleReadGuard<'a, T: ?Sized + 'a>(RwLockReadGuard<'a, Box<dyn Any>>, PhantomData<T>);
pub struct AnyHandleWriteGuard<'a, T: ?Sized + 'a>(RwLockWriteGuard<'a, Box<dyn Any>>, PhantomData<T>);
macro_rules! impl_deref {
($Type:ident) => {
#[doc = "Deref a handle, immutably."]
impl<'a, T: 'a + 'static> Deref for $Type<'a, T> {
type Target = T;
#[inline(always)]
fn deref(&self) -> &Self::Target {
unsafe { &*(self.0.deref().deref() as *const dyn Any as *const T) }
}
}
}
}
impl_deref!(AnyHandleWriteGuard);
impl_deref!(AnyHandleReadGuard);
impl<'a, T: 'a + 'static> DerefMut for AnyHandleWriteGuard<'a, T> {
#[inline(always)]
fn deref_mut(&mut self) -> &mut T {
unsafe { &mut *(self.0.deref_mut().deref_mut() as *mut dyn Any as *mut T) }
}
}
#[cfg(test)]
mod tests {
use super::*;
struct SomeStruct { value: i32 }
#[test]
fn basic_reading_writing() {
let handle : AnyHandle<dyn Any> = AnyHandle::new(Box::new(SomeStruct {
value: 12
}));
let handle : Option<AnyHandle<SomeStruct>> = handle.into();
let mut handle = handle.unwrap();
{
let handle_two = handle.clone();
assert_eq!(handle.read().value, 12);
assert_eq!(handle_two.read().value, 12);
assert_eq!(handle.reference_count(), 2);
handle.write().value = 24;
assert_eq!(handle.read().value, 24);
assert_eq!(handle_two.read().value, 24);
}
assert_eq!(handle.reference_count(), 1);
}
#[test]
fn type_safety() {
let handle = AnyHandle::new(Box::new(SomeStruct { value: 12 }));
Into::<Option<AnyHandle<SomeStruct>>>::into(handle).unwrap();
}
}