Skip to main content

glib/subclass/
types.rs

1// Take a look at the license at the top of the repository in the LICENSE file.
2
3// rustdoc-stripper-ignore-next
4//! Module that contains the basic infrastructure for subclassing `GObject`.
5
6use std::{any::Any, collections::BTreeMap, marker, mem, ptr};
7
8use super::{SignalId, interface::ObjectInterface};
9use crate::{
10    Closure, InterfaceInfo, Object, Type, TypeFlags, TypeInfo, Value, ffi, gobject_ffi,
11    object::{IsClass, IsInterface, ObjectSubclassIs, ParentClassIs},
12    prelude::*,
13    translate::*,
14};
15
16// rustdoc-stripper-ignore-next
17/// A newly registered `glib::Type` that is currently still being initialized.
18///
19/// This allows running additional type-setup functions.
20#[derive(Debug, PartialEq, Eq)]
21pub struct InitializingType<T>(pub(crate) Type, pub(crate) marker::PhantomData<*const T>);
22
23impl<T> IntoGlib for InitializingType<T> {
24    type GlibType = ffi::GType;
25
26    #[inline]
27    fn into_glib(self) -> ffi::GType {
28        self.0.into_glib()
29    }
30}
31
32// rustdoc-stripper-ignore-next
33/// Struct used for the instance private data of the GObject.
34struct PrivateStruct<T: ObjectSubclass> {
35    imp: T,
36    instance_data: Option<BTreeMap<Type, Box<dyn Any + Send + Sync>>>,
37}
38
39// rustdoc-stripper-ignore-next
40/// Trait implemented by structs that implement a `GObject` C instance struct.
41///
42/// The struct must be `#[repr(C)]` and have the parent type's instance struct
43/// as the first field.
44///
45/// See [`basic::InstanceStruct`] for a basic implementation of this that can
46/// be used most of the time and should only not be used if additional fields are
47/// required in the instance struct.
48///
49/// [`basic::InstanceStruct`]: ../basic/struct.InstanceStruct.html
50pub unsafe trait InstanceStruct: Sized + 'static {
51    // rustdoc-stripper-ignore-next
52    /// Corresponding object subclass type for this instance struct.
53    type Type: ObjectSubclass;
54
55    // rustdoc-stripper-ignore-next
56    /// Instance specific initialization.
57    ///
58    /// This is automatically called during instance initialization and must call `instance_init()`
59    /// of the parent class.
60    #[inline]
61    fn instance_init(&mut self) {
62        unsafe {
63            let obj = from_glib_borrow::<_, Object>(self as *mut _ as *mut gobject_ffi::GObject);
64            let obj = Borrowed::new(obj.into_inner().unsafe_cast());
65            let mut obj = InitializingObject(obj);
66
67            <<Self::Type as ObjectSubclass>::ParentType as IsSubclassable<Self::Type>>::instance_init(
68                &mut obj,
69            );
70        }
71    }
72}
73
74// rustdoc-stripper-ignore-next
75/// Trait implemented by any type implementing `InstanceStruct` to return the implementation, private Rust struct.
76pub unsafe trait InstanceStructExt: InstanceStruct {
77    // rustdoc-stripper-ignore-next
78    /// Returns the implementation for from this instance struct, that
79    /// is the implementor of [`ObjectImpl`] or subtraits.
80    ///
81    /// [`ObjectImpl`]: ../object/trait.ObjectImpl.html
82    #[doc(alias = "get_impl")]
83    fn imp(&self) -> &Self::Type;
84
85    // rustdoc-stripper-ignore-next
86    /// Returns the class struct for this specific instance.
87    #[doc(alias = "get_class")]
88    fn class(&self) -> &<Self::Type as ObjectSubclass>::Class;
89}
90
91// rustdoc-stripper-ignore-next
92/// Offset `ptr` by `offset` *bytes* and cast the result to `*const U`.
93///
94/// The result must be a correctly aligned pointer to a valid value of type `U`.
95///
96/// # Panics:
97///
98/// This function panics if debug assertions are enabled if adding `offset` causes `ptr` to
99/// overflow or if the resulting pointer is not correctly aligned.
100#[inline]
101fn offset_ptr_by_bytes<T, U>(ptr: *const T, offset: isize) -> *const U {
102    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    /// Allow name conflicts for this class.
622    ///
623    /// By default, trying to register a type with a name that was registered before will panic. If
624    /// this is set to `true` then a new name will be selected by appending a counter.
625    ///
626    /// This is useful for defining new types in Rust library crates that might be linked multiple
627    /// times in the same process.
628    ///
629    /// A consequence of setting this to `true` is that it's not guaranteed that
630    /// `glib::Type::from_name(Self::NAME).unwrap() == Self::type_()`.
631    ///
632    /// Note that this is not allowed for dynamic types. If a dynamic type is registered and a type
633    /// with that name exists already, it is assumed that they're the same.
634    ///
635    /// Optional.
636    const ALLOW_NAME_CONFLICT: bool = false;
637
638    // rustdoc-stripper-ignore-next
639    /// Wrapper around this subclass defined with `wrapper!`
640    type Type: ObjectType
641        + ObjectSubclassIs<Subclass = Self>
642        + FromGlibPtrFull<*mut <Self::Type as ObjectType>::GlibType>
643        + FromGlibPtrBorrow<*mut <Self::Type as ObjectType>::GlibType>
644        + FromGlibPtrNone<*mut <Self::Type as ObjectType>::GlibType>;
645
646    // rustdoc-stripper-ignore-next
647    /// Parent Rust type to inherit from.
648    type ParentType: IsSubclassable<Self>
649        + FromGlibPtrFull<*mut <Self::ParentType as ObjectType>::GlibType>
650        + FromGlibPtrBorrow<*mut <Self::ParentType as ObjectType>::GlibType>
651        + FromGlibPtrNone<*mut <Self::ParentType as ObjectType>::GlibType>;
652
653    // rustdoc-stripper-ignore-next
654    /// List of interfaces implemented by this type.
655    type Interfaces: InterfaceList<Self>;
656
657    // rustdoc-stripper-ignore-next
658    /// The C instance struct.
659    ///
660    /// See [`basic::InstanceStruct`] for an basic instance struct that should be
661    /// used in most cases.
662    ///
663    /// [`basic::InstanceStruct`]: ../basic/struct.InstanceStruct.html
664    // TODO: Should default to basic::InstanceStruct<Self> once associated
665    // type defaults are stabilized https://github.com/rust-lang/rust/issues/29661
666    type Instance: InstanceStruct<Type = Self>;
667
668    // rustdoc-stripper-ignore-next
669    /// The C class struct.
670    ///
671    /// See [`basic::ClassStruct`] for an basic class struct that should be
672    /// used in most cases.
673    ///
674    /// [`basic::ClassStruct`]: ../basic/struct.ClassStruct.html
675    // TODO: Should default to basic::ClassStruct<Self> once associated
676    // type defaults are stabilized https://github.com/rust-lang/rust/issues/29661
677    type Class: ClassStruct<Type = Self>;
678
679    // rustdoc-stripper-ignore-next
680    /// Additional type initialization.
681    ///
682    /// This is called right after the type was registered and allows
683    /// subclasses to do additional type-specific initialization, e.g.
684    /// for implementing `GObject` interfaces.
685    ///
686    /// Optional
687    #[inline]
688    fn type_init(_type_: &mut InitializingType<Self>) {}
689
690    /// Class initialization.
691    ///
692    // rustdoc-stripper-ignore-next
693    /// This is called after `type_init` and before the first instance
694    /// of the subclass is created. Subclasses can use this to do class-
695    /// specific initialization, e.g. for registering signals on the class
696    /// or calling class methods.
697    ///
698    /// Optional
699    #[inline]
700    fn class_init(_klass: &mut Self::Class) {}
701
702    // rustdoc-stripper-ignore-next
703    /// Constructor.
704    ///
705    /// This is called during object instantiation before further subclasses
706    /// are initialized, and should return a new instance of the subclass
707    /// private struct.
708    ///
709    /// Optional, either implement this or `with_class()`.
710    fn new() -> Self {
711        unimplemented!();
712    }
713
714    // rustdoc-stripper-ignore-next
715    /// Constructor.
716    ///
717    /// This is called during object instantiation before further subclasses
718    /// are initialized, and should return a new instance of the subclass
719    /// private struct.
720    ///
721    /// Different to `new()` above it also gets the class of this type passed
722    /// to itself for providing additional context.
723    ///
724    /// Optional, either implement this or `new()`.
725    #[inline]
726    fn with_class(_klass: &Self::Class) -> Self {
727        Self::new()
728    }
729
730    // rustdoc-stripper-ignore-next
731    /// Performs additional instance initialization.
732    ///
733    /// Called just after `with_class()`. At this point the initialization has not completed yet, so
734    /// only a limited set of operations is safe (see `InitializingObject`).
735    #[inline]
736    fn instance_init(_obj: &InitializingObject<Self>) {}
737}
738
739// rustdoc-stripper-ignore-next
740/// Extension methods for all `ObjectSubclass` impls.
741pub trait ObjectSubclassExt: ObjectSubclass {
742    // rustdoc-stripper-ignore-next
743    /// Returns the corresponding object instance.
744    ///
745    /// Shorter alias for `instance()`.
746    #[doc(alias = "get_instance")]
747    fn obj(&self) -> crate::BorrowedObject<'_, Self::Type>;
748
749    // rustdoc-stripper-ignore-next
750    /// Returns the implementation from an instance.
751    ///
752    /// Shorter alias for `from_instance()`.
753    fn from_obj(obj: &Self::Type) -> &Self;
754
755    // rustdoc-stripper-ignore-next
756    /// Returns a new reference-counted wrapper around `self`.
757    fn ref_counted(&self) -> super::ObjectImplRef<Self>;
758
759    // rustdoc-stripper-ignore-next
760    /// Returns a pointer to the instance implementation specific data.
761    ///
762    /// This is used for the subclassing infrastructure to store additional instance data.
763    #[doc(alias = "get_instance_data")]
764    fn instance_data<U: Any + Send + Sync + 'static>(&self, type_: Type) -> Option<&U>;
765}
766
767impl<T: ObjectSubclass> ObjectSubclassExt for T {
768    #[inline]
769    fn obj(&self) -> crate::BorrowedObject<'_, Self::Type> {
770        unsafe {
771            let data = Self::type_data();
772            let type_ = data.as_ref().type_();
773            debug_assert!(type_.is_valid());
774
775            let offset = -data.as_ref().impl_offset();
776            let ptr =
777                offset_ptr_by_bytes::<Self, <Self::Type as ObjectType>::GlibType>(self, offset);
778
779            // The object might just be finalized, and in that case it's unsafe to access
780            // it and use any API on it. This can only happen from inside the Drop impl
781            // of Self.
782            debug_assert_ne!((*(ptr as *const gobject_ffi::GObject)).ref_count, 0);
783
784            crate::BorrowedObject::new(mut_override(ptr))
785        }
786    }
787
788    #[inline]
789    fn from_obj(obj: &Self::Type) -> &Self {
790        unsafe {
791            let ptr = obj.as_ptr() as *const Self::Instance;
792            (*ptr).imp()
793        }
794    }
795
796    #[inline]
797    fn ref_counted(&self) -> super::ObjectImplRef<Self> {
798        super::ObjectImplRef::new(self)
799    }
800
801    #[inline]
802    fn instance_data<U: Any + Send + Sync + 'static>(&self, type_: Type) -> Option<&U> {
803        unsafe {
804            let type_data = Self::type_data();
805            let self_type_ = type_data.as_ref().type_();
806            debug_assert!(self_type_.is_valid());
807
808            let offset = -type_data.as_ref().private_imp_offset;
809            let ptr = offset_ptr_by_bytes::<Self, PrivateStruct<Self>>(self, offset);
810            let priv_ = &*ptr;
811
812            match priv_.instance_data {
813                None => None,
814                Some(ref data) => data.get(&type_).and_then(|ptr| ptr.downcast_ref()),
815            }
816        }
817    }
818}
819
820// rustdoc-stripper-ignore-next
821/// Helper trait for macros to access a subclass or its wrapper.
822pub trait FromObject {
823    type FromObjectType;
824    fn from_object(obj: &Self::FromObjectType) -> &Self;
825}
826
827// rustdoc-stripper-ignore-next
828/// An object that is currently being initialized.
829///
830/// Binding crates should use traits for adding methods to this struct. Only methods explicitly safe
831/// to call during `instance_init()` should be added.
832pub struct InitializingObject<T: ObjectSubclass>(Borrowed<T::Type>);
833
834impl<T: ObjectSubclass> InitializingObject<T> {
835    // rustdoc-stripper-ignore-next
836    /// Returns a reference to the object.
837    ///
838    /// # Safety
839    ///
840    /// The returned object has not been completely initialized at this point. Use of the object
841    /// should be restricted to methods that are explicitly documented to be safe to call during
842    /// `instance_init()`.
843    #[inline]
844    pub unsafe fn as_ref(&self) -> &T::Type {
845        &self.0
846    }
847
848    // rustdoc-stripper-ignore-next
849    /// Returns a pointer to the object.
850    ///
851    /// # Safety
852    ///
853    /// The returned object has not been completely initialized at this point. Use of the object
854    /// should be restricted to methods that are explicitly documented to be safe to call during
855    /// `instance_init()`.
856    #[inline]
857    pub fn as_ptr(&self) -> *mut T::Type {
858        self.0.as_ptr() as *const T::Type as *mut T::Type
859    }
860
861    // rustdoc-stripper-ignore-next
862    /// Sets instance specific implementation data.
863    ///
864    /// # Panics
865    ///
866    /// If the instance_data already contains a data for the specified `type_`.
867    pub fn set_instance_data<U: Any + Send + Sync + 'static>(&mut self, type_: Type, data: U) {
868        unsafe {
869            let type_data = T::type_data();
870            let self_type_ = type_data.as_ref().type_();
871            debug_assert!(self_type_.is_valid());
872
873            let offset = type_data.as_ref().private_offset;
874
875            let ptr = offset_ptr_by_bytes_mut::<
876                <<T as ObjectSubclass>::Type as ObjectType>::GlibType,
877                PrivateStruct<T>,
878            >(self.0.as_ptr(), offset);
879            let priv_ = &mut *ptr;
880
881            if priv_.instance_data.is_none() {
882                priv_.instance_data = Some(BTreeMap::default());
883            }
884
885            if let Some(ref mut instance_data) = priv_.instance_data {
886                assert!(
887                    instance_data.get(&type_).is_none(),
888                    "The class_data already contains a key for {type_}",
889                );
890
891                instance_data.insert(type_, Box::new(data));
892            }
893        }
894    }
895}
896
897unsafe extern "C" fn class_init<T: ObjectSubclass>(
898    klass: ffi::gpointer,
899    _klass_data: ffi::gpointer,
900) {
901    unsafe {
902        let mut data = T::type_data();
903
904        // We have to update the private struct offset once the class is actually
905        // being initialized.
906        let mut private_offset = data.as_ref().private_offset as i32;
907        gobject_ffi::g_type_class_adjust_private_offset(klass, &mut private_offset);
908        data.as_mut().private_offset = private_offset as isize;
909
910        // Set trampolines for the basic GObject virtual methods.
911        {
912            let gobject_klass = &mut *(klass as *mut gobject_ffi::GObjectClass);
913
914            gobject_klass.finalize = Some(finalize::<T>);
915        }
916
917        // And finally peek the parent class struct (containing the parent class'
918        // implementations of virtual methods for chaining up), and call the subclass'
919        // class initialization function.
920        {
921            let klass = &mut *(klass as *mut T::Class);
922            let parent_class =
923                gobject_ffi::g_type_class_peek_parent(klass as *mut _ as ffi::gpointer)
924                    as *mut <T::ParentType as ObjectType>::GlibClassType;
925            debug_assert!(!parent_class.is_null());
926
927            data.as_mut().parent_class = parent_class as ffi::gpointer;
928
929            klass.class_init();
930            T::class_init(klass);
931        }
932    }
933}
934
935unsafe extern "C" fn instance_init<T: ObjectSubclass>(
936    obj: *mut gobject_ffi::GTypeInstance,
937    klass: ffi::gpointer,
938) {
939    unsafe {
940        // Get offset to the storage of our private struct, create it
941        // and actually store it in that place.
942        let mut data = T::type_data();
943        let private_offset = data.as_mut().private_offset;
944        let priv_ptr = offset_ptr_by_bytes_mut::<gobject_ffi::GTypeInstance, PrivateStruct<T>>(
945            obj,
946            private_offset,
947        );
948
949        assert!(
950            (priv_ptr as *const PrivateStruct<T>).is_aligned(),
951            "Private instance data has higher alignment requirements ({}) than \
952         the allocation from GLib. If alignment of more than {} bytes \
953         is required, store the corresponding data separately on the heap.",
954            mem::align_of::<PrivateStruct<T>>(),
955            2 * mem::size_of::<usize>(),
956        );
957
958        let klass = &*(klass as *const T::Class);
959
960        let imp = T::with_class(klass);
961        ptr::write(
962            priv_ptr,
963            PrivateStruct {
964                imp,
965                instance_data: None,
966            },
967        );
968
969        // Any additional instance initialization.
970        T::Instance::instance_init(&mut *(obj as *mut _));
971
972        let obj = from_glib_borrow::<_, Object>(obj.cast());
973        let obj = Borrowed::new(obj.into_inner().unsafe_cast());
974        let mut obj = InitializingObject(obj);
975
976        T::Interfaces::instance_init(&mut obj);
977        T::instance_init(&obj);
978    }
979}
980
981unsafe extern "C" fn finalize<T: ObjectSubclass>(obj: *mut gobject_ffi::GObject) {
982    unsafe {
983        // Retrieve the private struct and drop it for freeing all associated memory.
984        let mut data = T::type_data();
985        let private_offset = data.as_mut().private_offset;
986        let priv_ptr =
987            offset_ptr_by_bytes_mut::<gobject_ffi::GObject, PrivateStruct<T>>(obj, private_offset);
988        ptr::drop_in_place(ptr::addr_of_mut!((*priv_ptr).imp));
989        ptr::drop_in_place(ptr::addr_of_mut!((*priv_ptr).instance_data));
990
991        // Chain up to the parent class' finalize implementation, if any.
992        let parent_class = &*(data.as_ref().parent_class() as *const gobject_ffi::GObjectClass);
993        if let Some(ref func) = parent_class.finalize {
994            func(obj);
995        }
996    }
997}
998
999// rustdoc-stripper-ignore-next
1000/// Register a `glib::Type` ID for `T`.
1001///
1002/// This must be called only once and will panic on a second call.
1003///
1004/// The [`object_subclass!`] macro will create a `type_()` function around this, which will
1005/// ensure that it's only ever called once.
1006///
1007/// [`object_subclass!`]: ../../macro.object_subclass.html
1008pub fn register_type<T: ObjectSubclass>() -> Type {
1009    // GLib aligns the type private data to two gsizes, so we can't safely store any type there that
1010    // requires a bigger alignment.
1011    assert!(
1012        mem::align_of::<T>() <= 2 * mem::size_of::<usize>(),
1013        "Alignment {} of type not supported, bigger than {}",
1014        mem::align_of::<T>(),
1015        2 * mem::size_of::<usize>(),
1016    );
1017
1018    unsafe {
1019        use std::ffi::CString;
1020
1021        let type_name = if T::ALLOW_NAME_CONFLICT {
1022            let mut i = 0;
1023            loop {
1024                let type_name = CString::new(if i == 0 {
1025                    T::NAME.to_string()
1026                } else {
1027                    format!("{}-{}", T::NAME, i)
1028                })
1029                .unwrap();
1030                if gobject_ffi::g_type_from_name(type_name.as_ptr()) == gobject_ffi::G_TYPE_INVALID
1031                {
1032                    break type_name;
1033                }
1034                i += 1;
1035            }
1036        } else {
1037            let type_name = CString::new(T::NAME).unwrap();
1038            assert_eq!(
1039                gobject_ffi::g_type_from_name(type_name.as_ptr()),
1040                gobject_ffi::G_TYPE_INVALID,
1041                "Type {} has already been registered",
1042                type_name.to_str().unwrap()
1043            );
1044
1045            type_name
1046        };
1047
1048        let type_ = Type::from_glib(gobject_ffi::g_type_register_static_simple(
1049            <T::ParentType as StaticType>::static_type().into_glib(),
1050            type_name.as_ptr(),
1051            mem::size_of::<T::Class>() as u32,
1052            Some(class_init::<T>),
1053            mem::size_of::<T::Instance>() as u32,
1054            Some(instance_init::<T>),
1055            if T::ABSTRACT {
1056                gobject_ffi::G_TYPE_FLAG_ABSTRACT
1057            } else {
1058                0
1059            },
1060        ));
1061        assert!(type_.is_valid());
1062
1063        let mut data = T::type_data();
1064        data.as_mut().type_ = type_;
1065
1066        let private_offset = gobject_ffi::g_type_add_instance_private(
1067            type_.into_glib(),
1068            mem::size_of::<PrivateStruct<T>>(),
1069        );
1070        data.as_mut().private_offset = private_offset as isize;
1071        data.as_mut().private_imp_offset = mem::offset_of!(PrivateStruct<T>, imp) as isize;
1072
1073        let iface_types = T::Interfaces::iface_infos();
1074        for (iface_type, iface_info) in iface_types {
1075            gobject_ffi::g_type_add_interface_static(
1076                type_.into_glib(),
1077                iface_type.into_glib(),
1078                iface_info.as_ptr(),
1079            );
1080        }
1081
1082        T::type_init(&mut InitializingType::<T>(type_, marker::PhantomData));
1083
1084        type_
1085    }
1086}
1087
1088// rustdoc-stripper-ignore-next
1089/// Registers a `glib::Type` ID for `T` as a dynamic type.
1090///
1091/// An object subclass must be explicitly registered as a dynamic type when the
1092/// system loads the implementation by calling [`TypePluginImpl::use_`] or more
1093/// specifically [`TypeModuleImpl::load`]. Therefore, unlike for object
1094/// subclasses registered as static types, object subclasses registered as
1095/// dynamic types can be registered several times.
1096///
1097/// The [`object_subclass_dynamic!`] macro helper attribute will create
1098/// `register_type()` and `on_implementation_load()` functions around this,
1099/// which will ensure that the function is called when necessary.
1100///
1101/// [`object_subclass_dynamic!`]: ../../../glib_macros/attr.object_subclass.html
1102/// [`TypePluginImpl::use_`]: ../type_plugin/trait.TypePluginImpl.html#method.use_
1103/// [`TypeModuleImpl::load`]: ../type_module/trait.TypeModuleImpl.html#method.load
1104pub fn register_dynamic_type<P: DynamicObjectRegisterExt, T: ObjectSubclass>(
1105    type_plugin: &P,
1106) -> Type {
1107    // GLib aligns the type private data to two gsizes, so we can't safely store any type there that
1108    // requires a bigger alignment.
1109    assert!(
1110        mem::align_of::<T>() <= 2 * mem::size_of::<usize>(),
1111        "Alignment {} of type not supported, bigger than {}",
1112        mem::align_of::<T>(),
1113        2 * mem::size_of::<usize>(),
1114    );
1115
1116    unsafe {
1117        use std::ffi::CString;
1118
1119        let type_name = CString::new(T::NAME).unwrap();
1120
1121        let already_registered =
1122            gobject_ffi::g_type_from_name(type_name.as_ptr()) != gobject_ffi::G_TYPE_INVALID;
1123
1124        let type_info = TypeInfo(gobject_ffi::GTypeInfo {
1125            class_size: mem::size_of::<T::Class>() as u16,
1126            class_init: Some(class_init::<T>),
1127            instance_size: mem::size_of::<T::Instance>() as u16,
1128            instance_init: Some(instance_init::<T>),
1129            ..TypeInfo::default().0
1130        });
1131
1132        // registers the type within the `type_plugin`
1133        let type_ = type_plugin.register_dynamic_type(
1134            <T::ParentType as StaticType>::static_type(),
1135            type_name.to_str().unwrap(),
1136            &type_info,
1137            if T::ABSTRACT {
1138                TypeFlags::ABSTRACT
1139            } else {
1140                TypeFlags::NONE
1141            },
1142        );
1143        assert!(type_.is_valid());
1144
1145        let mut data = T::type_data();
1146        data.as_mut().type_ = type_;
1147
1148        let private_offset = mem::size_of::<PrivateStruct<T>>();
1149        data.as_mut().private_offset = private_offset as isize;
1150        data.as_mut().private_imp_offset = mem::offset_of!(PrivateStruct<T>, imp) as isize;
1151
1152        let plugin_ptr = type_plugin.as_ref().to_glib_none().0;
1153        let iface_types = T::Interfaces::iface_infos();
1154        for (iface_type, iface_info) in iface_types {
1155            match gobject_ffi::g_type_get_plugin(iface_type.into_glib()) {
1156                // if interface type's plugin is null or is different to the `type_plugin`,
1157                // then interface can only be added as if the type was static
1158                iface_plugin if iface_plugin != plugin_ptr => {
1159                    // but adding interface to a static type can be done only once
1160                    if !already_registered {
1161                        gobject_ffi::g_type_add_interface_static(
1162                            type_.into_glib(),
1163                            iface_type.into_glib(),
1164                            iface_info.as_ptr(),
1165                        );
1166                    }
1167                }
1168                // else interface can be added and registered to live in the `type_plugin`
1169                _ => type_plugin.add_dynamic_interface(type_, iface_type, &iface_info),
1170            }
1171        }
1172
1173        T::type_init(&mut InitializingType::<T>(type_, marker::PhantomData));
1174
1175        type_
1176    }
1177}
1178
1179pub(crate) unsafe fn signal_override_class_handler<F>(
1180    name: &str,
1181    type_: ffi::GType,
1182    class_handler: F,
1183) where
1184    F: Fn(&super::SignalClassHandlerToken, &[Value]) -> Option<Value> + Send + Sync + 'static,
1185{
1186    unsafe {
1187        let (signal_id, _) = SignalId::parse_name(name, from_glib(type_), false)
1188            .unwrap_or_else(|| panic!("Signal '{name}' not found"));
1189
1190        let query = signal_id.query();
1191        let return_type = query.return_type();
1192
1193        let class_handler = Closure::new(move |values| {
1194            let instance = gobject_ffi::g_value_get_object(values[0].to_glib_none().0);
1195            let res = class_handler(
1196                &super::SignalClassHandlerToken(
1197                    instance as *mut _,
1198                    return_type.into(),
1199                    values.as_ptr(),
1200                ),
1201                values,
1202            );
1203
1204            if return_type == Type::UNIT {
1205                if let Some(ref v) = res {
1206                    panic!(
1207                        "Signal has no return value but class handler returned a value of type {}",
1208                        v.type_()
1209                    );
1210                }
1211            } else {
1212                match res {
1213                    None => {
1214                        panic!("Signal has a return value but class handler returned none");
1215                    }
1216                    Some(ref v) => {
1217                        assert!(
1218                            v.type_().is_a(return_type.into()),
1219                            "Signal has a return type of {} but class handler returned {}",
1220                            Type::from(return_type),
1221                            v.type_()
1222                        );
1223                    }
1224                }
1225            }
1226
1227            res
1228        });
1229
1230        gobject_ffi::g_signal_override_class_closure(
1231            signal_id.into_glib(),
1232            type_,
1233            class_handler.to_glib_none().0,
1234        );
1235    }
1236}
1237
1238pub(crate) unsafe fn signal_chain_from_overridden(
1239    instance: *mut gobject_ffi::GTypeInstance,
1240    token: &super::SignalClassHandlerToken,
1241    values: &[Value],
1242) -> Option<Value> {
1243    unsafe {
1244        assert_eq!(instance, token.0);
1245        assert_eq!(
1246            values.as_ptr(),
1247            token.2,
1248            "Arguments must be forwarded without changes when chaining up"
1249        );
1250
1251        let mut result = Value::from_type_unchecked(token.1);
1252        gobject_ffi::g_signal_chain_from_overridden(
1253            values.as_ptr() as *mut Value as *mut gobject_ffi::GValue,
1254            result.to_glib_none_mut().0,
1255        );
1256        Some(result).filter(|r| r.type_().is_valid() && r.type_() != Type::UNIT)
1257    }
1258}