Skip to main content

glib/subclass/
types.rs

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