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