use crate::runtime::meta::TypeMeta;
use std::mem;
use std::ptr;
use std::ptr::null;
use std::sync::Arc;
#[derive(Debug)]
pub struct ErasedArc {
type_id: TypeMeta,
data: [*const (); 2],
dec_fn: unsafe fn([*const (); 2]),
inc_fn: unsafe fn([*const (); 2]),
}
unsafe impl Send for ErasedArc {}
unsafe impl Sync for ErasedArc {}
impl ErasedArc {
pub fn from_instance<T>(instance: T) -> Self
where
T: Send + Sync + 'static,
{
Self::from(Arc::new(instance))
}
pub fn from<T>(instance: Arc<T>) -> Self
where
T: ?Sized + Send + Sync + 'static,
{
Self {
type_id: TypeMeta::of::<T>(),
data: unsafe {
let raw = Arc::into_raw(instance);
let mut data = [null(); 2];
ptr::copy_nonoverlapping(
&raw as *const _ as *const u8, data.as_mut_ptr() as *mut u8,
size_of_val(&raw),
);
data
},
dec_fn: |x| unsafe {
let ptr = Self::cast_ptr::<T>(&x);
Arc::decrement_strong_count(ptr);
},
inc_fn: |x| unsafe {
let ptr = Self::cast_ptr::<T>(&x);
Arc::increment_strong_count(ptr);
},
}
}
pub fn ty(&self) -> TypeMeta {
self.type_id
}
pub fn coerce<T>(&self) -> Option<Arc<T>>
where
T: ?Sized + Send + Sync + 'static,
{
if self.type_id == TypeMeta::of::<T>() {
let coerced = unsafe {
let ptr = Self::cast_ptr::<T>(&self.data);
Arc::increment_strong_count(ptr);
Arc::from_raw(ptr)
};
Some(coerced)
} else {
None
}
}
pub fn as_ptr(arc: &Self) -> *const () {
unsafe { Self::cast_ptr(&arc.data) }
}
unsafe fn cast_ptr<T: ?Sized>(from: &[*const (); 2]) -> *const T {
unsafe { mem::transmute_copy(from) }
}
}
impl Clone for ErasedArc {
fn clone(&self) -> Self {
unsafe {
(self.inc_fn)(self.data);
}
Self {
type_id: self.type_id,
data: self.data,
dec_fn: self.dec_fn,
inc_fn: self.inc_fn,
}
}
}
impl Drop for ErasedArc {
fn drop(&mut self) {
unsafe {
(self.dec_fn)(self.data);
}
}
}
#[cfg(test)]
mod tests {
use super::*;
use std::sync::Arc;
#[test]
fn test_coercion() {
let erased = ErasedArc::from_instance(42);
let coerced = erased.coerce::<i32>().unwrap();
assert_eq!(*coerced, 42);
}
#[test]
fn test_unsized() {
trait MyTrait {
fn get(&self) -> i32;
}
impl MyTrait for i32 {
fn get(&self) -> i32 {
*self
}
}
let arc: Arc<dyn MyTrait + Send + Sync> = Arc::new(100);
let erased = ErasedArc::from(arc);
let coerced = erased.coerce::<dyn MyTrait + Send + Sync>().unwrap();
assert_eq!(coerced.get(), 100);
}
#[test]
fn test_clone() {
let arc = Arc::new(10);
let erased = ErasedArc::from(arc.clone());
assert_eq!(Arc::strong_count(&arc), 2);
{
let _cloned = erased.clone();
assert_eq!(Arc::strong_count(&arc), 3);
}
assert_eq!(Arc::strong_count(&arc), 2);
}
}