slint_interpreter/
dynamic_type.rs1use core::alloc::Layout;
11use generativity::Id;
12use i_slint_core::rtti::FieldOffset;
13use std::rc::Rc;
14
15unsafe fn construct_fn<T: Default>(ptr: *mut u8) {
16 core::ptr::write(ptr as *mut T, T::default());
17}
18unsafe fn drop_fn<T>(ptr: *mut u8) {
19 core::ptr::drop_in_place(ptr as *mut T);
20}
21
22#[derive(Copy, Clone)]
26pub struct StaticTypeInfo {
27 construct: Option<unsafe fn(*mut u8)>,
31 drop: Option<unsafe fn(*mut u8)>,
34 mem_layout: Layout,
36}
37
38impl StaticTypeInfo {
39 pub fn new<T: Default>() -> StaticTypeInfo {
41 let drop = if core::mem::needs_drop::<T>() { Some(drop_fn::<T> as _) } else { None };
42 StaticTypeInfo { construct: Some(construct_fn::<T>), drop, mem_layout: Layout::new::<T>() }
43 }
44}
45
46struct FieldInfo {
48 construct: Option<unsafe fn(*mut u8)>,
49 drop: Option<unsafe fn(*mut u8)>,
50 offset: usize,
51}
52
53pub struct TypeInfo<'id> {
57 mem_layout: core::alloc::Layout,
58 fields: Vec<FieldInfo>,
63
64 #[allow(unused)]
65 id: Id<'id>,
66}
67
68pub struct TypeBuilder<'id> {
72 align: usize,
74 size: usize,
76 fields: Vec<FieldInfo>,
77 id: Id<'id>,
78}
79
80impl<'id> TypeBuilder<'id> {
81 pub fn new(id: generativity::Guard<'id>) -> Self {
82 let mut s = Self { align: 1, size: 0, fields: vec![], id: id.into() };
83 type T<'id> = Rc<TypeInfo<'id>>;
84 s.add_field(StaticTypeInfo {
85 construct: None,
86 drop: Some(drop_fn::<T<'id>>),
87 mem_layout: Layout::new::<T<'id>>(),
88 });
89 s
90 }
91
92 pub fn add_field_type<T: Default>(&mut self) -> FieldOffset<Instance<'id>, T> {
94 unsafe { FieldOffset::new_from_offset_pinned(self.add_field(StaticTypeInfo::new::<T>())) }
95 }
96
97 pub fn add_field(&mut self, ty: StaticTypeInfo) -> usize {
102 let align = ty.mem_layout.align();
103 let len_rounded_up = self.size.wrapping_add(align).wrapping_sub(1) & !align.wrapping_sub(1);
104
105 self.fields.push(FieldInfo {
106 construct: ty.construct,
107 drop: ty.drop,
108 offset: len_rounded_up,
109 });
110 self.size = len_rounded_up + ty.mem_layout.size();
111 self.align = self.align.max(align);
112 len_rounded_up
113 }
114
115 pub fn build(self) -> Rc<TypeInfo<'id>> {
116 let size = self.size.wrapping_add(self.align).wrapping_sub(1) & !self.align.wrapping_sub(1);
117 Rc::new(TypeInfo {
118 mem_layout: core::alloc::Layout::from_size_align(size, self.align).unwrap(),
119 fields: self.fields,
120 id: self.id,
121 })
122 }
123}
124
125impl<'id> TypeInfo<'id> {
126 pub fn create_instance(self: Rc<Self>) -> InstanceBox<'id> {
131 unsafe {
132 let mem = std::alloc::alloc(self.mem_layout) as *mut Instance;
133 self.create_instance_in_place(mem);
134 InstanceBox(core::ptr::NonNull::new_unchecked(mem))
135 }
136 }
137
138 pub unsafe fn create_instance_in_place(self: Rc<Self>, mem: *mut Instance<'id>) {
143 let mem = mem as *mut u8;
145 std::ptr::write(mem as *mut Rc<_>, self.clone());
146 for f in &self.fields {
147 if let Some(ctor) = f.construct {
148 ctor(mem.add(f.offset));
149 }
150 }
151 }
152
153 pub unsafe fn drop_in_place(instance: *mut Instance) {
157 let type_info = (*instance).type_info.clone();
158 let mem = instance as *mut u8;
159 for f in &type_info.fields {
160 if let Some(dtor) = f.drop {
161 dtor(mem.add(f.offset));
162 }
163 }
164 }
165
166 unsafe fn delete_instance(instance: *mut Instance) {
170 let mem_layout = (&(*instance).type_info).mem_layout;
171 Self::drop_in_place(instance);
172 let mem = instance as *mut u8;
173 std::alloc::dealloc(mem, mem_layout);
174 }
175
176 pub fn layout(&self) -> core::alloc::Layout {
177 self.mem_layout
178 }
179}
180
181#[repr(C)]
183pub struct Instance<'id> {
184 type_info: Rc<TypeInfo<'id>>,
185 _opaque: [u8; 0],
186}
187
188impl<'id> Instance<'id> {
189 pub fn type_info(&self) -> Rc<TypeInfo<'id>> {
191 self.type_info.clone()
192 }
193}
194
195impl core::fmt::Debug for Instance<'_> {
196 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
197 write!(f, "Instance({self:p})")
198 }
199}
200
201pub struct InstanceBox<'id>(core::ptr::NonNull<Instance<'id>>);
203
204impl<'id> InstanceBox<'id> {
205 pub fn as_ptr(&self) -> core::ptr::NonNull<Instance<'id>> {
207 self.0
208 }
209
210 pub fn as_pin_ref(&self) -> core::pin::Pin<&Instance<'id>> {
211 unsafe { core::pin::Pin::new_unchecked(self.0.as_ref()) }
212 }
213
214 pub fn as_mut(&mut self) -> &mut Instance<'id> {
215 unsafe { self.0.as_mut() }
216 }
217}
218
219impl Drop for InstanceBox<'_> {
220 fn drop(&mut self) {
221 unsafe { TypeInfo::delete_instance(self.0.as_mut()) }
222 }
223}