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 unsafe { core::ptr::write(ptr as *mut T, T::default()) };
17}
18unsafe fn drop_fn<T>(ptr: *mut u8) {
19 unsafe { 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::new(), 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 unsafe { std::ptr::write(mem as *mut Rc<_>, self.clone()) };
146 for f in &self.fields {
147 if let Some(ctor) = f.construct {
148 unsafe { ctor(mem.add(f.offset)) };
149 }
150 }
151 }
152
153 pub unsafe fn drop_in_place(instance: *mut Instance) {
157 let type_info = unsafe { (*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 unsafe { dtor(mem.add(f.offset)) };
162 }
163 }
164 }
165
166 unsafe fn delete_instance(instance: *mut Instance) {
170 unsafe {
171 let mem_layout = (&(*instance).type_info).mem_layout;
172 Self::drop_in_place(instance);
173 let mem = instance as *mut u8;
174 std::alloc::dealloc(mem, mem_layout);
175 }
176 }
177
178 pub fn layout(&self) -> core::alloc::Layout {
179 self.mem_layout
180 }
181}
182
183#[repr(C)]
185pub struct Instance<'id> {
186 type_info: Rc<TypeInfo<'id>>,
187 _opaque: [u8; 0],
188}
189
190impl<'id> Instance<'id> {
191 pub fn type_info(&self) -> Rc<TypeInfo<'id>> {
193 self.type_info.clone()
194 }
195}
196
197impl core::fmt::Debug for Instance<'_> {
198 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
199 write!(f, "Instance({self:p})")
200 }
201}
202
203pub struct InstanceBox<'id>(core::ptr::NonNull<Instance<'id>>);
205
206impl<'id> InstanceBox<'id> {
207 pub fn as_ptr(&self) -> core::ptr::NonNull<Instance<'id>> {
209 self.0
210 }
211
212 pub fn as_pin_ref(&self) -> core::pin::Pin<&Instance<'id>> {
213 unsafe { core::pin::Pin::new_unchecked(self.0.as_ref()) }
214 }
215
216 pub fn as_mut(&mut self) -> &mut Instance<'id> {
217 unsafe { self.0.as_mut() }
218 }
219}
220
221impl Drop for InstanceBox<'_> {
222 fn drop(&mut self) {
223 unsafe { TypeInfo::delete_instance(self.0.as_mut()) }
224 }
225}