Skip to main content

ratatui_kit/
props.rs

1use std::any::TypeId;
2
3use ratatui_kit_macros::Props;
4
5// 组件属性 trait,所有可作为组件 props 的类型都需实现此 trait。
6//
7// - 推荐使用 `#[derive(Props)]` 自动实现。
8pub trait Props {}
9
10// 用于处理原始指针释放的trait
11// 通过类型擦除实现对未知类型的内存释放
12trait DropRaw {
13    fn drop_raw(&self, raw: *mut ());
14}
15
16// 类型擦除的具体实现
17// 使用PhantomData标记实际类型T
18struct DropRawImpl<T> {
19    _marker: std::marker::PhantomData<T>,
20}
21
22impl<T> DropRaw for DropRawImpl<T> {
23    // 实际执行内存释放的方法
24    // 将原始指针转换为Box后释放
25    fn drop_raw(&self, raw: *mut ()) {
26        unsafe {
27            let _ = Box::from_raw(raw as *mut T);
28        }
29    }
30}
31
32// 类型擦除容器
33// 支持存储任意类型的属性(owned/borrowed)
34// raw: 指向实际数据的原始指针
35// drop: 可选的drop处理函数(对于owned类型)
36// _marker: 生命周期标记
37#[doc(hidden)]
38pub struct AnyProps<'a> {
39    raw: *mut (),
40    type_id: TypeId,
41    drop: Option<Box<dyn DropRaw + 'a>>,
42    _marker: std::marker::PhantomData<&'a mut ()>,
43}
44
45impl<'a> AnyProps<'a> {
46    // 创建拥有所有权的AnyProps实例
47    // T: 实现Props trait的类型
48    pub(crate) fn owned<T>(props: T, type_id: TypeId) -> Self
49    where
50        T: Props + 'a,
51    {
52        // 将属性堆分配并转换为原始指针
53        let raw = Box::into_raw(Box::new(props));
54        Self {
55            raw: raw as *mut (),
56            type_id,
57            // 保存对应的drop处理实现
58            drop: Some(Box::new(DropRawImpl::<T> {
59                _marker: std::marker::PhantomData,
60            })),
61            _marker: std::marker::PhantomData,
62        }
63    }
64
65    // 创建借用的AnyProps实例
66    // 不持有所有权,不负责内存释放
67    pub(crate) fn borrowed<T: Props>(props: &'a mut T, type_id: TypeId) -> Self {
68        Self {
69            raw: props as *const _ as *mut (),
70            type_id,
71            drop: None, // 不负责内存释放
72            _marker: std::marker::PhantomData,
73        }
74    }
75
76    // 创建只读借用版本
77    // drop字段设为None表示不处理内存释放
78    pub(crate) fn borrow(&mut self) -> AnyProps<'_> {
79        Self {
80            raw: self.raw,
81            type_id: self.type_id,
82            drop: None,
83            _marker: std::marker::PhantomData,
84        }
85    }
86
87    // 不安全的下转型方法(不可变引用)
88    // 调用者必须确保实际类型与T匹配
89    pub(crate) unsafe fn downcast_ref_unchecked<T: Props>(&self, expected_type_id: TypeId) -> &T {
90        debug_assert_eq!(
91            self.type_id, expected_type_id,
92            "AnyProps type mismatch before immutable downcast"
93        );
94        unsafe { &*(self.raw as *const T) }
95    }
96
97    // 不安全的下转型方法(可变引用)
98    // 调用者必须确保实际类型与T匹配
99    pub(crate) unsafe fn downcast_mut_unchecked<T: Props>(
100        &mut self,
101        expected_type_id: TypeId,
102    ) -> &mut T {
103        debug_assert_eq!(
104            self.type_id, expected_type_id,
105            "AnyProps type mismatch before mutable downcast"
106        );
107        unsafe { &mut *(self.raw as *mut T) }
108    }
109}
110
111// 实现Drop trait用于资源释放
112impl Drop for AnyProps<'_> {
113    fn drop(&mut self) {
114        // 如果存在drop处理器,执行内存释放
115        if let Some(drop) = self.drop.take() {
116            drop.drop_raw(self.raw);
117        }
118    }
119}
120
121#[derive(Debug, Clone, Default, Props)]
122// 空属性类型,表示组件不需要任何 props。
123//
124// 可用于无参数组件或默认占位。
125pub struct NoProps;