#![cfg_attr(not(feature = "std"), no_std)]
#[derive(Debug)]
pub struct StackAny<const N: usize> {
bytes: [core::mem::MaybeUninit<u8>; N],
size: usize,
}
impl<const N: usize> StackAny<N> {
#[inline]
pub fn new<T>(value: T) -> Self
where
T: core::any::Any,
{
Self::try_new(value).expect("T size is larger than N")
}
pub fn try_new<T>(value: T) -> Option<Self>
where
T: core::any::Any,
{
if N < core::mem::size_of::<T>() {
return None;
}
let mut slf = Self {
bytes: [core::mem::MaybeUninit::uninit(); N],
size: core::mem::size_of::<T>(),
};
let src = &value as *const _ as *const _;
let dst = slf.bytes.as_mut_ptr();
unsafe { core::ptr::copy_nonoverlapping(src, dst, slf.size) };
core::mem::forget(value);
Some(slf)
}
#[inline]
pub fn downcast_ref<T>(&self) -> &T
where
T: core::any::Any,
{
self.try_downcast_ref().expect("T size is larger than N")
}
pub fn try_downcast_ref<T>(&self) -> Option<&T>
where
T: core::any::Any,
{
if N < core::mem::size_of::<T>() {
return None;
}
let ptr = self.bytes.as_ptr();
Some(unsafe { &*(ptr as *const T) })
}
pub fn downcast_mut<T>(&mut self) -> &mut T
where
T: core::any::Any,
{
self.try_downcast_mut().expect("T size is larger than N")
}
pub fn try_downcast_mut<T>(&mut self) -> Option<&mut T>
where
T: core::any::Any,
{
if N < core::mem::size_of::<T>() {
return None;
}
let ptr = self.bytes.as_mut_ptr();
Some(unsafe { &mut *(ptr as *mut T) })
}
pub fn downcast<T>(self) -> T
where
T: core::any::Any,
{
self.try_downcast().expect("T size is larger than N")
}
pub fn try_downcast<T>(self) -> Option<T>
where
T: core::any::Any,
{
if N < core::mem::size_of::<T>() {
return None;
}
let ptr = self.bytes.as_ptr();
Some(unsafe { core::ptr::read(ptr as *const T) })
}
}
#[macro_export]
macro_rules! stack_any {
($type:ty, $init:expr) => {
$crate::StackAny::<{ std::mem::size_of::<$type>() }>::new::<$type>($init)
};
}