use alloc::boxed::Box;
use alloc::vec::Vec;
use core::any::TypeId;
#[derive(Default)]
pub struct Buffer {
pub(crate) registry: Registry,
pub(crate) out: Vec<u8>, }
impl Buffer {
pub fn new() -> Self {
Self::default()
}
}
#[derive(Default)]
pub(crate) struct Registry(Vec<(TypeId, ErasedBox)>);
impl Registry {
#[cfg(test)]
pub(crate) fn get<T: Default + Send + Sync + 'static>(&mut self) -> &mut T {
unsafe { self.get_non_static::<T>() }
}
pub(crate) unsafe fn get_non_static<T: Default + Send + Sync>(&mut self) -> &mut T {
#[inline(never)]
fn inner(me: &mut Registry, type_id: TypeId, create: fn() -> ErasedBox) -> *mut () {
match me.0.binary_search_by_key(&type_id, |(k, _)| *k) {
Ok(i) => me.0[i].1.ptr,
Err(i) => {
#[cold]
#[inline(never)]
fn cold(
me: &mut Registry,
i: usize,
type_id: TypeId,
create: fn() -> ErasedBox,
) -> *mut () {
me.0.insert(i, (type_id, create()));
me.0[i].1.ptr
}
cold(me, i, type_id, create)
}
}
}
let erased_ptr = inner(self, non_static_type_id::<T>(), || {
ErasedBox::new(T::default())
});
&mut *(erased_ptr as *mut T)
}
}
fn non_static_type_id<T: ?Sized>() -> TypeId {
use core::marker::PhantomData;
trait NonStaticAny {
fn get_type_id(&self) -> TypeId
where
Self: 'static;
}
impl<T: ?Sized> NonStaticAny for PhantomData<T> {
fn get_type_id(&self) -> TypeId
where
Self: 'static,
{
TypeId::of::<T>()
}
}
let phantom_data = PhantomData::<T>;
NonStaticAny::get_type_id(unsafe {
core::mem::transmute::<&dyn NonStaticAny, &(dyn NonStaticAny + 'static)>(&phantom_data)
})
}
struct ErasedBox {
ptr: *mut (), drop: unsafe fn(*mut ()), }
unsafe impl Send for ErasedBox {}
unsafe impl Sync for ErasedBox {}
impl ErasedBox {
unsafe fn new<T: Send + Sync>(t: T) -> Self {
let ptr = Box::into_raw(Box::new(t)) as *mut ();
let drop: unsafe fn(*mut ()) = core::mem::transmute(drop::<Box<T>> as fn(Box<T>));
Self { ptr, drop }
}
}
impl Drop for ErasedBox {
fn drop(&mut self) {
unsafe { (self.drop)(self.ptr) };
}
}
#[cfg(test)]
mod tests {
use super::{non_static_type_id, Buffer, ErasedBox, Registry};
use test::{black_box, Bencher};
#[test]
fn buffer() {
let mut b = Buffer::new();
assert_eq!(b.encode(&false), &[0]);
assert_eq!(b.encode(&true), &[1]);
assert_eq!(b.decode::<bool>(&[0]).unwrap(), false);
assert_eq!(b.decode::<bool>(&[1]).unwrap(), true);
fn assert_send_sync<T: Send + Sync>() {}
assert_send_sync::<Buffer>()
}
#[test]
fn registry() {
let mut r = Registry::default();
assert_eq!(*r.get::<u8>(), 0);
*r.get::<u8>() = 1;
assert_eq!(*r.get::<u8>(), 1);
assert_eq!(*r.get::<u16>(), 0);
*r.get::<u16>() = 5;
assert_eq!(*r.get::<u16>(), 5);
assert_eq!(*r.get::<u8>(), 1);
}
#[test]
fn type_id() {
assert_ne!(non_static_type_id::<u8>(), non_static_type_id::<i8>());
assert_ne!(non_static_type_id::<()>(), non_static_type_id::<[(); 1]>());
assert_ne!(
non_static_type_id::<&'static mut [u8]>(),
non_static_type_id::<&'static [u8]>()
);
assert_ne!(
non_static_type_id::<*mut u8>(),
non_static_type_id::<*const u8>()
);
fn f<'a>(_: &'a ()) {
assert_eq!(
non_static_type_id::<&'static [u8]>(),
non_static_type_id::<&'a [u8]>()
);
assert_eq!(
non_static_type_id::<&'static ()>(),
non_static_type_id::<&'a ()>()
);
}
f(&());
}
#[test]
fn erased_box() {
use alloc::sync::Arc;
let rc = Arc::new(());
struct TestDrop(#[allow(unused)] Arc<()>);
let b = unsafe { ErasedBox::new(TestDrop(Arc::clone(&rc))) };
assert_eq!(Arc::strong_count(&rc), 2);
drop(b);
assert_eq!(Arc::strong_count(&rc), 1);
}
macro_rules! register10 {
($registry:ident $(, $t:literal)*) => {
$(
$registry.get::<[u8; $t]>();
$registry.get::<[i8; $t]>();
$registry.get::<[u16; $t]>();
$registry.get::<[i16; $t]>();
$registry.get::<[u32; $t]>();
$registry.get::<[i32; $t]>();
$registry.get::<[u64; $t]>();
$registry.get::<[i64; $t]>();
$registry.get::<[u128; $t]>();
$registry.get::<[i128; $t]>();
)*
}
}
type T = [u8; 1];
#[bench]
fn bench_registry1_get(b: &mut Bencher) {
let mut r = Registry::default();
r.get::<T>();
assert_eq!(r.0.len(), 1);
b.iter(|| {
black_box(*black_box(&mut r).get::<T>());
})
}
#[bench]
fn bench_registry10_get(b: &mut Bencher) {
let mut r = Registry::default();
r.get::<T>();
register10!(r, 1);
assert_eq!(r.0.len(), 10);
b.iter(|| {
black_box(*black_box(&mut r).get::<T>());
})
}
#[bench]
fn bench_registry100_get(b: &mut Bencher) {
let mut r = Registry::default();
r.get::<T>();
register10!(r, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
assert_eq!(r.0.len(), 100);
b.iter(|| {
black_box(*black_box(&mut r).get::<T>());
})
}
}