use std::any::Any;
use std::fmt::Debug;
use std::marker::PhantomData;
use std::ptr::NonNull;
pub trait BlockMeta: Any + Send + Sync + Debug {}
impl dyn BlockMeta {
#[must_use]
pub fn is<T: Any>(&self) -> bool {
<dyn Any>::is::<T>(self)
}
#[must_use]
pub fn downcast_ref<T: Any>(&self) -> Option<&T> {
<dyn Any>::downcast_ref::<T>(self)
}
}
#[derive(Debug)]
pub struct BlockRef {
state: OpaqueStatePtr,
vtable: &'static BlockRefVTableInner,
}
impl BlockRef {
#[must_use]
pub const unsafe fn new<T: BlockRefDynamic>(state: NonNull<T::State>, vtable: &'static BlockRefVTable<T>) -> Self {
Self {
state: state.cast(),
vtable: &vtable.inner,
}
}
#[must_use]
pub fn meta(&self) -> Option<&dyn BlockMeta> {
self.vtable.meta.map(|f| {
let meta_ptr = unsafe { f(self.state) };
unsafe { meta_ptr.as_ref() }
})
}
}
impl Clone for BlockRef {
fn clone(&self) -> Self {
let new_data = unsafe { (self.vtable.clone)(self.state) };
Self {
state: new_data,
vtable: self.vtable,
}
}
}
impl Drop for BlockRef {
fn drop(&mut self) {
unsafe { (self.vtable.drop)(self.state) }
}
}
type OpaqueStatePtr = NonNull<()>;
type CloneFn = unsafe fn(state: OpaqueStatePtr) -> OpaqueStatePtr;
type DropFn = unsafe fn(state: OpaqueStatePtr);
type MetaFn = unsafe fn(state: OpaqueStatePtr) -> NonNull<dyn BlockMeta>;
unsafe impl Send for BlockRef {}
unsafe impl Sync for BlockRef {}
#[derive(Debug)]
struct BlockRefVTableInner {
clone: CloneFn,
drop: DropFn,
meta: Option<MetaFn>,
}
#[derive(Debug)]
pub struct BlockRefVTable<T> {
inner: BlockRefVTableInner,
_t: PhantomData<T>,
}
impl<T: BlockRefDynamicWithMeta> BlockRefVTable<T> {
#[expect(missing_docs, reason = "TODO")]
#[must_use]
pub const fn from_trait_with_meta() -> Self {
Self {
inner: BlockRefVTableInner {
clone: wrap_clone::<T>,
drop: wrap_drop::<T>,
meta: Some(wrap_meta::<T>),
},
_t: PhantomData,
}
}
}
impl<T: BlockRefDynamic> BlockRefVTable<T> {
#[expect(missing_docs, reason = "TODO")]
#[must_use]
pub const fn from_trait() -> Self {
Self {
inner: BlockRefVTableInner {
clone: wrap_clone::<T>,
drop: wrap_drop::<T>,
meta: None,
},
_t: PhantomData,
}
}
}
#[cfg_attr(test, mutants::skip)] fn wrap_clone<T: BlockRefDynamic>(state_ptr: OpaqueStatePtr) -> OpaqueStatePtr {
T::clone(state_ptr.cast()).cast()
}
#[cfg_attr(test, mutants::skip)] fn wrap_drop<T: BlockRefDynamic>(state_ptr: OpaqueStatePtr) {
T::drop(state_ptr.cast());
}
fn wrap_meta<T: BlockRefDynamicWithMeta>(state_ptr: OpaqueStatePtr) -> NonNull<dyn BlockMeta> {
T::meta(state_ptr.cast())
}
pub unsafe trait BlockRefDynamic {
type State;
fn clone(state_ptr: NonNull<Self::State>) -> NonNull<Self::State>;
fn drop(state_ptr: NonNull<Self::State>);
}
pub unsafe trait BlockRefDynamicWithMeta: BlockRefDynamic {
fn meta(state_ptr: NonNull<Self::State>) -> NonNull<dyn BlockMeta>;
}
#[cfg_attr(coverage_nightly, coverage(off))]
#[cfg(test)]
mod tests {
use std::sync::atomic::{self, AtomicUsize};
use super::*;
struct TestBlock {
ref_count: AtomicUsize,
meta: Option<NonNull<dyn BlockMeta>>,
}
#[derive(Debug)]
struct TestBlockMeta {
label: String,
}
impl BlockMeta for TestBlockMeta {}
unsafe impl BlockRefDynamic for TestBlock {
type State = Self;
fn clone(state_ptr: NonNull<Self::State>) -> NonNull<Self::State> {
let state = unsafe { state_ptr.as_ref() };
state.ref_count.fetch_add(1, atomic::Ordering::Relaxed);
state_ptr
}
fn drop(state_ptr: NonNull<Self::State>) {
let state = unsafe { state_ptr.as_ref() };
state.ref_count.fetch_sub(1, atomic::Ordering::Release);
}
}
unsafe impl BlockRefDynamicWithMeta for TestBlock {
fn meta(state_ptr: NonNull<Self::State>) -> NonNull<dyn BlockMeta> {
let state = unsafe { state_ptr.as_ref() };
state.meta.unwrap()
}
}
const TEST_BLOCK_REF_FNS: BlockRefVTable<TestBlock> = BlockRefVTable::from_trait_with_meta();
const TEST_BLOCK_REF_FNS_WITHOUT_META: BlockRefVTable<TestBlock> = BlockRefVTable::from_trait();
#[test]
fn smoke_test() {
let meta_ptr = NonNull::new(Box::into_raw(Box::new(TestBlockMeta {
label: "Test Block".to_string(),
})))
.unwrap();
let block_ptr = NonNull::new(Box::into_raw(Box::new(TestBlock {
ref_count: AtomicUsize::new(1),
meta: Some(meta_ptr),
})))
.unwrap();
let block_ref = unsafe { BlockRef::new(block_ptr, &TEST_BLOCK_REF_FNS) };
let meta = block_ref.meta().unwrap();
assert_eq!(meta.downcast_ref::<TestBlockMeta>().unwrap().label, "Test Block");
let block_ref_clone = block_ref.clone();
let meta = block_ref_clone.meta().unwrap();
assert_eq!(meta.downcast_ref::<TestBlockMeta>().unwrap().label, "Test Block");
let ref_count = unsafe { block_ptr.as_ref() }.ref_count.load(atomic::Ordering::Relaxed);
assert_eq!(2, ref_count);
drop(block_ref_clone);
drop(block_ref);
let ref_count = unsafe { block_ptr.as_ref() }.ref_count.load(atomic::Ordering::Relaxed);
assert_eq!(0, ref_count);
drop(unsafe { Box::from_raw(block_ptr.as_ptr()) });
drop(unsafe { Box::from_raw(meta_ptr.as_ptr()) });
}
#[test]
fn without_meta_returns_none_meta() {
let block_ptr = NonNull::new(Box::into_raw(Box::new(TestBlock {
ref_count: AtomicUsize::new(1),
meta: None,
})))
.unwrap();
let block_ref = unsafe { BlockRef::new(block_ptr, &TEST_BLOCK_REF_FNS_WITHOUT_META) };
assert!(block_ref.meta().is_none());
let block_ref_clone = block_ref.clone();
assert!(block_ref_clone.meta().is_none());
drop(block_ref_clone);
drop(block_ref);
drop(unsafe { Box::from_raw(block_ptr.as_ptr()) });
}
#[test]
#[cfg_attr(miri, ignore)]
fn from_trait_with_meta_creates_vtable_with_meta_fn() {
let vtable: &'static BlockRefVTable<TestBlock> = Box::leak(Box::new(BlockRefVTable::from_trait_with_meta()));
assert!(vtable.inner.meta.is_some());
let meta_ptr = NonNull::new(Box::into_raw(Box::new(TestBlockMeta {
label: "Test Metadata".to_string(),
})))
.unwrap();
let block_ptr = NonNull::new(Box::into_raw(Box::new(TestBlock {
ref_count: AtomicUsize::new(1),
meta: Some(meta_ptr),
})))
.unwrap();
let block_ref = unsafe { BlockRef::new(block_ptr, vtable) };
let meta = block_ref.meta().expect("Meta should be available");
assert_eq!(meta.downcast_ref::<TestBlockMeta>().unwrap().label, "Test Metadata");
drop(block_ref);
drop(unsafe { Box::from_raw(block_ptr.as_ptr()) });
drop(unsafe { Box::from_raw(meta_ptr.as_ptr()) });
}
#[test]
#[cfg_attr(miri, ignore)]
fn from_trait_creates_vtable_without_meta_fn() {
let vtable: &'static BlockRefVTable<TestBlock> = Box::leak(Box::new(BlockRefVTable::from_trait()));
assert!(vtable.inner.meta.is_none());
let block_ptr = NonNull::new(Box::into_raw(Box::new(TestBlock {
ref_count: AtomicUsize::new(1),
meta: None,
})))
.unwrap();
let block_ref = unsafe { BlockRef::new(block_ptr, vtable) };
assert!(block_ref.meta().is_none());
drop(block_ref);
drop(unsafe { Box::from_raw(block_ptr.as_ptr()) });
}
#[test]
#[cfg_attr(miri, ignore)]
fn from_trait_with_meta_vtable_handles_clone_correctly() {
let vtable: &'static BlockRefVTable<TestBlock> = Box::leak(Box::new(BlockRefVTable::from_trait_with_meta()));
let block_ptr = NonNull::new(Box::into_raw(Box::new(TestBlock {
ref_count: AtomicUsize::new(1),
meta: None,
})))
.unwrap();
let block_ref = unsafe { BlockRef::new(block_ptr, vtable) };
let block_ref_clone = block_ref.clone();
let ref_count = unsafe { block_ptr.as_ref() }.ref_count.load(atomic::Ordering::Relaxed);
assert_eq!(ref_count, 2);
drop(block_ref_clone);
drop(block_ref);
let ref_count = unsafe { block_ptr.as_ref() }.ref_count.load(atomic::Ordering::Relaxed);
assert_eq!(ref_count, 0);
drop(unsafe { Box::from_raw(block_ptr.as_ptr()) });
}
#[test]
#[cfg_attr(miri, ignore)]
fn from_trait_vtable_handles_clone_correctly() {
let vtable: &'static BlockRefVTable<TestBlock> = Box::leak(Box::new(BlockRefVTable::from_trait()));
let block_ptr = NonNull::new(Box::into_raw(Box::new(TestBlock {
ref_count: AtomicUsize::new(1),
meta: None,
})))
.unwrap();
let block_ref = unsafe { BlockRef::new(block_ptr, vtable) };
let block_ref_clone = block_ref.clone();
let ref_count = unsafe { block_ptr.as_ref() }.ref_count.load(atomic::Ordering::Relaxed);
assert_eq!(ref_count, 2);
drop(block_ref_clone);
drop(block_ref);
let ref_count = unsafe { block_ptr.as_ref() }.ref_count.load(atomic::Ordering::Relaxed);
assert_eq!(ref_count, 0);
drop(unsafe { Box::from_raw(block_ptr.as_ptr()) });
}
}