1// Take a look at the license at the top of the repository in the LICENSE file.
2
3// rustdoc-stripper-ignore-next
4//! Runtime type information.
5
6use std::{
7 fmt,
8 marker::PhantomData,
9 mem,
10 num::{NonZeroI32, NonZeroI64, NonZeroI8, NonZeroU32, NonZeroU64, NonZeroU8},
11 path::{Path, PathBuf},
12 ptr,
13};
14
15use crate::{translate::*, IntoGStr, Slice};
16
17// rustdoc-stripper-ignore-next
18/// A GLib or GLib-based library type
19#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
20#[doc(alias = "GType")]
21#[repr(transparent)]
22pub struct Type(ffi::GType);
23
24unsafe impl TransparentType for Type {
25 type GlibType = ffi::GType;
26}
27
28impl Type {
29 // rustdoc-stripper-ignore-next
30 /// An invalid `Type` used as error return value in some functions
31 #[doc(alias = "G_TYPE_INVALID")]
32 pub const INVALID: Self = Self(gobject_ffi::G_TYPE_INVALID);
33
34 // rustdoc-stripper-ignore-next
35 /// The fundamental type corresponding to the unit type `()`
36 #[doc(alias = "G_TYPE_NONE")]
37 pub const UNIT: Self = Self(gobject_ffi::G_TYPE_NONE);
38
39 // rustdoc-stripper-ignore-next
40 /// The fundamental type corresponding to `i8`
41 #[doc(alias = "G_TYPE_CHAR")]
42 pub const I8: Self = Self(gobject_ffi::G_TYPE_CHAR);
43
44 // rustdoc-stripper-ignore-next
45 /// The fundamental type corresponding to `u8`
46 #[doc(alias = "G_TYPE_UCHAR")]
47 pub const U8: Self = Self(gobject_ffi::G_TYPE_UCHAR);
48
49 // rustdoc-stripper-ignore-next
50 /// The fundamental type corresponding to `bool`
51 #[doc(alias = "G_TYPE_BOOLEAN")]
52 pub const BOOL: Self = Self(gobject_ffi::G_TYPE_BOOLEAN);
53
54 // rustdoc-stripper-ignore-next
55 /// The fundamental type corresponding to `i32`
56 #[doc(alias = "G_TYPE_INT")]
57 pub const I32: Self = Self(gobject_ffi::G_TYPE_INT);
58
59 // rustdoc-stripper-ignore-next
60 /// The fundamental type corresponding to `u32`
61 #[doc(alias = "G_TYPE_UINT")]
62 pub const U32: Self = Self(gobject_ffi::G_TYPE_UINT);
63
64 // rustdoc-stripper-ignore-next
65 /// The fundamental type corresponding to C `long`
66 #[doc(alias = "G_TYPE_LONG")]
67 pub const I_LONG: Self = Self(gobject_ffi::G_TYPE_LONG);
68
69 // rustdoc-stripper-ignore-next
70 /// The fundamental type corresponding to C `unsigned long`
71 #[doc(alias = "G_TYPE_ULONG")]
72 pub const U_LONG: Self = Self(gobject_ffi::G_TYPE_ULONG);
73
74 // rustdoc-stripper-ignore-next
75 /// The fundamental type corresponding to `i64`
76 #[doc(alias = "G_TYPE_INT64")]
77 pub const I64: Self = Self(gobject_ffi::G_TYPE_INT64);
78
79 // rustdoc-stripper-ignore-next
80 /// The fundamental type corresponding to `u64`
81 #[doc(alias = "G_TYPE_UINT64")]
82 pub const U64: Self = Self(gobject_ffi::G_TYPE_UINT64);
83
84 // rustdoc-stripper-ignore-next
85 /// The fundamental type corresponding to `f32`
86 #[doc(alias = "G_TYPE_FLOAT")]
87 pub const F32: Self = Self(gobject_ffi::G_TYPE_FLOAT);
88
89 // rustdoc-stripper-ignore-next
90 /// The fundamental type corresponding to `f64`
91 #[doc(alias = "G_TYPE_DOUBLE")]
92 pub const F64: Self = Self(gobject_ffi::G_TYPE_DOUBLE);
93
94 // rustdoc-stripper-ignore-next
95 /// The fundamental type corresponding to `String`
96 #[doc(alias = "G_TYPE_STRING")]
97 pub const STRING: Self = Self(gobject_ffi::G_TYPE_STRING);
98
99 // rustdoc-stripper-ignore-next
100 /// The fundamental type corresponding to a pointer
101 #[doc(alias = "G_TYPE_POINTER")]
102 pub const POINTER: Self = Self(gobject_ffi::G_TYPE_POINTER);
103
104 // rustdoc-stripper-ignore-next
105 /// The fundamental type of GVariant
106 #[doc(alias = "G_TYPE_VARIANT")]
107 pub const VARIANT: Self = Self(gobject_ffi::G_TYPE_VARIANT);
108
109 // rustdoc-stripper-ignore-next
110 /// The fundamental type from which all interfaces are derived
111 #[doc(alias = "G_TYPE_INTERFACE")]
112 pub const INTERFACE: Self = Self(gobject_ffi::G_TYPE_INTERFACE);
113
114 // rustdoc-stripper-ignore-next
115 /// The fundamental type from which all enumeration types are derived
116 #[doc(alias = "G_TYPE_ENUM")]
117 pub const ENUM: Self = Self(gobject_ffi::G_TYPE_ENUM);
118
119 // rustdoc-stripper-ignore-next
120 /// The fundamental type from which all flags types are derived
121 #[doc(alias = "G_TYPE_FLAGS")]
122 pub const FLAGS: Self = Self(gobject_ffi::G_TYPE_FLAGS);
123
124 // rustdoc-stripper-ignore-next
125 /// The fundamental type from which all boxed types are derived
126 #[doc(alias = "G_TYPE_BOXED")]
127 pub const BOXED: Self = Self(gobject_ffi::G_TYPE_BOXED);
128
129 // rustdoc-stripper-ignore-next
130 /// The fundamental type from which all `GParamSpec` types are derived
131 #[doc(alias = "G_TYPE_PARAM")]
132 pub const PARAM_SPEC: Self = Self(gobject_ffi::G_TYPE_PARAM);
133
134 // rustdoc-stripper-ignore-next
135 /// The fundamental type from which all objects are derived
136 #[doc(alias = "G_TYPE_OBJECT")]
137 pub const OBJECT: Self = Self(gobject_ffi::G_TYPE_OBJECT);
138
139 #[doc(alias = "g_type_name")]
140 pub fn name<'a>(self) -> &'a str {
141 match self.into_glib() {
142 gobject_ffi::G_TYPE_INVALID => "<invalid>",
143 x => unsafe {
144 let ptr = gobject_ffi::g_type_name(x);
145 std::ffi::CStr::from_ptr(ptr).to_str().unwrap()
146 },
147 }
148 }
149
150 #[doc(alias = "g_type_qname")]
151 pub fn qname(self) -> crate::Quark {
152 match self.into_glib() {
153 gobject_ffi::G_TYPE_INVALID => crate::Quark::from_str("<invalid>"),
154 x => unsafe { from_glib(gobject_ffi::g_type_qname(x)) },
155 }
156 }
157
158 #[doc(alias = "g_type_is_a")]
159 #[inline]
160 pub fn is_a(self, other: Self) -> bool {
161 unsafe {
162 from_glib(gobject_ffi::g_type_is_a(
163 self.into_glib(),
164 other.into_glib(),
165 ))
166 }
167 }
168
169 #[doc(alias = "g_type_parent")]
170 pub fn parent(self) -> Option<Self> {
171 unsafe {
172 let parent: Self = from_glib(gobject_ffi::g_type_parent(self.into_glib()));
173 Some(parent).filter(|t| t.is_valid())
174 }
175 }
176
177 #[doc(alias = "g_type_children")]
178 pub fn children(self) -> Slice<Self> {
179 unsafe {
180 let mut n_children = 0u32;
181 let children = gobject_ffi::g_type_children(self.into_glib(), &mut n_children);
182
183 Slice::from_glib_full_num(children, n_children as usize)
184 }
185 }
186
187 #[doc(alias = "g_type_interfaces")]
188 pub fn interfaces(self) -> Slice<Self> {
189 unsafe {
190 let mut n_interfaces = 0u32;
191 let interfaces = gobject_ffi::g_type_interfaces(self.into_glib(), &mut n_interfaces);
192
193 Slice::from_glib_full_num(interfaces, n_interfaces as usize)
194 }
195 }
196
197 #[doc(alias = "g_type_interface_prerequisites")]
198 pub fn interface_prerequisites(self) -> Slice<Self> {
199 unsafe {
200 match self {
201 t if !t.is_a(Self::INTERFACE) => Slice::from_glib_full_num(ptr::null_mut(), 0),
202 _ => {
203 let mut n_prereqs = 0u32;
204 let prereqs = gobject_ffi::g_type_interface_prerequisites(
205 self.into_glib(),
206 &mut n_prereqs,
207 );
208
209 Slice::from_glib_full_num(prereqs, n_prereqs as usize)
210 }
211 }
212 }
213 }
214
215 #[doc(alias = "g_type_from_name")]
216 pub fn from_name(name: impl IntoGStr) -> Option<Self> {
217 unsafe {
218 let type_ = name.run_with_gstr(|name| {
219 Self::from_glib(gobject_ffi::g_type_from_name(name.as_ptr()))
220 });
221
222 Some(type_).filter(|t| t.is_valid())
223 }
224 }
225
226 // rustdoc-stripper-ignore-next
227 /// Checks that the type is not [`INVALID`](Self::INVALID)
228 #[inline]
229 pub fn is_valid(self) -> bool {
230 self != Self::INVALID
231 }
232}
233
234impl fmt::Debug for Type {
235 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
236 f.write_str(self.name())
237 }
238}
239
240impl fmt::Display for Type {
241 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
242 f.write_str(self.name())
243 }
244}
245
246// rustdoc-stripper-ignore-next
247/// Types that are supported by GLib dynamic typing.
248pub trait StaticType {
249 // rustdoc-stripper-ignore-next
250 /// Returns the type identifier of `Self`.
251 fn static_type() -> Type;
252}
253
254impl StaticType for Type {
255 #[doc(alias = "g_gtype_get_type")]
256 #[inline]
257 fn static_type() -> Type {
258 unsafe { from_glib(val:gobject_ffi::g_gtype_get_type()) }
259 }
260}
261
262pub trait StaticTypeExt {
263 // rustdoc-stripper-ignore-next
264 /// Ensures that the type has been registered with the type system.
265 #[doc(alias = "g_type_ensure")]
266 fn ensure_type();
267}
268
269impl<T: StaticType> StaticTypeExt for T {
270 #[inline]
271 fn ensure_type() {
272 T::static_type();
273 }
274}
275
276#[doc(hidden)]
277impl crate::value::ValueType for Type {
278 type Type = Type;
279}
280
281#[doc(hidden)]
282unsafe impl<'a> crate::value::FromValue<'a> for Type {
283 type Checker = crate::value::GenericValueTypeChecker<Self>;
284
285 #[inline]
286 unsafe fn from_value(value: &'a crate::Value) -> Self {
287 from_glib(val:gobject_ffi::g_value_get_gtype(value.to_glib_none().0))
288 }
289}
290
291#[doc(hidden)]
292impl crate::value::ToValue for Type {
293 #[inline]
294 fn to_value(&self) -> crate::Value {
295 unsafe {
296 let mut value: Value = crate::Value::from_type_unchecked(type_:Type::static_type());
297 gobject_ffi::g_value_set_gtype(value:value.to_glib_none_mut().0, self.into_glib());
298 value
299 }
300 }
301
302 #[inline]
303 fn value_type(&self) -> crate::Type {
304 Type::static_type()
305 }
306}
307
308#[doc(hidden)]
309impl From<Type> for crate::Value {
310 #[inline]
311 fn from(t: Type) -> Self {
312 crate::value::ToValue::to_value(&t)
313 }
314}
315
316impl<'a, T: ?Sized + StaticType> StaticType for &'a T {
317 #[inline]
318 fn static_type() -> Type {
319 T::static_type()
320 }
321}
322
323impl<'a, T: ?Sized + StaticType> StaticType for &'a mut T {
324 #[inline]
325 fn static_type() -> Type {
326 T::static_type()
327 }
328}
329
330macro_rules! builtin {
331 ($name:ty, $val:ident) => {
332 impl StaticType for $name {
333 #[inline]
334 fn static_type() -> Type {
335 Type::$val
336 }
337 }
338 };
339}
340
341// rustdoc-stripper-ignore-next
342/// A GLib pointer
343///
344/// A raw untyped pointer equivalent to [`*mut Pointee`](Pointee).
345pub type Pointer = ffi::gpointer;
346
347// rustdoc-stripper-ignore-next
348/// The target of a [Pointer]
349///
350/// # Examples
351///
352/// ```
353/// use glib::prelude::*;
354/// use glib::types::{Pointee, Pointer};
355/// use std::ptr::NonNull;
356///
357/// let pointer = NonNull::<Pointee>::dangling();
358/// let value = pointer.to_value();
359/// assert!(value.is::<Pointer>());
360/// assert_eq!(value.get(), Ok(pointer.as_ptr()));
361/// ```
362pub type Pointee = libc::c_void;
363
364impl StaticType for ptr::NonNull<Pointee> {
365 #[inline]
366 fn static_type() -> Type {
367 Pointer::static_type()
368 }
369}
370
371#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
372pub struct ILong(pub libc::c_long);
373
374impl std::ops::Deref for ILong {
375 type Target = libc::c_long;
376
377 #[inline]
378 fn deref(&self) -> &Self::Target {
379 &self.0
380 }
381}
382
383impl std::ops::DerefMut for ILong {
384 #[inline]
385 fn deref_mut(&mut self) -> &mut Self::Target {
386 &mut self.0
387 }
388}
389
390impl From<libc::c_long> for ILong {
391 #[inline]
392 fn from(v: libc::c_long) -> ILong {
393 ILong(v)
394 }
395}
396
397impl From<ILong> for libc::c_long {
398 #[inline]
399 fn from(v: ILong) -> libc::c_long {
400 v.0
401 }
402}
403
404impl PartialEq<libc::c_long> for ILong {
405 #[inline]
406 fn eq(&self, other: &libc::c_long) -> bool {
407 &self.0 == other
408 }
409}
410
411impl PartialEq<ILong> for libc::c_long {
412 #[inline]
413 fn eq(&self, other: &ILong) -> bool {
414 self == &other.0
415 }
416}
417
418impl PartialOrd<libc::c_long> for ILong {
419 #[inline]
420 fn partial_cmp(&self, other: &libc::c_long) -> Option<std::cmp::Ordering> {
421 self.0.partial_cmp(other)
422 }
423}
424
425impl PartialOrd<ILong> for libc::c_long {
426 #[inline]
427 fn partial_cmp(&self, other: &ILong) -> Option<std::cmp::Ordering> {
428 self.partial_cmp(&other.0)
429 }
430}
431
432#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
433pub struct ULong(pub libc::c_ulong);
434
435impl std::ops::Deref for ULong {
436 type Target = libc::c_ulong;
437
438 #[inline]
439 fn deref(&self) -> &Self::Target {
440 &self.0
441 }
442}
443
444impl std::ops::DerefMut for ULong {
445 #[inline]
446 fn deref_mut(&mut self) -> &mut Self::Target {
447 &mut self.0
448 }
449}
450
451impl From<libc::c_ulong> for ULong {
452 #[inline]
453 fn from(v: libc::c_ulong) -> ULong {
454 ULong(v)
455 }
456}
457
458impl From<ULong> for libc::c_ulong {
459 #[inline]
460 fn from(v: ULong) -> libc::c_ulong {
461 v.0
462 }
463}
464
465impl PartialEq<libc::c_ulong> for ULong {
466 #[inline]
467 fn eq(&self, other: &libc::c_ulong) -> bool {
468 &self.0 == other
469 }
470}
471
472impl PartialEq<ULong> for libc::c_ulong {
473 #[inline]
474 fn eq(&self, other: &ULong) -> bool {
475 self == &other.0
476 }
477}
478
479impl PartialOrd<libc::c_ulong> for ULong {
480 #[inline]
481 fn partial_cmp(&self, other: &libc::c_ulong) -> Option<std::cmp::Ordering> {
482 self.0.partial_cmp(other)
483 }
484}
485
486impl PartialOrd<ULong> for libc::c_ulong {
487 #[inline]
488 fn partial_cmp(&self, other: &ULong) -> Option<std::cmp::Ordering> {
489 self.partial_cmp(&other.0)
490 }
491}
492
493builtin!(bool, BOOL);
494builtin!(i8, I8);
495builtin!(NonZeroI8, I8);
496builtin!(u8, U8);
497builtin!(NonZeroU8, U8);
498builtin!(i32, I32);
499builtin!(NonZeroI32, I32);
500builtin!(u32, U32);
501builtin!(NonZeroU32, U32);
502builtin!(i64, I64);
503builtin!(NonZeroI64, I64);
504builtin!(u64, U64);
505builtin!(NonZeroU64, U64);
506builtin!(ILong, I_LONG);
507builtin!(ULong, U_LONG);
508builtin!(f32, F32);
509builtin!(f64, F64);
510builtin!(str, STRING);
511builtin!(String, STRING);
512builtin!(PathBuf, STRING);
513builtin!(Path, STRING);
514builtin!(Pointer, POINTER);
515
516impl<'a> StaticType for [&'a str] {
517 #[inline]
518 fn static_type() -> Type {
519 unsafe { from_glib(val:ffi::g_strv_get_type()) }
520 }
521}
522
523impl StaticType for Vec<String> {
524 #[inline]
525 fn static_type() -> Type {
526 unsafe { from_glib(val:ffi::g_strv_get_type()) }
527 }
528}
529
530impl StaticType for () {
531 #[inline]
532 fn static_type() -> Type {
533 Type::UNIT
534 }
535}
536
537#[inline]
538pub unsafe fn instance_of<C: StaticType>(ptr: ffi::gconstpointer) -> bool {
539 from_glib(val:gobject_ffi::g_type_check_instance_is_a(
540 instance:ptr as *mut _,
541 <C as StaticType>::static_type().into_glib(),
542 ))
543}
544
545impl FromGlib<ffi::GType> for Type {
546 #[inline]
547 unsafe fn from_glib(val: ffi::GType) -> Self {
548 Self(val)
549 }
550}
551
552impl IntoGlib for Type {
553 type GlibType = ffi::GType;
554
555 #[inline]
556 fn into_glib(self) -> ffi::GType {
557 self.0
558 }
559}
560
561impl<'a> ToGlibContainerFromSlice<'a, *mut ffi::GType> for Type {
562 type Storage = PhantomData<&'a [Type]>;
563
564 #[inline]
565 fn to_glib_none_from_slice(t: &'a [Type]) -> (*mut ffi::GType, Self::Storage) {
566 (t.as_ptr() as *mut ffi::GType, PhantomData)
567 }
568
569 #[inline]
570 fn to_glib_container_from_slice(t: &'a [Type]) -> (*mut ffi::GType, Self::Storage) {
571 (Self::to_glib_full_from_slice(t), PhantomData)
572 }
573
574 fn to_glib_full_from_slice(t: &[Type]) -> *mut ffi::GType {
575 if t.is_empty() {
576 return ptr::null_mut();
577 }
578
579 unsafe {
580 let res =
581 ffi::g_malloc(mem::size_of::<ffi::GType>() * (t.len() + 1)) as *mut ffi::GType;
582 std::ptr::copy_nonoverlapping(t.as_ptr() as *const ffi::GType, res, t.len());
583 *res.add(t.len()) = 0;
584 res
585 }
586 }
587}
588
589impl FromGlibContainerAsVec<Type, *const ffi::GType> for Type {
590 unsafe fn from_glib_none_num_as_vec(ptr: *const ffi::GType, num: usize) -> Vec<Self> {
591 if num == 0 || ptr.is_null() {
592 return Vec::new();
593 }
594
595 let mut res: Vec = Vec::<Self>::with_capacity(num);
596 let res_ptr: *mut usize = res.as_mut_ptr() as *mut ffi::GType;
597 std::ptr::copy_nonoverlapping(src:ptr, dst:res_ptr, count:num);
598 res.set_len(new_len:num);
599 res
600 }
601
602 unsafe fn from_glib_container_num_as_vec(_: *const ffi::GType, _: usize) -> Vec<Self> {
603 // Can't really free a *const
604 unimplemented!();
605 }
606
607 unsafe fn from_glib_full_num_as_vec(_: *const ffi::GType, _: usize) -> Vec<Self> {
608 // Can't really free a *const
609 unimplemented!();
610 }
611}
612
613impl FromGlibContainerAsVec<Type, *mut ffi::GType> for Type {
614 unsafe fn from_glib_none_num_as_vec(ptr: *mut ffi::GType, num: usize) -> Vec<Self> {
615 FromGlibContainerAsVec::from_glib_none_num_as_vec(ptr as *const _, num)
616 }
617
618 unsafe fn from_glib_container_num_as_vec(ptr: *mut ffi::GType, num: usize) -> Vec<Self> {
619 let res: Vec = FromGlibContainerAsVec::from_glib_none_num_as_vec(ptr, num);
620 ffi::g_free(mem:ptr as *mut _);
621 res
622 }
623
624 unsafe fn from_glib_full_num_as_vec(ptr: *mut ffi::GType, num: usize) -> Vec<Self> {
625 FromGlibContainerAsVec::from_glib_container_num_as_vec(ptr, num)
626 }
627}
628
629#[cfg(test)]
630mod tests {
631 use std::collections::{BTreeSet, HashSet};
632
633 use super::*;
634 use crate::InitiallyUnowned;
635
636 #[test]
637 fn invalid() {
638 let invalid = Type::INVALID;
639
640 assert_eq!(invalid.name(), "<invalid>");
641 assert_eq!(invalid.qname(), crate::Quark::from_str("<invalid>"));
642 assert!(invalid.is_a(Type::INVALID));
643 assert!(!invalid.is_a(Type::STRING));
644 assert_eq!(invalid.parent(), None);
645 assert!(invalid.children().is_empty());
646 assert!(invalid.interfaces().is_empty());
647 assert!(invalid.interface_prerequisites().is_empty());
648 assert!(!invalid.is_valid());
649 dbg!(&invalid);
650 }
651
652 #[test]
653 fn hash() {
654 // Get this first so the type is registered
655 let iu_type = InitiallyUnowned::static_type();
656
657 let set = Type::OBJECT
658 .children()
659 .iter()
660 .copied()
661 .collect::<HashSet<_>>();
662 assert!(set.contains(&iu_type));
663 }
664
665 #[test]
666 fn ord() {
667 // Get this first so the type is registered
668 let iu_type = InitiallyUnowned::static_type();
669 assert!(Type::OBJECT < iu_type);
670
671 let set = Type::OBJECT
672 .children()
673 .iter()
674 .copied()
675 .collect::<BTreeSet<_>>();
676 assert!(set.contains(&iu_type));
677 }
678}
679