1use std::any::TypeId;
2
3use ratatui_kit_macros::Props;
4
5pub trait Props {}
9
10trait DropRaw {
13 fn drop_raw(&self, raw: *mut ());
14}
15
16struct DropRawImpl<T> {
19 _marker: std::marker::PhantomData<T>,
20}
21
22impl<T> DropRaw for DropRawImpl<T> {
23 fn drop_raw(&self, raw: *mut ()) {
26 unsafe {
27 let _ = Box::from_raw(raw as *mut T);
28 }
29 }
30}
31
32pub struct AnyProps<'a> {
38 raw: *mut (),
39 type_id: TypeId,
40 drop: Option<Box<dyn DropRaw + 'a>>,
41 _marker: std::marker::PhantomData<&'a mut ()>,
42}
43
44impl<'a> AnyProps<'a> {
45 pub(crate) fn owned<T>(props: T, type_id: TypeId) -> Self
48 where
49 T: Props + 'a,
50 {
51 let raw = Box::into_raw(Box::new(props));
53 Self {
54 raw: raw as *mut (),
55 type_id,
56 drop: Some(Box::new(DropRawImpl::<T> {
58 _marker: std::marker::PhantomData,
59 })),
60 _marker: std::marker::PhantomData,
61 }
62 }
63
64 pub(crate) fn borrowed<T: Props>(props: &'a mut T, type_id: TypeId) -> Self {
67 Self {
68 raw: props as *const _ as *mut (),
69 type_id,
70 drop: None, _marker: std::marker::PhantomData,
72 }
73 }
74
75 pub(crate) fn borrow(&mut self) -> AnyProps<'_> {
78 Self {
79 raw: self.raw,
80 type_id: self.type_id,
81 drop: None,
82 _marker: std::marker::PhantomData,
83 }
84 }
85
86 pub(crate) unsafe fn downcast_ref_unchecked<T: Props>(&self, expected_type_id: TypeId) -> &T {
89 debug_assert_eq!(
90 self.type_id, expected_type_id,
91 "AnyProps type mismatch before immutable downcast"
92 );
93 unsafe { &*(self.raw as *const T) }
94 }
95
96 pub(crate) unsafe fn downcast_mut_unchecked<T: Props>(
99 &mut self,
100 expected_type_id: TypeId,
101 ) -> &mut T {
102 debug_assert_eq!(
103 self.type_id, expected_type_id,
104 "AnyProps type mismatch before mutable downcast"
105 );
106 unsafe { &mut *(self.raw as *mut T) }
107 }
108}
109
110impl Drop for AnyProps<'_> {
112 fn drop(&mut self) {
113 if let Some(drop) = self.drop.take() {
115 drop.drop_raw(self.raw);
116 }
117 }
118}
119
120#[derive(Debug, Clone, Default, Props)]
121pub struct NoProps;