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