1 | // Take a look at the license at the top of the repository in the LICENSE file. |
2 | |
3 | // rustdoc-stripper-ignore-next |
4 | //! Module that contains the basic infrastructure for subclassing `GObject`. |
5 | |
6 | use std::{any::Any, collections::BTreeMap, marker, mem, ptr}; |
7 | |
8 | use super::SignalId; |
9 | use crate::{ |
10 | object::{IsClass, IsInterface, ObjectSubclassIs, ParentClassIs}, |
11 | prelude::*, |
12 | translate::*, |
13 | Closure, Object, Type, Value, |
14 | }; |
15 | |
16 | // rustdoc-stripper-ignore-next |
17 | /// A newly registered `glib::Type` that is currently still being initialized. |
18 | /// |
19 | /// This allows running additional type-setup functions. |
20 | #[derive (Debug, PartialEq, Eq)] |
21 | pub struct InitializingType<T>(pub(crate) Type, pub(crate) marker::PhantomData<*const T>); |
22 | |
23 | impl<T> IntoGlib for InitializingType<T> { |
24 | type GlibType = ffi::GType; |
25 | |
26 | #[inline ] |
27 | fn into_glib(self) -> ffi::GType { |
28 | self.0.into_glib() |
29 | } |
30 | } |
31 | |
32 | // rustdoc-stripper-ignore-next |
33 | /// Struct used for the instance private data of the GObject. |
34 | struct PrivateStruct<T: ObjectSubclass> { |
35 | imp: T, |
36 | instance_data: Option<BTreeMap<Type, Box<dyn Any + Send + Sync>>>, |
37 | } |
38 | |
39 | // rustdoc-stripper-ignore-next |
40 | /// Trait implemented by structs that implement a `GObject` C instance struct. |
41 | /// |
42 | /// The struct must be `#[repr(C)]` and have the parent type's instance struct |
43 | /// as the first field. |
44 | /// |
45 | /// See [`basic::InstanceStruct`] for a basic implementation of this that can |
46 | /// be used most of the time and should only not be used if additional fields are |
47 | /// required in the instance struct. |
48 | /// |
49 | /// [`basic::InstanceStruct`]: ../basic/struct.InstanceStruct.html |
50 | pub unsafe trait InstanceStruct: Sized + 'static { |
51 | // rustdoc-stripper-ignore-next |
52 | /// Corresponding object subclass type for this instance struct. |
53 | type Type: ObjectSubclass; |
54 | |
55 | // rustdoc-stripper-ignore-next |
56 | /// Instance specific initialization. |
57 | /// |
58 | /// This is automatically called during instance initialization and must call `instance_init()` |
59 | /// of the parent class. |
60 | #[inline ] |
61 | fn instance_init(&mut self) { |
62 | unsafe { |
63 | let obj: Borrowed = from_glib_borrow::<_, Object>(self as *mut _ as *mut gobject_ffi::GObject); |
64 | let obj: Borrowed<{unknown}> = Borrowed::new(val:obj.into_inner().unsafe_cast()); |
65 | let mut obj: InitializingObject<{unknown}> = InitializingObject(obj); |
66 | |
67 | <<Self::Type as ObjectSubclass>::ParentType as IsSubclassable<Self::Type>>::instance_init( |
68 | &mut obj, |
69 | ); |
70 | } |
71 | } |
72 | } |
73 | |
74 | // rustdoc-stripper-ignore-next |
75 | /// Trait implemented by any type implementing `InstanceStruct` to return the implementation, private Rust struct. |
76 | pub unsafe trait InstanceStructExt: InstanceStruct { |
77 | // rustdoc-stripper-ignore-next |
78 | /// Returns the implementation for from this instance struct, that |
79 | /// is the implementor of [`ObjectImpl`] or subtraits. |
80 | /// |
81 | /// [`ObjectImpl`]: ../object/trait.ObjectImpl.html |
82 | #[doc (alias = "get_impl" )] |
83 | fn imp(&self) -> &Self::Type; |
84 | |
85 | // rustdoc-stripper-ignore-next |
86 | /// Returns the class struct for this specific instance. |
87 | #[doc (alias = "get_class" )] |
88 | fn class(&self) -> &<Self::Type as ObjectSubclass>::Class; |
89 | } |
90 | |
91 | // rustdoc-stripper-ignore-next |
92 | /// Offset `ptr` by `offset` *bytes* and cast the result to `*const U`. |
93 | /// |
94 | /// The result must be a correctly aligned pointer to a valid value of type `U`. |
95 | /// |
96 | /// # Panics: |
97 | /// |
98 | /// This function panics if debug assertions are enabled if adding `offset` causes `ptr` to |
99 | /// overflow or if the resulting pointer is not correctly aligned. |
100 | #[inline ] |
101 | fn offset_ptr_by_bytes<T, U>(ptr: *const T, offset: isize) -> *const U { |
102 | // FIXME: Use `ptr::expose_addr()` once stable |
103 | let ptr: usize = ptr as usize; |
104 | let ptr: usize = if offset < 0 { |
105 | ptr - (-offset) as usize |
106 | } else { |
107 | ptr + offset as usize |
108 | }; |
109 | debug_assert_eq!(ptr & (mem::align_of::<U>() - 1), 0); |
110 | ptr as *const U |
111 | } |
112 | |
113 | // rustdoc-stripper-ignore-next |
114 | /// Offset `ptr` by `offset` *bytes* and cast the result to `*mut U`. |
115 | /// |
116 | /// The result must be a correctly aligned pointer to a valid value of type `U`. |
117 | /// |
118 | /// # Panics: |
119 | /// |
120 | /// This function panics if debug assertions are enabled if adding `offset` causes `ptr` to |
121 | /// overflow or if the resulting pointer is not correctly aligned. |
122 | #[inline ] |
123 | fn offset_ptr_by_bytes_mut<T, U>(ptr: *mut T, offset: isize) -> *mut U { |
124 | // FIXME: Use `ptr::expose_addr()` once stable |
125 | let ptr: usize = ptr as usize; |
126 | let ptr: usize = if offset < 0 { |
127 | ptr - (-offset) as usize |
128 | } else { |
129 | ptr + offset as usize |
130 | }; |
131 | debug_assert_eq!(ptr & (mem::align_of::<U>() - 1), 0); |
132 | ptr as *mut U |
133 | } |
134 | |
135 | unsafe impl<T: InstanceStruct> InstanceStructExt for T { |
136 | #[inline ] |
137 | fn imp(&self) -> &Self::Type { |
138 | unsafe { |
139 | let data: NonNull = Self::Type::type_data(); |
140 | let private_offset: isize = data.as_ref().impl_offset(); |
141 | let imp: *const {unknown} = offset_ptr_by_bytes::<T, Self::Type>(self, private_offset); |
142 | &*imp |
143 | } |
144 | } |
145 | |
146 | #[inline ] |
147 | fn class(&self) -> &<Self::Type as ObjectSubclass>::Class { |
148 | unsafe { &**(self as *const _ as *const *const <Self::Type as ObjectSubclass>::Class) } |
149 | } |
150 | } |
151 | |
152 | // rustdoc-stripper-ignore-next |
153 | /// Trait implemented by any type implementing `ObjectSubclassIs` to return the implementation, private Rust struct. |
154 | pub trait ObjectSubclassIsExt: ObjectSubclassIs { |
155 | // rustdoc-stripper-ignore-next |
156 | /// Returns the implementation (the private Rust struct) of this class instance |
157 | fn imp(&self) -> &Self::Subclass; |
158 | } |
159 | |
160 | impl<T: ObjectSubclassIs<Subclass = S>, S: ObjectSubclass<Type = Self>> ObjectSubclassIsExt for T { |
161 | #[inline ] |
162 | fn imp(&self) -> &T::Subclass { |
163 | T::Subclass::from_obj(self) |
164 | } |
165 | } |
166 | |
167 | // rustdoc-stripper-ignore-next |
168 | /// Trait implemented by structs that implement a `GObject` C class struct. |
169 | /// |
170 | /// The struct must be `#[repr(C)]` and have the parent type's class struct |
171 | /// as the first field. |
172 | /// |
173 | /// See [`basic::ClassStruct`] for a basic implementation of this that can |
174 | /// be used most of the time and should only not be used if additional fields are |
175 | /// required in the class struct, e.g. for declaring new virtual methods. |
176 | /// |
177 | /// [`basic::ClassStruct`]: ../basic/struct.ClassStruct.html |
178 | pub unsafe trait ClassStruct: Sized + 'static { |
179 | // rustdoc-stripper-ignore-next |
180 | /// Corresponding object subclass type for this class struct. |
181 | type Type: ObjectSubclass; |
182 | |
183 | // rustdoc-stripper-ignore-next |
184 | /// Override the vfuncs of all parent types. |
185 | /// |
186 | /// This is automatically called during type initialization. |
187 | #[inline ] |
188 | fn class_init(&mut self) { |
189 | unsafe { |
190 | let base: &mut Class<{unknown}> = &mut *(self as *mut _ |
191 | as *mut crate::Class<<Self::Type as ObjectSubclass>::ParentType>); |
192 | <<Self::Type as ObjectSubclass>::ParentType as IsSubclassable<Self::Type>>::class_init( |
193 | class:base, |
194 | ); |
195 | } |
196 | } |
197 | } |
198 | |
199 | // rustdoc-stripper-ignore-next |
200 | /// Trait for subclassable class structs. |
201 | pub unsafe trait IsSubclassable<T: ObjectSubclass>: IsSubclassableDefault<T> { |
202 | // rustdoc-stripper-ignore-next |
203 | /// Override the virtual methods of this class for the given subclass and do other class |
204 | /// initialization. |
205 | /// |
206 | /// This is automatically called during type initialization and must call `class_init()` of the |
207 | /// parent class. |
208 | #[inline ] |
209 | fn class_init(class: &mut crate::Class<Self>) { |
210 | Self::default_class_init(class); |
211 | } |
212 | |
213 | // rustdoc-stripper-ignore-next |
214 | /// Instance specific initialization. |
215 | /// |
216 | /// This is automatically called during instance initialization and must call `instance_init()` |
217 | /// of the parent class. |
218 | #[inline ] |
219 | fn instance_init(instance: &mut InitializingObject<T>) { |
220 | Self::default_instance_init(instance); |
221 | } |
222 | } |
223 | |
224 | // FIXME: It should be possible to make implemented for all instances of `IsSubclassable<T>` |
225 | // with specialization, and make it private. |
226 | #[doc (hidden)] |
227 | pub trait IsSubclassableDefault<T: ObjectSubclass>: IsClass { |
228 | fn default_class_init(class: &mut crate::Class<Self>); |
229 | fn default_instance_init(instance: &mut InitializingObject<T>); |
230 | } |
231 | |
232 | impl<T: ObjectSubclass, U: IsSubclassable<T> + ParentClassIs> IsSubclassableDefault<T> for U |
233 | where |
234 | U::Parent: IsSubclassable<T>, |
235 | { |
236 | #[inline ] |
237 | fn default_class_init(class: &mut crate::Class<Self>) { |
238 | U::Parent::class_init(self:class); |
239 | } |
240 | |
241 | #[inline ] |
242 | fn default_instance_init(instance: &mut InitializingObject<T>) { |
243 | U::Parent::instance_init(instance); |
244 | } |
245 | } |
246 | |
247 | impl<T: ObjectSubclass> IsSubclassableDefault<T> for Object { |
248 | #[inline ] |
249 | fn default_class_init(_class: &mut crate::Class<Self>) {} |
250 | |
251 | #[inline ] |
252 | fn default_instance_init(_instance: &mut InitializingObject<T>) {} |
253 | } |
254 | |
255 | pub trait IsSubclassableExt: IsClass + ParentClassIs { |
256 | fn parent_class_init<T: ObjectSubclass>(class: &mut crate::Class<Self>) |
257 | where |
258 | Self::Parent: IsSubclassable<T>; |
259 | fn parent_instance_init<T: ObjectSubclass>(instance: &mut InitializingObject<T>) |
260 | where |
261 | Self::Parent: IsSubclassable<T>; |
262 | } |
263 | |
264 | impl<U: IsClass + ParentClassIs> IsSubclassableExt for U { |
265 | #[inline ] |
266 | fn parent_class_init<T: ObjectSubclass>(class: &mut crate::Class<Self>) |
267 | where |
268 | U::Parent: IsSubclassable<T>, |
269 | { |
270 | Self::Parent::class_init(self:class); |
271 | } |
272 | |
273 | #[inline ] |
274 | fn parent_instance_init<T: ObjectSubclass>(instance: &mut InitializingObject<T>) |
275 | where |
276 | U::Parent: IsSubclassable<T>, |
277 | { |
278 | Self::Parent::instance_init(instance); |
279 | } |
280 | } |
281 | |
282 | // rustdoc-stripper-ignore-next |
283 | /// Trait for implementable interfaces. |
284 | pub unsafe trait IsImplementable<T: ObjectSubclass>: IsInterface |
285 | where |
286 | <Self as ObjectType>::GlibClassType: Copy, |
287 | { |
288 | // rustdoc-stripper-ignore-next |
289 | /// Override the virtual methods of this interface for the given subclass and do other |
290 | /// interface initialization. |
291 | /// |
292 | /// This is automatically called during type initialization. |
293 | fn interface_init(_iface: &mut crate::Interface<Self>) {} |
294 | |
295 | // rustdoc-stripper-ignore-next |
296 | /// Instance specific initialization. |
297 | /// |
298 | /// This is automatically called during instance initialization. |
299 | fn instance_init(_instance: &mut InitializingObject<T>) {} |
300 | } |
301 | |
302 | unsafe extern "C" fn interface_init<T: ObjectSubclass, A: IsImplementable<T>>( |
303 | iface: ffi::gpointer, |
304 | _iface_data: ffi::gpointer, |
305 | ) where |
306 | <A as ObjectType>::GlibClassType: Copy, |
307 | { |
308 | let iface: &mut Interface = &mut *(iface as *mut crate::Interface<A>); |
309 | |
310 | let mut data: NonNull = T::type_data(); |
311 | if data.as_ref().parent_ifaces.is_none() { |
312 | data.as_mut().parent_ifaces = Some(BTreeMap::default()); |
313 | } |
314 | { |
315 | let copy: Box<::GlibClassType> = Box::new(*iface.as_ref()); |
316 | data.as_mut() |
317 | .parent_ifaces |
318 | .as_mut() |
319 | .unwrap() |
320 | .insert(A::static_type(), value:Box::into_raw(copy) as ffi::gpointer); |
321 | } |
322 | |
323 | A::interface_init(iface); |
324 | } |
325 | |
326 | // rustdoc-stripper-ignore-next |
327 | /// Trait for a type list of interfaces. |
328 | pub trait InterfaceList<T: ObjectSubclass> { |
329 | // rustdoc-stripper-ignore-next |
330 | /// Returns the list of types and corresponding interface infos for this list. |
331 | fn iface_infos() -> Vec<(ffi::GType, gobject_ffi::GInterfaceInfo)>; |
332 | |
333 | // rustdoc-stripper-ignore-next |
334 | /// Runs `instance_init` on each of the `IsImplementable` items. |
335 | fn instance_init(_instance: &mut InitializingObject<T>); |
336 | } |
337 | |
338 | impl<T: ObjectSubclass> InterfaceList<T> for () { |
339 | fn iface_infos() -> Vec<(ffi::GType, gobject_ffi::GInterfaceInfo)> { |
340 | vec![] |
341 | } |
342 | |
343 | #[inline ] |
344 | fn instance_init(_instance: &mut InitializingObject<T>) {} |
345 | } |
346 | |
347 | impl<T: ObjectSubclass, A: IsImplementable<T>> InterfaceList<T> for (A,) |
348 | where |
349 | <A as ObjectType>::GlibClassType: Copy, |
350 | { |
351 | fn iface_infos() -> Vec<(ffi::GType, gobject_ffi::GInterfaceInfo)> { |
352 | vec![( |
353 | A::static_type().into_glib(), |
354 | gobject_ffi::GInterfaceInfo { |
355 | interface_init: Some(interface_init::<T, A>), |
356 | interface_finalize: None, |
357 | interface_data: ptr::null_mut(), |
358 | }, |
359 | )] |
360 | } |
361 | |
362 | #[inline ] |
363 | fn instance_init(instance: &mut InitializingObject<T>) { |
364 | A::instance_init(instance); |
365 | } |
366 | } |
367 | |
368 | // Generates all the InterfaceList impls for interface_lists of arbitrary sizes based on a list of type |
369 | // parameters like A B C. It would generate the impl then for (A, B) and (A, B, C). |
370 | macro_rules! interface_list_trait( |
371 | ($name1:ident, $name2: ident, $($name:ident),*) => ( |
372 | interface_list_trait!(__impl $name1, $name2; $($name),*); |
373 | ); |
374 | (__impl $($name:ident),+; $name1:ident, $($name2:ident),*) => ( |
375 | interface_list_trait_impl!($($name),+); |
376 | interface_list_trait!(__impl $($name),+ , $name1; $($name2),*); |
377 | ); |
378 | (__impl $($name:ident),+; $name1:ident) => ( |
379 | interface_list_trait_impl!($($name),+); |
380 | interface_list_trait_impl!($($name),+, $name1); |
381 | ); |
382 | ); |
383 | |
384 | // Generates the impl block for InterfaceList on interface_lists or arbitrary sizes based on its |
385 | // arguments. Takes a list of type parameters as parameters, e.g. A B C |
386 | // and then implements the trait on (A, B, C). |
387 | macro_rules! interface_list_trait_impl( |
388 | ($($name:ident),+) => ( |
389 | impl<T: ObjectSubclass, $($name: IsImplementable<T>),+> InterfaceList<T> for ( $($name),+ ) |
390 | where |
391 | $(<$name as ObjectType>::GlibClassType: Copy),+ |
392 | { |
393 | fn iface_infos() -> Vec<(ffi::GType, gobject_ffi::GInterfaceInfo)> { |
394 | vec![ |
395 | $( |
396 | ( |
397 | $name::static_type().into_glib(), |
398 | gobject_ffi::GInterfaceInfo { |
399 | interface_init: Some(interface_init::<T, $name>), |
400 | interface_finalize: None, |
401 | interface_data: ptr::null_mut(), |
402 | }, |
403 | ) |
404 | ),+ |
405 | ] |
406 | } |
407 | |
408 | #[inline] |
409 | fn instance_init(instance: &mut InitializingObject<T>) { |
410 | $( |
411 | $name::instance_init(instance); |
412 | )+ |
413 | } |
414 | } |
415 | ); |
416 | ); |
417 | |
418 | interface_list_trait!(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S); |
419 | |
420 | /// Type-specific data that is filled in during type creation. |
421 | // FIXME: Once trait bounds other than `Sized` on const fn parameters are stable |
422 | // the content of `TypeData` can be made private, and we can add a `const fn new` |
423 | // for initialization by the `object_subclass_internal!` macro. |
424 | pub struct TypeData { |
425 | #[doc (hidden)] |
426 | pub type_: Type, |
427 | #[doc (hidden)] |
428 | pub parent_class: ffi::gpointer, |
429 | #[doc (hidden)] |
430 | pub parent_ifaces: Option<BTreeMap<Type, ffi::gpointer>>, |
431 | #[doc (hidden)] |
432 | pub class_data: Option<BTreeMap<Type, Box<dyn Any + Send + Sync>>>, |
433 | #[doc (hidden)] |
434 | pub private_offset: isize, |
435 | #[doc (hidden)] |
436 | pub private_imp_offset: isize, |
437 | } |
438 | |
439 | unsafe impl Send for TypeData {} |
440 | unsafe impl Sync for TypeData {} |
441 | |
442 | impl TypeData { |
443 | // rustdoc-stripper-ignore-next |
444 | /// Returns the type ID. |
445 | #[inline ] |
446 | #[doc (alias = "get_type" )] |
447 | pub fn type_(&self) -> Type { |
448 | self.type_ |
449 | } |
450 | |
451 | // rustdoc-stripper-ignore-next |
452 | /// Returns a pointer to the native parent class. |
453 | /// |
454 | /// This is used for chaining up to the parent class' implementation |
455 | /// of virtual methods. |
456 | #[doc (alias = "get_parent_class" )] |
457 | #[inline ] |
458 | pub fn parent_class(&self) -> ffi::gpointer { |
459 | debug_assert!(!self.parent_class.is_null()); |
460 | self.parent_class |
461 | } |
462 | |
463 | // rustdoc-stripper-ignore-next |
464 | /// Returns a pointer to the native parent interface struct for interface `type_`. |
465 | /// |
466 | /// This is used for chaining up to the parent interface's implementation |
467 | /// of virtual methods. |
468 | /// |
469 | /// # Panics |
470 | /// |
471 | /// This function panics if the type to which the `TypeData` belongs does not implement the |
472 | /// given interface or was not registered yet. |
473 | #[doc (alias = "get_parent_interface" )] |
474 | pub fn parent_interface<I: crate::object::IsInterface>(&self) -> ffi::gpointer { |
475 | match self.parent_ifaces { |
476 | None => unreachable!("No parent interfaces" ), |
477 | Some(ref parent_ifaces) => *parent_ifaces |
478 | .get(&I::static_type()) |
479 | .expect("Parent interface not found" ), |
480 | } |
481 | } |
482 | |
483 | // rustdoc-stripper-ignore-next |
484 | /// Returns a pointer to the class implementation specific data. |
485 | /// |
486 | /// This is used for class implementations to store additional data. |
487 | #[doc (alias = "get_class_data" )] |
488 | pub fn class_data<T: Any + Send + Sync + 'static>(&self, type_: Type) -> Option<&T> { |
489 | match self.class_data { |
490 | None => None, |
491 | Some(ref data) => data.get(&type_).and_then(|ptr| ptr.downcast_ref()), |
492 | } |
493 | } |
494 | |
495 | // rustdoc-stripper-ignore-next |
496 | /// Gets a mutable reference of the class implementation specific data. |
497 | /// |
498 | /// # Safety |
499 | /// |
500 | /// This can only be used while the type is being initialized. |
501 | #[doc (alias = "get_class_data_mut" )] |
502 | pub unsafe fn class_data_mut<T: Any + Send + Sync + 'static>( |
503 | &mut self, |
504 | type_: Type, |
505 | ) -> Option<&mut T> { |
506 | match self.class_data { |
507 | None => None, |
508 | Some(ref mut data) => data.get_mut(&type_).and_then(|v| v.downcast_mut()), |
509 | } |
510 | } |
511 | |
512 | // rustdoc-stripper-ignore-next |
513 | /// Sets class specific implementation data. |
514 | /// |
515 | /// # Safety |
516 | /// |
517 | /// This can only be used while the type is being initialized. |
518 | /// |
519 | /// # Panics |
520 | /// |
521 | /// If the class_data already contains a data for the specified `type_`. |
522 | pub unsafe fn set_class_data<T: Any + Send + Sync + 'static>(&mut self, type_: Type, data: T) { |
523 | if self.class_data.is_none() { |
524 | self.class_data = Some(BTreeMap::default()); |
525 | } |
526 | |
527 | if let Some(ref mut class_data) = self.class_data { |
528 | assert!( |
529 | class_data.get(&type_).is_none(), |
530 | "The class_data already contains a key for {type_}" , |
531 | ); |
532 | |
533 | class_data.insert(type_, Box::new(data)); |
534 | } |
535 | } |
536 | |
537 | // rustdoc-stripper-ignore-next |
538 | /// Returns the offset of the private implementation struct in bytes relative to the beginning |
539 | /// of the instance struct. |
540 | #[doc (alias = "get_impl_offset" )] |
541 | #[inline ] |
542 | pub fn impl_offset(&self) -> isize { |
543 | self.private_offset + self.private_imp_offset |
544 | } |
545 | } |
546 | |
547 | // rustdoc-stripper-ignore-next |
548 | /// Type methods required for an [`ObjectSubclass`] implementation. |
549 | /// |
550 | /// This is usually generated by the [`#[object_subclass]`](crate::object_subclass) attribute macro. |
551 | pub unsafe trait ObjectSubclassType { |
552 | // rustdoc-stripper-ignore-next |
553 | /// Storage for the type-specific data used during registration. |
554 | fn type_data() -> ptr::NonNull<TypeData>; |
555 | |
556 | // rustdoc-stripper-ignore-next |
557 | /// Returns the `glib::Type` ID of the subclass. |
558 | /// |
559 | /// This will register the type with the type system on the first call. |
560 | #[doc (alias = "get_type" )] |
561 | fn type_() -> Type; |
562 | } |
563 | |
564 | pub const INIT_TYPE_DATA: TypeData = TypeData { |
565 | type_: Type::INVALID, |
566 | parent_class: ::std::ptr::null_mut(), |
567 | parent_ifaces: None, |
568 | class_data: None, |
569 | private_offset: 0, |
570 | private_imp_offset: 0, |
571 | }; |
572 | |
573 | // rustdoc-stripper-ignore-next |
574 | /// The central trait for subclassing a `GObject` type. |
575 | /// |
576 | /// Links together the type name, parent type and the instance and |
577 | /// class structs for type registration and allows subclasses to |
578 | /// hook into various steps of the type registration and initialization. |
579 | /// |
580 | /// See [`register_type`] for registering an implementation of this trait |
581 | /// with the type system. |
582 | /// |
583 | /// [`register_type`]: fn.register_type.html |
584 | pub trait ObjectSubclass: ObjectSubclassType + Sized + 'static { |
585 | // rustdoc-stripper-ignore-next |
586 | /// `GObject` type name. |
587 | /// |
588 | /// This must be unique in the whole process. |
589 | const NAME: &'static str; |
590 | |
591 | // rustdoc-stripper-ignore-next |
592 | /// If this subclass is an abstract class or not. |
593 | /// |
594 | /// By default, all subclasses are non-abstract types but setting this to `true` will create an |
595 | /// abstract class instead. |
596 | /// |
597 | /// Abstract classes can't be instantiated and require a non-abstract subclass. |
598 | /// |
599 | /// Optional. |
600 | const ABSTRACT: bool = false; |
601 | |
602 | // rustdoc-stripper-ignore-next |
603 | /// Wrapper around this subclass defined with `wrapper!` |
604 | type Type: ObjectType |
605 | + ObjectSubclassIs<Subclass = Self> |
606 | + FromGlibPtrFull<*mut <Self::Type as ObjectType>::GlibType> |
607 | + FromGlibPtrBorrow<*mut <Self::Type as ObjectType>::GlibType> |
608 | + FromGlibPtrNone<*mut <Self::Type as ObjectType>::GlibType>; |
609 | |
610 | // rustdoc-stripper-ignore-next |
611 | /// Parent Rust type to inherit from. |
612 | type ParentType: IsSubclassable<Self> |
613 | + FromGlibPtrFull<*mut <Self::ParentType as ObjectType>::GlibType> |
614 | + FromGlibPtrBorrow<*mut <Self::ParentType as ObjectType>::GlibType> |
615 | + FromGlibPtrNone<*mut <Self::ParentType as ObjectType>::GlibType>; |
616 | |
617 | // rustdoc-stripper-ignore-next |
618 | /// List of interfaces implemented by this type. |
619 | type Interfaces: InterfaceList<Self>; |
620 | |
621 | // rustdoc-stripper-ignore-next |
622 | /// The C instance struct. |
623 | /// |
624 | /// See [`basic::InstanceStruct`] for an basic instance struct that should be |
625 | /// used in most cases. |
626 | /// |
627 | /// [`basic::InstanceStruct`]: ../basic/struct.InstanceStruct.html |
628 | // TODO: Should default to basic::InstanceStruct<Self> once associated |
629 | // type defaults are stabilized https://github.com/rust-lang/rust/issues/29661 |
630 | type Instance: InstanceStruct<Type = Self>; |
631 | |
632 | // rustdoc-stripper-ignore-next |
633 | /// The C class struct. |
634 | /// |
635 | /// See [`basic::ClassStruct`] for an basic instance struct that should be |
636 | /// used in most cases. |
637 | /// |
638 | /// [`basic::ClassStruct`]: ../basic/struct.ClassStruct.html |
639 | // TODO: Should default to basic::ClassStruct<Self> once associated |
640 | // type defaults are stabilized https://github.com/rust-lang/rust/issues/29661 |
641 | type Class: ClassStruct<Type = Self>; |
642 | |
643 | // rustdoc-stripper-ignore-next |
644 | /// Additional type initialization. |
645 | /// |
646 | /// This is called right after the type was registered and allows |
647 | /// subclasses to do additional type-specific initialization, e.g. |
648 | /// for implementing `GObject` interfaces. |
649 | /// |
650 | /// Optional |
651 | #[inline ] |
652 | fn type_init(_type_: &mut InitializingType<Self>) {} |
653 | |
654 | /// Class initialization. |
655 | /// |
656 | // rustdoc-stripper-ignore-next |
657 | /// This is called after `type_init` and before the first instance |
658 | /// of the subclass is created. Subclasses can use this to do class- |
659 | /// specific initialization, e.g. for registering signals on the class |
660 | /// or calling class methods. |
661 | /// |
662 | /// Optional |
663 | #[inline ] |
664 | fn class_init(_klass: &mut Self::Class) {} |
665 | |
666 | // rustdoc-stripper-ignore-next |
667 | /// Constructor. |
668 | /// |
669 | /// This is called during object instantiation before further subclasses |
670 | /// are initialized, and should return a new instance of the subclass |
671 | /// private struct. |
672 | /// |
673 | /// Optional, either implement this or `with_class()`. |
674 | fn new() -> Self { |
675 | unimplemented!(); |
676 | } |
677 | |
678 | // rustdoc-stripper-ignore-next |
679 | /// Constructor. |
680 | /// |
681 | /// This is called during object instantiation before further subclasses |
682 | /// are initialized, and should return a new instance of the subclass |
683 | /// private struct. |
684 | /// |
685 | /// Different to `new()` above it also gets the class of this type passed |
686 | /// to itself for providing additional context. |
687 | /// |
688 | /// Optional, either implement this or `new()`. |
689 | #[inline ] |
690 | fn with_class(_klass: &Self::Class) -> Self { |
691 | Self::new() |
692 | } |
693 | |
694 | // rustdoc-stripper-ignore-next |
695 | /// Performs additional instance initialization. |
696 | /// |
697 | /// Called just after `with_class()`. At this point the initialization has not completed yet, so |
698 | /// only a limited set of operations is safe (see `InitializingObject`). |
699 | #[inline ] |
700 | fn instance_init(_obj: &InitializingObject<Self>) {} |
701 | } |
702 | |
703 | // rustdoc-stripper-ignore-next |
704 | /// Extension methods for all `ObjectSubclass` impls. |
705 | pub trait ObjectSubclassExt: ObjectSubclass { |
706 | // rustdoc-stripper-ignore-next |
707 | /// Returns the corresponding object instance. |
708 | #[doc (alias = "get_instance" )] |
709 | #[deprecated = "Use obj() instead" ] |
710 | fn instance(&self) -> crate::BorrowedObject<Self::Type>; |
711 | |
712 | // rustdoc-stripper-ignore-next |
713 | /// Returns the implementation from an instance. |
714 | #[deprecated = "Use from_obj() instead" ] |
715 | fn from_instance(obj: &Self::Type) -> &Self; |
716 | |
717 | // rustdoc-stripper-ignore-next |
718 | /// Returns the corresponding object instance. |
719 | /// |
720 | /// Shorter alias for `instance()`. |
721 | #[doc (alias = "get_instance" )] |
722 | fn obj(&self) -> crate::BorrowedObject<Self::Type>; |
723 | |
724 | // rustdoc-stripper-ignore-next |
725 | /// Returns the implementation from an instance. |
726 | /// |
727 | /// Shorter alias for `from_instance()`. |
728 | fn from_obj(obj: &Self::Type) -> &Self; |
729 | |
730 | // rustdoc-stripper-ignore-next |
731 | /// Returns a new reference-counted wrapper around `self`. |
732 | fn ref_counted(&self) -> super::ObjectImplRef<Self>; |
733 | |
734 | // rustdoc-stripper-ignore-next |
735 | /// Returns a pointer to the instance implementation specific data. |
736 | /// |
737 | /// This is used for the subclassing infrastructure to store additional instance data. |
738 | #[doc (alias = "get_instance_data" )] |
739 | fn instance_data<U: Any + Send + Sync + 'static>(&self, type_: Type) -> Option<&U>; |
740 | } |
741 | |
742 | impl<T: ObjectSubclass> ObjectSubclassExt for T { |
743 | #[inline ] |
744 | fn instance(&self) -> crate::BorrowedObject<Self::Type> { |
745 | self.obj() |
746 | } |
747 | |
748 | #[inline ] |
749 | fn from_instance(obj: &Self::Type) -> &Self { |
750 | Self::from_obj(obj) |
751 | } |
752 | |
753 | #[inline ] |
754 | fn obj(&self) -> crate::BorrowedObject<Self::Type> { |
755 | unsafe { |
756 | let data = Self::type_data(); |
757 | let type_ = data.as_ref().type_(); |
758 | debug_assert!(type_.is_valid()); |
759 | |
760 | let offset = -data.as_ref().impl_offset(); |
761 | let ptr = |
762 | offset_ptr_by_bytes::<Self, <Self::Type as ObjectType>::GlibType>(self, offset); |
763 | |
764 | // The object might just be finalized, and in that case it's unsafe to access |
765 | // it and use any API on it. This can only happen from inside the Drop impl |
766 | // of Self. |
767 | debug_assert_ne!((*(ptr as *const gobject_ffi::GObject)).ref_count, 0); |
768 | |
769 | crate::BorrowedObject::new(mut_override(ptr)) |
770 | } |
771 | } |
772 | |
773 | #[inline ] |
774 | fn from_obj(obj: &Self::Type) -> &Self { |
775 | unsafe { |
776 | let ptr = obj.as_ptr() as *const Self::Instance; |
777 | (*ptr).imp() |
778 | } |
779 | } |
780 | |
781 | #[inline ] |
782 | fn ref_counted(&self) -> super::ObjectImplRef<Self> { |
783 | super::ObjectImplRef::new(self) |
784 | } |
785 | |
786 | #[inline ] |
787 | fn instance_data<U: Any + Send + Sync + 'static>(&self, type_: Type) -> Option<&U> { |
788 | unsafe { |
789 | let type_data = Self::type_data(); |
790 | let self_type_ = type_data.as_ref().type_(); |
791 | debug_assert!(self_type_.is_valid()); |
792 | |
793 | let offset = -type_data.as_ref().private_imp_offset; |
794 | let ptr = offset_ptr_by_bytes::<Self, PrivateStruct<Self>>(self, offset); |
795 | let priv_ = &*ptr; |
796 | |
797 | match priv_.instance_data { |
798 | None => None, |
799 | Some(ref data) => data.get(&type_).and_then(|ptr| ptr.downcast_ref()), |
800 | } |
801 | } |
802 | } |
803 | } |
804 | |
805 | // rustdoc-stripper-ignore-next |
806 | /// Helper trait for macros to access a subclass or its wrapper. |
807 | pub trait FromObject { |
808 | type FromObjectType; |
809 | fn from_object(obj: &Self::FromObjectType) -> &Self; |
810 | } |
811 | |
812 | // rustdoc-stripper-ignore-next |
813 | /// An object that is currently being initialized. |
814 | /// |
815 | /// Binding crates should use traits for adding methods to this struct. Only methods explicitly safe |
816 | /// to call during `instance_init()` should be added. |
817 | pub struct InitializingObject<T: ObjectSubclass>(Borrowed<T::Type>); |
818 | |
819 | impl<T: ObjectSubclass> InitializingObject<T> { |
820 | // rustdoc-stripper-ignore-next |
821 | /// Returns a reference to the object. |
822 | /// |
823 | /// # Safety |
824 | /// |
825 | /// The returned object has not been completely initialized at this point. Use of the object |
826 | /// should be restricted to methods that are explicitly documented to be safe to call during |
827 | /// `instance_init()`. |
828 | #[inline ] |
829 | pub unsafe fn as_ref(&self) -> &T::Type { |
830 | &self.0 |
831 | } |
832 | |
833 | // rustdoc-stripper-ignore-next |
834 | /// Returns a pointer to the object. |
835 | /// |
836 | /// # Safety |
837 | /// |
838 | /// The returned object has not been completely initialized at this point. Use of the object |
839 | /// should be restricted to methods that are explicitly documented to be safe to call during |
840 | /// `instance_init()`. |
841 | #[inline ] |
842 | pub fn as_ptr(&self) -> *mut T::Type { |
843 | self.0.as_ptr() as *const T::Type as *mut T::Type |
844 | } |
845 | |
846 | // rustdoc-stripper-ignore-next |
847 | /// Sets instance specific implementation data. |
848 | /// |
849 | /// # Panics |
850 | /// |
851 | /// If the instance_data already contains a data for the specified `type_`. |
852 | pub fn set_instance_data<U: Any + Send + Sync + 'static>(&mut self, type_: Type, data: U) { |
853 | unsafe { |
854 | let type_data = T::type_data(); |
855 | let self_type_ = type_data.as_ref().type_(); |
856 | debug_assert!(self_type_.is_valid()); |
857 | |
858 | let offset = type_data.as_ref().private_offset; |
859 | |
860 | let ptr = offset_ptr_by_bytes_mut::< |
861 | <<T as ObjectSubclass>::Type as ObjectType>::GlibType, |
862 | PrivateStruct<T>, |
863 | >(self.0.as_ptr(), offset); |
864 | let priv_ = &mut *ptr; |
865 | |
866 | if priv_.instance_data.is_none() { |
867 | priv_.instance_data = Some(BTreeMap::default()); |
868 | } |
869 | |
870 | if let Some(ref mut instance_data) = priv_.instance_data { |
871 | assert!( |
872 | instance_data.get(&type_).is_none(), |
873 | "The class_data already contains a key for {type_}" , |
874 | ); |
875 | |
876 | instance_data.insert(type_, Box::new(data)); |
877 | } |
878 | } |
879 | } |
880 | } |
881 | |
882 | unsafe extern "C" fn class_init<T: ObjectSubclass>( |
883 | klass: ffi::gpointer, |
884 | _klass_data: ffi::gpointer, |
885 | ) { |
886 | let mut data = T::type_data(); |
887 | |
888 | // We have to update the private struct offset once the class is actually |
889 | // being initialized. |
890 | let mut private_offset = data.as_ref().private_offset as i32; |
891 | gobject_ffi::g_type_class_adjust_private_offset(klass, &mut private_offset); |
892 | data.as_mut().private_offset = private_offset as isize; |
893 | |
894 | // Set trampolines for the basic GObject virtual methods. |
895 | { |
896 | let gobject_klass = &mut *(klass as *mut gobject_ffi::GObjectClass); |
897 | |
898 | gobject_klass.finalize = Some(finalize::<T>); |
899 | } |
900 | |
901 | // And finally peek the parent class struct (containing the parent class' |
902 | // implementations of virtual methods for chaining up), and call the subclass' |
903 | // class initialization function. |
904 | { |
905 | let klass = &mut *(klass as *mut T::Class); |
906 | let parent_class = gobject_ffi::g_type_class_peek_parent(klass as *mut _ as ffi::gpointer) |
907 | as *mut <T::ParentType as ObjectType>::GlibClassType; |
908 | debug_assert!(!parent_class.is_null()); |
909 | |
910 | data.as_mut().parent_class = parent_class as ffi::gpointer; |
911 | |
912 | klass.class_init(); |
913 | T::class_init(klass); |
914 | } |
915 | } |
916 | |
917 | unsafe extern "C" fn instance_init<T: ObjectSubclass>( |
918 | obj: *mut gobject_ffi::GTypeInstance, |
919 | klass: ffi::gpointer, |
920 | ) { |
921 | // Get offset to the storage of our private struct, create it |
922 | // and actually store it in that place. |
923 | let mut data = T::type_data(); |
924 | let private_offset = data.as_mut().private_offset; |
925 | let priv_ptr = offset_ptr_by_bytes_mut::<gobject_ffi::GTypeInstance, PrivateStruct<T>>( |
926 | obj, |
927 | private_offset, |
928 | ); |
929 | |
930 | assert!( |
931 | priv_ptr as usize & (mem::align_of::<PrivateStruct<T>>() - 1) == 0, |
932 | "Private instance data has higher alignment requirements ( {}) than \ |
933 | the allocation from GLib. If alignment of more than {} bytes \ |
934 | is required, store the corresponding data separately on the heap." , |
935 | mem::align_of::<PrivateStruct<T>>(), |
936 | 2 * mem::size_of::<usize>(), |
937 | ); |
938 | |
939 | let klass = &*(klass as *const T::Class); |
940 | |
941 | let imp = T::with_class(klass); |
942 | ptr::write( |
943 | priv_ptr, |
944 | PrivateStruct { |
945 | imp, |
946 | instance_data: None, |
947 | }, |
948 | ); |
949 | |
950 | // Any additional instance initialization. |
951 | T::Instance::instance_init(&mut *(obj as *mut _)); |
952 | |
953 | let obj = from_glib_borrow::<_, Object>(obj.cast()); |
954 | let obj = Borrowed::new(obj.into_inner().unsafe_cast()); |
955 | let mut obj = InitializingObject(obj); |
956 | |
957 | T::Interfaces::instance_init(&mut obj); |
958 | T::instance_init(&obj); |
959 | } |
960 | |
961 | unsafe extern "C" fn finalize<T: ObjectSubclass>(obj: *mut gobject_ffi::GObject) { |
962 | // Retrieve the private struct and drop it for freeing all associated memory. |
963 | let mut data: NonNull = T::type_data(); |
964 | let private_offset: isize = data.as_mut().private_offset; |
965 | let priv_ptr: *mut PrivateStruct = |
966 | offset_ptr_by_bytes_mut::<gobject_ffi::GObject, PrivateStruct<T>>(ptr:obj, private_offset); |
967 | ptr::drop_in_place(to_drop:ptr::addr_of_mut!((*priv_ptr).imp)); |
968 | ptr::drop_in_place(to_drop:ptr::addr_of_mut!((*priv_ptr).instance_data)); |
969 | |
970 | // Chain up to the parent class' finalize implementation, if any. |
971 | let parent_class: &GObjectClass = &*(data.as_ref().parent_class() as *const gobject_ffi::GObjectClass); |
972 | if let Some(ref func: &unsafe fn(*mut GObject)) = parent_class.finalize { |
973 | func(obj); |
974 | } |
975 | } |
976 | |
977 | // rustdoc-stripper-ignore-next |
978 | /// Register a `glib::Type` ID for `T`. |
979 | /// |
980 | /// This must be called only once and will panic on a second call. |
981 | /// |
982 | /// The [`object_subclass!`] macro will create a `type_()` function around this, which will |
983 | /// ensure that it's only ever called once. |
984 | /// |
985 | /// [`object_subclass!`]: ../../macro.object_subclass.html |
986 | pub fn register_type<T: ObjectSubclass>() -> Type { |
987 | // GLib aligns the type private data to two gsizes, so we can't safely store any type there that |
988 | // requires a bigger alignment. |
989 | assert!( |
990 | mem::align_of::<T>() <= 2 * mem::size_of::<usize>(), |
991 | "Alignment {} of type not supported, bigger than {}" , |
992 | mem::align_of::<T>(), |
993 | 2 * mem::size_of::<usize>(), |
994 | ); |
995 | |
996 | unsafe { |
997 | use std::ffi::CString; |
998 | |
999 | let type_name = CString::new(T::NAME).unwrap(); |
1000 | assert_eq!( |
1001 | gobject_ffi::g_type_from_name(type_name.as_ptr()), |
1002 | gobject_ffi::G_TYPE_INVALID, |
1003 | "Type {} has already been registered" , |
1004 | type_name.to_str().unwrap() |
1005 | ); |
1006 | |
1007 | let type_ = Type::from_glib(gobject_ffi::g_type_register_static_simple( |
1008 | <T::ParentType as StaticType>::static_type().into_glib(), |
1009 | type_name.as_ptr(), |
1010 | mem::size_of::<T::Class>() as u32, |
1011 | Some(class_init::<T>), |
1012 | mem::size_of::<T::Instance>() as u32, |
1013 | Some(instance_init::<T>), |
1014 | if T::ABSTRACT { |
1015 | gobject_ffi::G_TYPE_FLAG_ABSTRACT |
1016 | } else { |
1017 | 0 |
1018 | }, |
1019 | )); |
1020 | assert!(type_.is_valid()); |
1021 | |
1022 | let mut data = T::type_data(); |
1023 | data.as_mut().type_ = type_; |
1024 | |
1025 | let private_offset = gobject_ffi::g_type_add_instance_private( |
1026 | type_.into_glib(), |
1027 | mem::size_of::<PrivateStruct<T>>(), |
1028 | ); |
1029 | data.as_mut().private_offset = private_offset as isize; |
1030 | |
1031 | // Get the offset from PrivateStruct<T> to the imp field in it. This has to go through |
1032 | // some hoops because Rust doesn't have an offsetof operator yet. |
1033 | data.as_mut().private_imp_offset = { |
1034 | // Must not be a dangling pointer so let's create some uninitialized memory |
1035 | let priv_ = mem::MaybeUninit::<PrivateStruct<T>>::uninit(); |
1036 | let ptr = priv_.as_ptr(); |
1037 | let imp_ptr = ptr::addr_of!((*ptr).imp); |
1038 | (imp_ptr as isize) - (ptr as isize) |
1039 | }; |
1040 | |
1041 | let iface_types = T::Interfaces::iface_infos(); |
1042 | for (iface_type, iface_info) in iface_types { |
1043 | gobject_ffi::g_type_add_interface_static(type_.into_glib(), iface_type, &iface_info); |
1044 | } |
1045 | |
1046 | T::type_init(&mut InitializingType::<T>(type_, marker::PhantomData)); |
1047 | |
1048 | type_ |
1049 | } |
1050 | } |
1051 | |
1052 | pub(crate) unsafe fn signal_override_class_handler<F>( |
1053 | name: &str, |
1054 | type_: ffi::GType, |
1055 | class_handler: F, |
1056 | ) where |
1057 | F: Fn(&super::SignalClassHandlerToken, &[Value]) -> Option<Value> + Send + Sync + 'static, |
1058 | { |
1059 | let (signal_id, _) = SignalId::parse_name(name, from_glib(type_), false) |
1060 | .unwrap_or_else(|| panic!("Signal ' {name}' not found" )); |
1061 | |
1062 | let query = signal_id.query(); |
1063 | let return_type = query.return_type(); |
1064 | |
1065 | let class_handler = Closure::new(move |values| { |
1066 | let instance = gobject_ffi::g_value_get_object(values[0].to_glib_none().0); |
1067 | let res = class_handler( |
1068 | &super::SignalClassHandlerToken( |
1069 | instance as *mut _, |
1070 | return_type.into(), |
1071 | values.as_ptr(), |
1072 | ), |
1073 | values, |
1074 | ); |
1075 | |
1076 | if return_type == Type::UNIT { |
1077 | if let Some(ref v) = res { |
1078 | panic!( |
1079 | "Signal has no return value but class handler returned a value of type {}" , |
1080 | v.type_() |
1081 | ); |
1082 | } |
1083 | } else { |
1084 | match res { |
1085 | None => { |
1086 | panic!("Signal has a return value but class handler returned none" ); |
1087 | } |
1088 | Some(ref v) => { |
1089 | assert!( |
1090 | v.type_().is_a(return_type.into()), |
1091 | "Signal has a return type of {} but class handler returned {}" , |
1092 | Type::from(return_type), |
1093 | v.type_() |
1094 | ); |
1095 | } |
1096 | } |
1097 | } |
1098 | |
1099 | res |
1100 | }); |
1101 | |
1102 | gobject_ffi::g_signal_override_class_closure( |
1103 | signal_id.into_glib(), |
1104 | type_, |
1105 | class_handler.to_glib_none().0, |
1106 | ); |
1107 | } |
1108 | |
1109 | pub(crate) unsafe fn signal_chain_from_overridden( |
1110 | instance: *mut gobject_ffi::GTypeInstance, |
1111 | token: &super::SignalClassHandlerToken, |
1112 | values: &[Value], |
1113 | ) -> Option<Value> { |
1114 | assert_eq!(instance, token.0); |
1115 | assert_eq!( |
1116 | values.as_ptr(), |
1117 | token.2, |
1118 | "Arguments must be forwarded without changes when chaining up" |
1119 | ); |
1120 | |
1121 | let mut result: Value = Value::from_type_unchecked(type_:token.1); |
1122 | gobject_ffi::g_signal_chain_from_overridden( |
1123 | instance_and_params:values.as_ptr() as *mut Value as *mut gobject_ffi::GValue, |
1124 | return_value:result.to_glib_none_mut().0, |
1125 | ); |
1126 | Some(result).filter(|r: &Value| r.type_().is_valid() && r.type_() != Type::UNIT) |
1127 | } |
1128 | |