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