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
6use std::{any::Any, collections::BTreeMap, marker, mem, ptr};
7
8use super::{interface::ObjectInterface, SignalId};
9use 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)]
22pub struct InitializingType<T>(pub(crate) Type, pub(crate) marker::PhantomData<*const T>);
23
24impl<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.
35struct 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
51pub 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.
77pub 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]
102fn 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]
124fn 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
136unsafe 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.
155pub 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
161impl<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
179pub 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.
202pub 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)]
228pub 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
233impl<T: ObjectSubclass, U: IsSubclassable<T> + ParentClassIs> IsSubclassableDefault<T> for U
234where
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
248impl<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
256pub 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
265impl<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.
288pub unsafe trait InterfaceStruct: Sized + 'static
289where
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.
306pub 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
321unsafe 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.
347pub 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
357impl<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
366impl<T: ObjectSubclass, A: IsImplementable<T>> InterfaceList<T> for (A,)
367where
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).
388macro_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).
405macro_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
436interface_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.
439pub 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
448unsafe impl Send for TypeData {}
449unsafe impl Sync for TypeData {}
450
451impl 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
567impl 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.
577pub 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
601pub 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.
740pub 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
777impl<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.
842pub 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.
852pub struct InitializingObject<T: ObjectSubclass>(Borrowed<T::Type>);
853
854impl<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
917unsafe 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
952unsafe 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
996unsafe 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
1021pub 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
1126pub 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
1210pub(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
1267pub(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