use std::any::TypeId;
use ratatui_kit_macros::Props;
pub trait Props {}
trait DropRaw {
fn drop_raw(&self, raw: *mut ());
}
struct DropRawImpl<T> {
_marker: std::marker::PhantomData<T>,
}
impl<T> DropRaw for DropRawImpl<T> {
fn drop_raw(&self, raw: *mut ()) {
unsafe {
let _ = Box::from_raw(raw as *mut T);
}
}
}
#[doc(hidden)]
pub struct AnyProps<'a> {
raw: *mut (),
type_id: TypeId,
drop: Option<Box<dyn DropRaw + 'a>>,
_marker: std::marker::PhantomData<&'a mut ()>,
}
impl<'a> AnyProps<'a> {
pub(crate) fn owned<T>(props: T, type_id: TypeId) -> Self
where
T: Props + 'a,
{
let raw = Box::into_raw(Box::new(props));
Self {
raw: raw as *mut (),
type_id,
drop: Some(Box::new(DropRawImpl::<T> {
_marker: std::marker::PhantomData,
})),
_marker: std::marker::PhantomData,
}
}
pub(crate) fn borrowed<T: Props>(props: &'a mut T, type_id: TypeId) -> Self {
Self {
raw: props as *const _ as *mut (),
type_id,
drop: None, _marker: std::marker::PhantomData,
}
}
pub(crate) fn borrow(&mut self) -> AnyProps<'_> {
Self {
raw: self.raw,
type_id: self.type_id,
drop: None,
_marker: std::marker::PhantomData,
}
}
pub(crate) unsafe fn downcast_ref_unchecked<T: Props>(&self, expected_type_id: TypeId) -> &T {
debug_assert_eq!(
self.type_id, expected_type_id,
"AnyProps type mismatch before immutable downcast"
);
unsafe { &*(self.raw as *const T) }
}
pub(crate) unsafe fn downcast_mut_unchecked<T: Props>(
&mut self,
expected_type_id: TypeId,
) -> &mut T {
debug_assert_eq!(
self.type_id, expected_type_id,
"AnyProps type mismatch before mutable downcast"
);
unsafe { &mut *(self.raw as *mut T) }
}
}
impl Drop for AnyProps<'_> {
fn drop(&mut self) {
if let Some(drop) = self.drop.take() {
drop.drop_raw(self.raw);
}
}
}
#[derive(Debug, Clone, Default, Props)]
pub struct NoProps;