use core::{
any::{Any, TypeId},
marker::PhantomData,
mem::ManuallyDrop,
ptr,
};
use alloc::boxed::Box;
use crate::storage::InlineStorage;
unsafe fn type_id_boxed_any(storage: &InlineStorage) -> TypeId {
let r: &Box<dyn Any> = unsafe { storage.as_ref::<Box<dyn Any>>().assume_init_ref() };
let r: &dyn Any = &**r;
r.type_id()
}
unsafe fn drop_inlined<T>(storage: &mut InlineStorage) {
unsafe {
storage.as_mut::<T>().assume_init_drop();
}
}
unsafe fn drop_boxed<T: ?Sized>(storage: &mut InlineStorage) {
unsafe {
storage.as_mut::<Box<T>>().assume_init_drop();
}
}
unsafe fn drop_empty_inlined<T>(_storage: &mut InlineStorage) {
}
unsafe fn drop_empty_boxed<T: ?Sized>(storage: &mut InlineStorage) {
unsafe {
storage.as_mut::<Box<ManuallyDrop<T>>>().assume_init_drop();
}
}
unsafe fn as_ptr_inlined<T>(storage: &InlineStorage) -> *const u8 {
let r: &T = unsafe { storage.as_ref::<T>().assume_init_ref() };
ptr::from_ref(r).cast()
}
unsafe fn as_ptr_boxed<T: ?Sized>(storage: &InlineStorage) -> *const u8 {
let r: &T = &**unsafe { storage.as_ref::<Box<T>>().assume_init_ref() };
ptr::from_ref(r).cast()
}
unsafe fn as_mut_inlined<T>(storage: &mut InlineStorage) -> *mut u8 {
let r: &mut T = unsafe { storage.as_mut::<T>().assume_init_mut() };
ptr::from_mut(r).cast()
}
unsafe fn as_mut_boxed<T: ?Sized>(storage: &mut InlineStorage) -> *mut u8 {
let r: &mut T = &mut **unsafe { storage.as_mut::<Box<T>>().assume_init_mut() };
ptr::from_mut(r).cast()
}
struct VTable {
type_id: unsafe fn(&InlineStorage) -> TypeId,
drop: unsafe fn(&mut InlineStorage),
drop_empty: unsafe fn(&mut InlineStorage),
as_ptr: unsafe fn(&InlineStorage) -> *const u8,
as_mut: unsafe fn(&mut InlineStorage) -> *mut u8,
}
pub struct LTAny {
vtable: &'static VTable,
storage: InlineStorage,
unsend: PhantomData<*mut u8>,
}
impl Drop for LTAny {
#[inline(always)]
fn drop(&mut self) {
unsafe {
(self.vtable.drop)(&mut self.storage);
}
}
}
impl From<Box<dyn Any>> for LTAny {
#[inline(always)]
fn from(boxed: Box<dyn Any>) -> Self {
LTAny::from_any(boxed)
}
}
impl LTAny {
pub const fn fits<T>() -> bool {
InlineStorage::fits::<T>()
}
#[inline]
pub fn new<T>(value: T) -> Self
where
T: 'static,
{
let mut storage = InlineStorage::new();
if InlineStorage::fits::<T>() {
storage.as_mut::<T>().write(value);
let vtable = &VTable {
type_id: |_| TypeId::of::<T>(),
drop: drop_inlined::<T>,
drop_empty: drop_empty_inlined::<T>,
as_ptr: as_ptr_inlined::<T>,
as_mut: as_mut_inlined::<T>,
};
LTAny {
vtable,
storage,
unsend: PhantomData,
}
} else {
let boxed = Box::new(value);
storage.as_mut().write(boxed);
let vtable = &VTable {
type_id: |_| TypeId::of::<T>(),
drop: drop_boxed::<T>,
drop_empty: drop_empty_boxed::<T>,
as_ptr: as_ptr_boxed::<T>,
as_mut: as_mut_boxed::<T>,
};
LTAny {
vtable,
storage,
unsend: PhantomData,
}
}
}
#[inline]
pub fn from_box<T: 'static>(boxed: Box<T>) -> Self {
let mut storage = InlineStorage::new();
if InlineStorage::fits::<T>() {
storage.as_mut::<T>().write(*boxed);
let vtable = &VTable {
type_id: |_| TypeId::of::<T>(),
drop: drop_inlined::<T>,
drop_empty: drop_empty_inlined::<T>,
as_ptr: as_ptr_inlined::<T>,
as_mut: as_mut_inlined::<T>,
};
LTAny {
vtable,
storage,
unsend: PhantomData,
}
} else {
storage.as_mut().write(boxed);
let vtable = &VTable {
type_id: |_| TypeId::of::<T>(),
drop: drop_boxed::<T>,
drop_empty: drop_empty_boxed::<T>,
as_ptr: as_ptr_boxed::<T>,
as_mut: as_mut_boxed::<T>,
};
LTAny {
vtable,
storage,
unsend: PhantomData,
}
}
}
#[inline]
pub fn from_any(boxed: Box<dyn Any>) -> Self {
const {
assert!(InlineStorage::fits::<Box<dyn Any>>());
}
let mut storage = InlineStorage::new();
storage.as_mut::<Box<dyn Any>>().write(boxed);
let vtable = &VTable {
type_id: type_id_boxed_any,
drop: drop_boxed::<dyn Any>,
drop_empty: drop_empty_boxed::<dyn Any>,
as_ptr: as_ptr_boxed::<dyn Any>,
as_mut: as_mut_boxed::<dyn Any>,
};
LTAny {
vtable,
storage,
unsend: PhantomData,
}
}
#[inline]
pub fn type_id(&self) -> TypeId {
unsafe { (self.vtable.type_id)(&self.storage) }
}
#[inline]
pub fn is<T>(&self) -> bool
where
T: 'static,
{
self.type_id() == TypeId::of::<T>()
}
#[inline]
pub fn downcast_ref<T>(&self) -> Option<&T>
where
T: 'static,
{
if self.is::<T>() {
Some(unsafe { self.downcast_ref_unchecked::<T>() })
} else {
None
}
}
#[inline]
pub fn downcast_mut<T>(&mut self) -> Option<&mut T>
where
T: 'static,
{
if self.is::<T>() {
Some(unsafe { self.downcast_mut_unchecked::<T>() })
} else {
None
}
}
#[inline]
pub fn downcast<T>(self) -> Result<T, LTAny>
where
T: 'static,
{
if self.is::<T>() {
Ok(unsafe { self.downcast_unchecked() })
} else {
Err(self)
}
}
#[inline]
pub unsafe fn downcast_ref_unchecked<T>(&self) -> &T
where
T: 'static,
{
debug_assert!(self.is::<T>());
let ptr = unsafe { (self.vtable.as_ptr)(&self.storage) };
unsafe { &*ptr.cast() }
}
#[inline]
pub unsafe fn downcast_mut_unchecked<T>(&mut self) -> &mut T
where
T: 'static,
{
debug_assert!(self.is::<T>());
let ptr = unsafe { (self.vtable.as_mut)(&mut self.storage) };
unsafe { &mut *ptr.cast() }
}
#[inline]
pub unsafe fn downcast_unchecked<T>(self) -> T
where
T: 'static,
{
debug_assert!(self.is::<T>());
let mut me = ManuallyDrop::new(self);
let ptr = unsafe { (me.vtable.as_ptr)(&me.storage) };
let value = unsafe { ptr.cast::<T>().read() };
unsafe {
(me.vtable.drop_empty)(&mut me.storage);
}
value
}
}
pub struct TAny {
inner: LTAny,
}
unsafe impl Send for TAny {}
unsafe impl Sync for TAny {}
impl From<Box<dyn Any + Send + Sync>> for TAny {
#[inline(always)]
fn from(boxed: Box<dyn Any + Send + Sync>) -> Self {
TAny::from_any(boxed)
}
}
impl From<TAny> for LTAny {
#[inline(always)]
fn from(value: TAny) -> Self {
value.inner
}
}
impl TAny {
pub const fn fits<T>() -> bool {
InlineStorage::fits::<T>()
}
#[inline]
pub fn new<T>(value: T) -> Self
where
T: Send + Sync + 'static,
{
TAny {
inner: LTAny::new(value),
}
}
#[inline]
pub fn from_box<T>(boxed: Box<T>) -> Self
where
T: Send + Sync + 'static,
{
TAny {
inner: LTAny::from_box(boxed),
}
}
#[inline]
pub fn from_any(boxed: Box<dyn Any + Send + Sync>) -> Self {
TAny {
inner: LTAny::from_any(boxed),
}
}
#[inline]
pub fn type_id(&self) -> TypeId {
self.inner.type_id()
}
#[inline]
pub fn is<T>(&self) -> bool
where
T: 'static,
{
self.inner.is::<T>()
}
#[inline]
pub fn downcast_ref<T>(&self) -> Option<&T>
where
T: 'static,
{
self.inner.downcast_ref()
}
#[inline]
pub fn downcast_mut<T>(&mut self) -> Option<&mut T>
where
T: 'static,
{
self.inner.downcast_mut()
}
#[inline]
pub fn downcast<T>(self) -> Result<T, TAny>
where
T: 'static,
{
if self.is::<T>() {
Ok(unsafe { self.inner.downcast_unchecked() })
} else {
Err(self)
}
}
#[inline]
pub unsafe fn downcast_ref_unchecked<T>(&self) -> &T
where
T: 'static,
{
self.inner.downcast_ref_unchecked()
}
#[inline]
pub unsafe fn downcast_mut_unchecked<T>(&mut self) -> &mut T
where
T: 'static,
{
self.inner.downcast_mut_unchecked()
}
#[inline]
pub unsafe fn downcast_unchecked<T>(self) -> T
where
T: 'static,
{
self.inner.downcast_unchecked()
}
}