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;
9use crate::{
10 object::{IsClass, IsInterface, ObjectSubclassIs, ParentClassIs},
11 prelude::*,
12 translate::*,
13 Closure, Object, Type, Value,
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: Borrowed = from_glib_borrow::<_, Object>(self as *mut _ as *mut gobject_ffi::GObject);
64 let obj: Borrowed<{unknown}> = Borrowed::new(val:obj.into_inner().unsafe_cast());
65 let mut obj: InitializingObject<{unknown}> = InitializingObject(obj);
66
67 <<Self::Type as ObjectSubclass>::ParentType as IsSubclassable<Self::Type>>::instance_init(
68 &mut obj,
69 );
70 }
71 }
72}
73
74// rustdoc-stripper-ignore-next
75/// Trait implemented by any type implementing `InstanceStruct` to return the implementation, private Rust struct.
76pub unsafe trait InstanceStructExt: InstanceStruct {
77 // rustdoc-stripper-ignore-next
78 /// Returns the implementation for from this instance struct, that
79 /// is the implementor of [`ObjectImpl`] or subtraits.
80 ///
81 /// [`ObjectImpl`]: ../object/trait.ObjectImpl.html
82 #[doc(alias = "get_impl")]
83 fn imp(&self) -> &Self::Type;
84
85 // rustdoc-stripper-ignore-next
86 /// Returns the class struct for this specific instance.
87 #[doc(alias = "get_class")]
88 fn class(&self) -> &<Self::Type as ObjectSubclass>::Class;
89}
90
91// rustdoc-stripper-ignore-next
92/// Offset `ptr` by `offset` *bytes* and cast the result to `*const U`.
93///
94/// The result must be a correctly aligned pointer to a valid value of type `U`.
95///
96/// # Panics:
97///
98/// This function panics if debug assertions are enabled if adding `offset` causes `ptr` to
99/// overflow or if the resulting pointer is not correctly aligned.
100#[inline]
101fn offset_ptr_by_bytes<T, U>(ptr: *const T, offset: isize) -> *const U {
102 // FIXME: Use `ptr::expose_addr()` once stable
103 let ptr: usize = ptr as usize;
104 let ptr: usize = if offset < 0 {
105 ptr - (-offset) as usize
106 } else {
107 ptr + offset as usize
108 };
109 debug_assert_eq!(ptr & (mem::align_of::<U>() - 1), 0);
110 ptr as *const U
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 // FIXME: Use `ptr::expose_addr()` once stable
125 let ptr: usize = ptr as usize;
126 let ptr: usize = if offset < 0 {
127 ptr - (-offset) as usize
128 } else {
129 ptr + offset as usize
130 };
131 debug_assert_eq!(ptr & (mem::align_of::<U>() - 1), 0);
132 ptr as *mut U
133}
134
135unsafe impl<T: InstanceStruct> InstanceStructExt for T {
136 #[inline]
137 fn imp(&self) -> &Self::Type {
138 unsafe {
139 let data: NonNull = Self::Type::type_data();
140 let private_offset: isize = data.as_ref().impl_offset();
141 let imp: *const {unknown} = 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 Class<{unknown}> = &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 class: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(self: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(self: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 for implementable interfaces.
284pub unsafe trait IsImplementable<T: ObjectSubclass>: IsInterface
285where
286 <Self as ObjectType>::GlibClassType: Copy,
287{
288 // rustdoc-stripper-ignore-next
289 /// Override the virtual methods of this interface for the given subclass and do other
290 /// interface initialization.
291 ///
292 /// This is automatically called during type initialization.
293 fn interface_init(_iface: &mut crate::Interface<Self>) {}
294
295 // rustdoc-stripper-ignore-next
296 /// Instance specific initialization.
297 ///
298 /// This is automatically called during instance initialization.
299 fn instance_init(_instance: &mut InitializingObject<T>) {}
300}
301
302unsafe extern "C" fn interface_init<T: ObjectSubclass, A: IsImplementable<T>>(
303 iface: ffi::gpointer,
304 _iface_data: ffi::gpointer,
305) where
306 <A as ObjectType>::GlibClassType: Copy,
307{
308 let iface: &mut Interface = &mut *(iface as *mut crate::Interface<A>);
309
310 let mut data: NonNull = T::type_data();
311 if data.as_ref().parent_ifaces.is_none() {
312 data.as_mut().parent_ifaces = Some(BTreeMap::default());
313 }
314 {
315 let copy: Box<::GlibClassType> = Box::new(*iface.as_ref());
316 data.as_mut()
317 .parent_ifaces
318 .as_mut()
319 .unwrap()
320 .insert(A::static_type(), value:Box::into_raw(copy) as ffi::gpointer);
321 }
322
323 A::interface_init(iface);
324}
325
326// rustdoc-stripper-ignore-next
327/// Trait for a type list of interfaces.
328pub trait InterfaceList<T: ObjectSubclass> {
329 // rustdoc-stripper-ignore-next
330 /// Returns the list of types and corresponding interface infos for this list.
331 fn iface_infos() -> Vec<(ffi::GType, gobject_ffi::GInterfaceInfo)>;
332
333 // rustdoc-stripper-ignore-next
334 /// Runs `instance_init` on each of the `IsImplementable` items.
335 fn instance_init(_instance: &mut InitializingObject<T>);
336}
337
338impl<T: ObjectSubclass> InterfaceList<T> for () {
339 fn iface_infos() -> Vec<(ffi::GType, gobject_ffi::GInterfaceInfo)> {
340 vec![]
341 }
342
343 #[inline]
344 fn instance_init(_instance: &mut InitializingObject<T>) {}
345}
346
347impl<T: ObjectSubclass, A: IsImplementable<T>> InterfaceList<T> for (A,)
348where
349 <A as ObjectType>::GlibClassType: Copy,
350{
351 fn iface_infos() -> Vec<(ffi::GType, gobject_ffi::GInterfaceInfo)> {
352 vec![(
353 A::static_type().into_glib(),
354 gobject_ffi::GInterfaceInfo {
355 interface_init: Some(interface_init::<T, A>),
356 interface_finalize: None,
357 interface_data: ptr::null_mut(),
358 },
359 )]
360 }
361
362 #[inline]
363 fn instance_init(instance: &mut InitializingObject<T>) {
364 A::instance_init(instance);
365 }
366}
367
368// Generates all the InterfaceList impls for interface_lists of arbitrary sizes based on a list of type
369// parameters like A B C. It would generate the impl then for (A, B) and (A, B, C).
370macro_rules! interface_list_trait(
371 ($name1:ident, $name2: ident, $($name:ident),*) => (
372 interface_list_trait!(__impl $name1, $name2; $($name),*);
373 );
374 (__impl $($name:ident),+; $name1:ident, $($name2:ident),*) => (
375 interface_list_trait_impl!($($name),+);
376 interface_list_trait!(__impl $($name),+ , $name1; $($name2),*);
377 );
378 (__impl $($name:ident),+; $name1:ident) => (
379 interface_list_trait_impl!($($name),+);
380 interface_list_trait_impl!($($name),+, $name1);
381 );
382);
383
384// Generates the impl block for InterfaceList on interface_lists or arbitrary sizes based on its
385// arguments. Takes a list of type parameters as parameters, e.g. A B C
386// and then implements the trait on (A, B, C).
387macro_rules! interface_list_trait_impl(
388 ($($name:ident),+) => (
389 impl<T: ObjectSubclass, $($name: IsImplementable<T>),+> InterfaceList<T> for ( $($name),+ )
390 where
391 $(<$name as ObjectType>::GlibClassType: Copy),+
392 {
393 fn iface_infos() -> Vec<(ffi::GType, gobject_ffi::GInterfaceInfo)> {
394 vec![
395 $(
396 (
397 $name::static_type().into_glib(),
398 gobject_ffi::GInterfaceInfo {
399 interface_init: Some(interface_init::<T, $name>),
400 interface_finalize: None,
401 interface_data: ptr::null_mut(),
402 },
403 )
404 ),+
405 ]
406 }
407
408 #[inline]
409 fn instance_init(instance: &mut InitializingObject<T>) {
410 $(
411 $name::instance_init(instance);
412 )+
413 }
414 }
415 );
416);
417
418interface_list_trait!(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S);
419
420/// Type-specific data that is filled in during type creation.
421// FIXME: Once trait bounds other than `Sized` on const fn parameters are stable
422// the content of `TypeData` can be made private, and we can add a `const fn new`
423// for initialization by the `object_subclass_internal!` macro.
424pub struct TypeData {
425 #[doc(hidden)]
426 pub type_: Type,
427 #[doc(hidden)]
428 pub parent_class: ffi::gpointer,
429 #[doc(hidden)]
430 pub parent_ifaces: Option<BTreeMap<Type, ffi::gpointer>>,
431 #[doc(hidden)]
432 pub class_data: Option<BTreeMap<Type, Box<dyn Any + Send + Sync>>>,
433 #[doc(hidden)]
434 pub private_offset: isize,
435 #[doc(hidden)]
436 pub private_imp_offset: isize,
437}
438
439unsafe impl Send for TypeData {}
440unsafe impl Sync for TypeData {}
441
442impl TypeData {
443 // rustdoc-stripper-ignore-next
444 /// Returns the type ID.
445 #[inline]
446 #[doc(alias = "get_type")]
447 pub fn type_(&self) -> Type {
448 self.type_
449 }
450
451 // rustdoc-stripper-ignore-next
452 /// Returns a pointer to the native parent class.
453 ///
454 /// This is used for chaining up to the parent class' implementation
455 /// of virtual methods.
456 #[doc(alias = "get_parent_class")]
457 #[inline]
458 pub fn parent_class(&self) -> ffi::gpointer {
459 debug_assert!(!self.parent_class.is_null());
460 self.parent_class
461 }
462
463 // rustdoc-stripper-ignore-next
464 /// Returns a pointer to the native parent interface struct for interface `type_`.
465 ///
466 /// This is used for chaining up to the parent interface's implementation
467 /// of virtual methods.
468 ///
469 /// # Panics
470 ///
471 /// This function panics if the type to which the `TypeData` belongs does not implement the
472 /// given interface or was not registered yet.
473 #[doc(alias = "get_parent_interface")]
474 pub fn parent_interface<I: crate::object::IsInterface>(&self) -> ffi::gpointer {
475 match self.parent_ifaces {
476 None => unreachable!("No parent interfaces"),
477 Some(ref parent_ifaces) => *parent_ifaces
478 .get(&I::static_type())
479 .expect("Parent interface not found"),
480 }
481 }
482
483 // rustdoc-stripper-ignore-next
484 /// Returns a pointer to the class implementation specific data.
485 ///
486 /// This is used for class implementations to store additional data.
487 #[doc(alias = "get_class_data")]
488 pub fn class_data<T: Any + Send + Sync + 'static>(&self, type_: Type) -> Option<&T> {
489 match self.class_data {
490 None => None,
491 Some(ref data) => data.get(&type_).and_then(|ptr| ptr.downcast_ref()),
492 }
493 }
494
495 // rustdoc-stripper-ignore-next
496 /// Gets a mutable reference of the class implementation specific data.
497 ///
498 /// # Safety
499 ///
500 /// This can only be used while the type is being initialized.
501 #[doc(alias = "get_class_data_mut")]
502 pub unsafe fn class_data_mut<T: Any + Send + Sync + 'static>(
503 &mut self,
504 type_: Type,
505 ) -> Option<&mut T> {
506 match self.class_data {
507 None => None,
508 Some(ref mut data) => data.get_mut(&type_).and_then(|v| v.downcast_mut()),
509 }
510 }
511
512 // rustdoc-stripper-ignore-next
513 /// Sets class specific implementation data.
514 ///
515 /// # Safety
516 ///
517 /// This can only be used while the type is being initialized.
518 ///
519 /// # Panics
520 ///
521 /// If the class_data already contains a data for the specified `type_`.
522 pub unsafe fn set_class_data<T: Any + Send + Sync + 'static>(&mut self, type_: Type, data: T) {
523 if self.class_data.is_none() {
524 self.class_data = Some(BTreeMap::default());
525 }
526
527 if let Some(ref mut class_data) = self.class_data {
528 assert!(
529 class_data.get(&type_).is_none(),
530 "The class_data already contains a key for {type_}",
531 );
532
533 class_data.insert(type_, Box::new(data));
534 }
535 }
536
537 // rustdoc-stripper-ignore-next
538 /// Returns the offset of the private implementation struct in bytes relative to the beginning
539 /// of the instance struct.
540 #[doc(alias = "get_impl_offset")]
541 #[inline]
542 pub fn impl_offset(&self) -> isize {
543 self.private_offset + self.private_imp_offset
544 }
545}
546
547// rustdoc-stripper-ignore-next
548/// Type methods required for an [`ObjectSubclass`] implementation.
549///
550/// This is usually generated by the [`#[object_subclass]`](crate::object_subclass) attribute macro.
551pub unsafe trait ObjectSubclassType {
552 // rustdoc-stripper-ignore-next
553 /// Storage for the type-specific data used during registration.
554 fn type_data() -> ptr::NonNull<TypeData>;
555
556 // rustdoc-stripper-ignore-next
557 /// Returns the `glib::Type` ID of the subclass.
558 ///
559 /// This will register the type with the type system on the first call.
560 #[doc(alias = "get_type")]
561 fn type_() -> Type;
562}
563
564pub const INIT_TYPE_DATA: TypeData = TypeData {
565 type_: Type::INVALID,
566 parent_class: ::std::ptr::null_mut(),
567 parent_ifaces: None,
568 class_data: None,
569 private_offset: 0,
570 private_imp_offset: 0,
571};
572
573// rustdoc-stripper-ignore-next
574/// The central trait for subclassing a `GObject` type.
575///
576/// Links together the type name, parent type and the instance and
577/// class structs for type registration and allows subclasses to
578/// hook into various steps of the type registration and initialization.
579///
580/// See [`register_type`] for registering an implementation of this trait
581/// with the type system.
582///
583/// [`register_type`]: fn.register_type.html
584pub trait ObjectSubclass: ObjectSubclassType + Sized + 'static {
585 // rustdoc-stripper-ignore-next
586 /// `GObject` type name.
587 ///
588 /// This must be unique in the whole process.
589 const NAME: &'static str;
590
591 // rustdoc-stripper-ignore-next
592 /// If this subclass is an abstract class or not.
593 ///
594 /// By default, all subclasses are non-abstract types but setting this to `true` will create an
595 /// abstract class instead.
596 ///
597 /// Abstract classes can't be instantiated and require a non-abstract subclass.
598 ///
599 /// Optional.
600 const ABSTRACT: bool = false;
601
602 // rustdoc-stripper-ignore-next
603 /// Wrapper around this subclass defined with `wrapper!`
604 type Type: ObjectType
605 + ObjectSubclassIs<Subclass = Self>
606 + FromGlibPtrFull<*mut <Self::Type as ObjectType>::GlibType>
607 + FromGlibPtrBorrow<*mut <Self::Type as ObjectType>::GlibType>
608 + FromGlibPtrNone<*mut <Self::Type as ObjectType>::GlibType>;
609
610 // rustdoc-stripper-ignore-next
611 /// Parent Rust type to inherit from.
612 type ParentType: IsSubclassable<Self>
613 + FromGlibPtrFull<*mut <Self::ParentType as ObjectType>::GlibType>
614 + FromGlibPtrBorrow<*mut <Self::ParentType as ObjectType>::GlibType>
615 + FromGlibPtrNone<*mut <Self::ParentType as ObjectType>::GlibType>;
616
617 // rustdoc-stripper-ignore-next
618 /// List of interfaces implemented by this type.
619 type Interfaces: InterfaceList<Self>;
620
621 // rustdoc-stripper-ignore-next
622 /// The C instance struct.
623 ///
624 /// See [`basic::InstanceStruct`] for an basic instance struct that should be
625 /// used in most cases.
626 ///
627 /// [`basic::InstanceStruct`]: ../basic/struct.InstanceStruct.html
628 // TODO: Should default to basic::InstanceStruct<Self> once associated
629 // type defaults are stabilized https://github.com/rust-lang/rust/issues/29661
630 type Instance: InstanceStruct<Type = Self>;
631
632 // rustdoc-stripper-ignore-next
633 /// The C class struct.
634 ///
635 /// See [`basic::ClassStruct`] for an basic instance struct that should be
636 /// used in most cases.
637 ///
638 /// [`basic::ClassStruct`]: ../basic/struct.ClassStruct.html
639 // TODO: Should default to basic::ClassStruct<Self> once associated
640 // type defaults are stabilized https://github.com/rust-lang/rust/issues/29661
641 type Class: ClassStruct<Type = Self>;
642
643 // rustdoc-stripper-ignore-next
644 /// Additional type initialization.
645 ///
646 /// This is called right after the type was registered and allows
647 /// subclasses to do additional type-specific initialization, e.g.
648 /// for implementing `GObject` interfaces.
649 ///
650 /// Optional
651 #[inline]
652 fn type_init(_type_: &mut InitializingType<Self>) {}
653
654 /// Class initialization.
655 ///
656 // rustdoc-stripper-ignore-next
657 /// This is called after `type_init` and before the first instance
658 /// of the subclass is created. Subclasses can use this to do class-
659 /// specific initialization, e.g. for registering signals on the class
660 /// or calling class methods.
661 ///
662 /// Optional
663 #[inline]
664 fn class_init(_klass: &mut Self::Class) {}
665
666 // rustdoc-stripper-ignore-next
667 /// Constructor.
668 ///
669 /// This is called during object instantiation before further subclasses
670 /// are initialized, and should return a new instance of the subclass
671 /// private struct.
672 ///
673 /// Optional, either implement this or `with_class()`.
674 fn new() -> Self {
675 unimplemented!();
676 }
677
678 // rustdoc-stripper-ignore-next
679 /// Constructor.
680 ///
681 /// This is called during object instantiation before further subclasses
682 /// are initialized, and should return a new instance of the subclass
683 /// private struct.
684 ///
685 /// Different to `new()` above it also gets the class of this type passed
686 /// to itself for providing additional context.
687 ///
688 /// Optional, either implement this or `new()`.
689 #[inline]
690 fn with_class(_klass: &Self::Class) -> Self {
691 Self::new()
692 }
693
694 // rustdoc-stripper-ignore-next
695 /// Performs additional instance initialization.
696 ///
697 /// Called just after `with_class()`. At this point the initialization has not completed yet, so
698 /// only a limited set of operations is safe (see `InitializingObject`).
699 #[inline]
700 fn instance_init(_obj: &InitializingObject<Self>) {}
701}
702
703// rustdoc-stripper-ignore-next
704/// Extension methods for all `ObjectSubclass` impls.
705pub trait ObjectSubclassExt: ObjectSubclass {
706 // rustdoc-stripper-ignore-next
707 /// Returns the corresponding object instance.
708 #[doc(alias = "get_instance")]
709 #[deprecated = "Use obj() instead"]
710 fn instance(&self) -> crate::BorrowedObject<Self::Type>;
711
712 // rustdoc-stripper-ignore-next
713 /// Returns the implementation from an instance.
714 #[deprecated = "Use from_obj() instead"]
715 fn from_instance(obj: &Self::Type) -> &Self;
716
717 // rustdoc-stripper-ignore-next
718 /// Returns the corresponding object instance.
719 ///
720 /// Shorter alias for `instance()`.
721 #[doc(alias = "get_instance")]
722 fn obj(&self) -> crate::BorrowedObject<Self::Type>;
723
724 // rustdoc-stripper-ignore-next
725 /// Returns the implementation from an instance.
726 ///
727 /// Shorter alias for `from_instance()`.
728 fn from_obj(obj: &Self::Type) -> &Self;
729
730 // rustdoc-stripper-ignore-next
731 /// Returns a new reference-counted wrapper around `self`.
732 fn ref_counted(&self) -> super::ObjectImplRef<Self>;
733
734 // rustdoc-stripper-ignore-next
735 /// Returns a pointer to the instance implementation specific data.
736 ///
737 /// This is used for the subclassing infrastructure to store additional instance data.
738 #[doc(alias = "get_instance_data")]
739 fn instance_data<U: Any + Send + Sync + 'static>(&self, type_: Type) -> Option<&U>;
740}
741
742impl<T: ObjectSubclass> ObjectSubclassExt for T {
743 #[inline]
744 fn instance(&self) -> crate::BorrowedObject<Self::Type> {
745 self.obj()
746 }
747
748 #[inline]
749 fn from_instance(obj: &Self::Type) -> &Self {
750 Self::from_obj(obj)
751 }
752
753 #[inline]
754 fn obj(&self) -> crate::BorrowedObject<Self::Type> {
755 unsafe {
756 let data = Self::type_data();
757 let type_ = data.as_ref().type_();
758 debug_assert!(type_.is_valid());
759
760 let offset = -data.as_ref().impl_offset();
761 let ptr =
762 offset_ptr_by_bytes::<Self, <Self::Type as ObjectType>::GlibType>(self, offset);
763
764 // The object might just be finalized, and in that case it's unsafe to access
765 // it and use any API on it. This can only happen from inside the Drop impl
766 // of Self.
767 debug_assert_ne!((*(ptr as *const gobject_ffi::GObject)).ref_count, 0);
768
769 crate::BorrowedObject::new(mut_override(ptr))
770 }
771 }
772
773 #[inline]
774 fn from_obj(obj: &Self::Type) -> &Self {
775 unsafe {
776 let ptr = obj.as_ptr() as *const Self::Instance;
777 (*ptr).imp()
778 }
779 }
780
781 #[inline]
782 fn ref_counted(&self) -> super::ObjectImplRef<Self> {
783 super::ObjectImplRef::new(self)
784 }
785
786 #[inline]
787 fn instance_data<U: Any + Send + Sync + 'static>(&self, type_: Type) -> Option<&U> {
788 unsafe {
789 let type_data = Self::type_data();
790 let self_type_ = type_data.as_ref().type_();
791 debug_assert!(self_type_.is_valid());
792
793 let offset = -type_data.as_ref().private_imp_offset;
794 let ptr = offset_ptr_by_bytes::<Self, PrivateStruct<Self>>(self, offset);
795 let priv_ = &*ptr;
796
797 match priv_.instance_data {
798 None => None,
799 Some(ref data) => data.get(&type_).and_then(|ptr| ptr.downcast_ref()),
800 }
801 }
802 }
803}
804
805// rustdoc-stripper-ignore-next
806/// Helper trait for macros to access a subclass or its wrapper.
807pub trait FromObject {
808 type FromObjectType;
809 fn from_object(obj: &Self::FromObjectType) -> &Self;
810}
811
812// rustdoc-stripper-ignore-next
813/// An object that is currently being initialized.
814///
815/// Binding crates should use traits for adding methods to this struct. Only methods explicitly safe
816/// to call during `instance_init()` should be added.
817pub struct InitializingObject<T: ObjectSubclass>(Borrowed<T::Type>);
818
819impl<T: ObjectSubclass> InitializingObject<T> {
820 // rustdoc-stripper-ignore-next
821 /// Returns a reference to the object.
822 ///
823 /// # Safety
824 ///
825 /// The returned object has not been completely initialized at this point. Use of the object
826 /// should be restricted to methods that are explicitly documented to be safe to call during
827 /// `instance_init()`.
828 #[inline]
829 pub unsafe fn as_ref(&self) -> &T::Type {
830 &self.0
831 }
832
833 // rustdoc-stripper-ignore-next
834 /// Returns a pointer to the object.
835 ///
836 /// # Safety
837 ///
838 /// The returned object has not been completely initialized at this point. Use of the object
839 /// should be restricted to methods that are explicitly documented to be safe to call during
840 /// `instance_init()`.
841 #[inline]
842 pub fn as_ptr(&self) -> *mut T::Type {
843 self.0.as_ptr() as *const T::Type as *mut T::Type
844 }
845
846 // rustdoc-stripper-ignore-next
847 /// Sets instance specific implementation data.
848 ///
849 /// # Panics
850 ///
851 /// If the instance_data already contains a data for the specified `type_`.
852 pub fn set_instance_data<U: Any + Send + Sync + 'static>(&mut self, type_: Type, data: U) {
853 unsafe {
854 let type_data = T::type_data();
855 let self_type_ = type_data.as_ref().type_();
856 debug_assert!(self_type_.is_valid());
857
858 let offset = type_data.as_ref().private_offset;
859
860 let ptr = offset_ptr_by_bytes_mut::<
861 <<T as ObjectSubclass>::Type as ObjectType>::GlibType,
862 PrivateStruct<T>,
863 >(self.0.as_ptr(), offset);
864 let priv_ = &mut *ptr;
865
866 if priv_.instance_data.is_none() {
867 priv_.instance_data = Some(BTreeMap::default());
868 }
869
870 if let Some(ref mut instance_data) = priv_.instance_data {
871 assert!(
872 instance_data.get(&type_).is_none(),
873 "The class_data already contains a key for {type_}",
874 );
875
876 instance_data.insert(type_, Box::new(data));
877 }
878 }
879 }
880}
881
882unsafe extern "C" fn class_init<T: ObjectSubclass>(
883 klass: ffi::gpointer,
884 _klass_data: ffi::gpointer,
885) {
886 let mut data = T::type_data();
887
888 // We have to update the private struct offset once the class is actually
889 // being initialized.
890 let mut private_offset = data.as_ref().private_offset as i32;
891 gobject_ffi::g_type_class_adjust_private_offset(klass, &mut private_offset);
892 data.as_mut().private_offset = private_offset as isize;
893
894 // Set trampolines for the basic GObject virtual methods.
895 {
896 let gobject_klass = &mut *(klass as *mut gobject_ffi::GObjectClass);
897
898 gobject_klass.finalize = Some(finalize::<T>);
899 }
900
901 // And finally peek the parent class struct (containing the parent class'
902 // implementations of virtual methods for chaining up), and call the subclass'
903 // class initialization function.
904 {
905 let klass = &mut *(klass as *mut T::Class);
906 let parent_class = gobject_ffi::g_type_class_peek_parent(klass as *mut _ as ffi::gpointer)
907 as *mut <T::ParentType as ObjectType>::GlibClassType;
908 debug_assert!(!parent_class.is_null());
909
910 data.as_mut().parent_class = parent_class as ffi::gpointer;
911
912 klass.class_init();
913 T::class_init(klass);
914 }
915}
916
917unsafe extern "C" fn instance_init<T: ObjectSubclass>(
918 obj: *mut gobject_ffi::GTypeInstance,
919 klass: ffi::gpointer,
920) {
921 // Get offset to the storage of our private struct, create it
922 // and actually store it in that place.
923 let mut data = T::type_data();
924 let private_offset = data.as_mut().private_offset;
925 let priv_ptr = offset_ptr_by_bytes_mut::<gobject_ffi::GTypeInstance, PrivateStruct<T>>(
926 obj,
927 private_offset,
928 );
929
930 assert!(
931 priv_ptr as usize & (mem::align_of::<PrivateStruct<T>>() - 1) == 0,
932 "Private instance data has higher alignment requirements ({}) than \
933 the allocation from GLib. If alignment of more than {} bytes \
934 is required, store the corresponding data separately on the heap.",
935 mem::align_of::<PrivateStruct<T>>(),
936 2 * mem::size_of::<usize>(),
937 );
938
939 let klass = &*(klass as *const T::Class);
940
941 let imp = T::with_class(klass);
942 ptr::write(
943 priv_ptr,
944 PrivateStruct {
945 imp,
946 instance_data: None,
947 },
948 );
949
950 // Any additional instance initialization.
951 T::Instance::instance_init(&mut *(obj as *mut _));
952
953 let obj = from_glib_borrow::<_, Object>(obj.cast());
954 let obj = Borrowed::new(obj.into_inner().unsafe_cast());
955 let mut obj = InitializingObject(obj);
956
957 T::Interfaces::instance_init(&mut obj);
958 T::instance_init(&obj);
959}
960
961unsafe extern "C" fn finalize<T: ObjectSubclass>(obj: *mut gobject_ffi::GObject) {
962 // Retrieve the private struct and drop it for freeing all associated memory.
963 let mut data: NonNull = T::type_data();
964 let private_offset: isize = data.as_mut().private_offset;
965 let priv_ptr: *mut PrivateStruct =
966 offset_ptr_by_bytes_mut::<gobject_ffi::GObject, PrivateStruct<T>>(ptr:obj, private_offset);
967 ptr::drop_in_place(to_drop:ptr::addr_of_mut!((*priv_ptr).imp));
968 ptr::drop_in_place(to_drop:ptr::addr_of_mut!((*priv_ptr).instance_data));
969
970 // Chain up to the parent class' finalize implementation, if any.
971 let parent_class: &GObjectClass = &*(data.as_ref().parent_class() as *const gobject_ffi::GObjectClass);
972 if let Some(ref func: &unsafe fn(*mut GObject)) = parent_class.finalize {
973 func(obj);
974 }
975}
976
977// rustdoc-stripper-ignore-next
978/// Register a `glib::Type` ID for `T`.
979///
980/// This must be called only once and will panic on a second call.
981///
982/// The [`object_subclass!`] macro will create a `type_()` function around this, which will
983/// ensure that it's only ever called once.
984///
985/// [`object_subclass!`]: ../../macro.object_subclass.html
986pub fn register_type<T: ObjectSubclass>() -> Type {
987 // GLib aligns the type private data to two gsizes, so we can't safely store any type there that
988 // requires a bigger alignment.
989 assert!(
990 mem::align_of::<T>() <= 2 * mem::size_of::<usize>(),
991 "Alignment {} of type not supported, bigger than {}",
992 mem::align_of::<T>(),
993 2 * mem::size_of::<usize>(),
994 );
995
996 unsafe {
997 use std::ffi::CString;
998
999 let type_name = CString::new(T::NAME).unwrap();
1000 assert_eq!(
1001 gobject_ffi::g_type_from_name(type_name.as_ptr()),
1002 gobject_ffi::G_TYPE_INVALID,
1003 "Type {} has already been registered",
1004 type_name.to_str().unwrap()
1005 );
1006
1007 let type_ = Type::from_glib(gobject_ffi::g_type_register_static_simple(
1008 <T::ParentType as StaticType>::static_type().into_glib(),
1009 type_name.as_ptr(),
1010 mem::size_of::<T::Class>() as u32,
1011 Some(class_init::<T>),
1012 mem::size_of::<T::Instance>() as u32,
1013 Some(instance_init::<T>),
1014 if T::ABSTRACT {
1015 gobject_ffi::G_TYPE_FLAG_ABSTRACT
1016 } else {
1017 0
1018 },
1019 ));
1020 assert!(type_.is_valid());
1021
1022 let mut data = T::type_data();
1023 data.as_mut().type_ = type_;
1024
1025 let private_offset = gobject_ffi::g_type_add_instance_private(
1026 type_.into_glib(),
1027 mem::size_of::<PrivateStruct<T>>(),
1028 );
1029 data.as_mut().private_offset = private_offset as isize;
1030
1031 // Get the offset from PrivateStruct<T> to the imp field in it. This has to go through
1032 // some hoops because Rust doesn't have an offsetof operator yet.
1033 data.as_mut().private_imp_offset = {
1034 // Must not be a dangling pointer so let's create some uninitialized memory
1035 let priv_ = mem::MaybeUninit::<PrivateStruct<T>>::uninit();
1036 let ptr = priv_.as_ptr();
1037 let imp_ptr = ptr::addr_of!((*ptr).imp);
1038 (imp_ptr as isize) - (ptr as isize)
1039 };
1040
1041 let iface_types = T::Interfaces::iface_infos();
1042 for (iface_type, iface_info) in iface_types {
1043 gobject_ffi::g_type_add_interface_static(type_.into_glib(), iface_type, &iface_info);
1044 }
1045
1046 T::type_init(&mut InitializingType::<T>(type_, marker::PhantomData));
1047
1048 type_
1049 }
1050}
1051
1052pub(crate) unsafe fn signal_override_class_handler<F>(
1053 name: &str,
1054 type_: ffi::GType,
1055 class_handler: F,
1056) where
1057 F: Fn(&super::SignalClassHandlerToken, &[Value]) -> Option<Value> + Send + Sync + 'static,
1058{
1059 let (signal_id, _) = SignalId::parse_name(name, from_glib(type_), false)
1060 .unwrap_or_else(|| panic!("Signal '{name}' not found"));
1061
1062 let query = signal_id.query();
1063 let return_type = query.return_type();
1064
1065 let class_handler = Closure::new(move |values| {
1066 let instance = gobject_ffi::g_value_get_object(values[0].to_glib_none().0);
1067 let res = class_handler(
1068 &super::SignalClassHandlerToken(
1069 instance as *mut _,
1070 return_type.into(),
1071 values.as_ptr(),
1072 ),
1073 values,
1074 );
1075
1076 if return_type == Type::UNIT {
1077 if let Some(ref v) = res {
1078 panic!(
1079 "Signal has no return value but class handler returned a value of type {}",
1080 v.type_()
1081 );
1082 }
1083 } else {
1084 match res {
1085 None => {
1086 panic!("Signal has a return value but class handler returned none");
1087 }
1088 Some(ref v) => {
1089 assert!(
1090 v.type_().is_a(return_type.into()),
1091 "Signal has a return type of {} but class handler returned {}",
1092 Type::from(return_type),
1093 v.type_()
1094 );
1095 }
1096 }
1097 }
1098
1099 res
1100 });
1101
1102 gobject_ffi::g_signal_override_class_closure(
1103 signal_id.into_glib(),
1104 type_,
1105 class_handler.to_glib_none().0,
1106 );
1107}
1108
1109pub(crate) unsafe fn signal_chain_from_overridden(
1110 instance: *mut gobject_ffi::GTypeInstance,
1111 token: &super::SignalClassHandlerToken,
1112 values: &[Value],
1113) -> Option<Value> {
1114 assert_eq!(instance, token.0);
1115 assert_eq!(
1116 values.as_ptr(),
1117 token.2,
1118 "Arguments must be forwarded without changes when chaining up"
1119 );
1120
1121 let mut result: Value = Value::from_type_unchecked(type_:token.1);
1122 gobject_ffi::g_signal_chain_from_overridden(
1123 instance_and_params:values.as_ptr() as *mut Value as *mut gobject_ffi::GValue,
1124 return_value:result.to_glib_none_mut().0,
1125 );
1126 Some(result).filter(|r: &Value| r.type_().is_valid() && r.type_() != Type::UNIT)
1127}
1128