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