1 // Take a look at the license at the top of the repository in the LICENSE file.
2 
3 //! Runtime type information.
4 
5 use crate::translate::{
6     from_glib, FromGlib, FromGlibContainerAsVec, IntoGlib, ToGlibContainerFromSlice, ToGlibPtr,
7     ToGlibPtrMut,
8 };
9 
10 use std::fmt;
11 use std::mem;
12 use std::ptr;
13 
14 /// A GLib or GLib-based library type
15 #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
16 #[doc(alias = "GType")]
17 pub struct Type(ffi::GType);
18 
19 impl Type {
20     /// An invalid `Type` used as error return value in some functions
21     pub const INVALID: Self = Self(gobject_ffi::G_TYPE_INVALID);
22 
23     /// The fundamental type corresponding to the unit type `()`
24     pub const UNIT: Self = Self(gobject_ffi::G_TYPE_NONE);
25 
26     /// The fundamental type corresponding to `i8`
27     pub const I8: Self = Self(gobject_ffi::G_TYPE_CHAR);
28 
29     /// The fundamental type corresponding to `u8`
30     pub const U8: Self = Self(gobject_ffi::G_TYPE_UCHAR);
31 
32     /// The fundamental type corresponding to `bool`
33     pub const BOOL: Self = Self(gobject_ffi::G_TYPE_BOOLEAN);
34 
35     /// The fundamental type corresponding to `i32`
36     pub const I32: Self = Self(gobject_ffi::G_TYPE_INT);
37 
38     /// The fundamental type corresponding to `u32`
39     pub const U32: Self = Self(gobject_ffi::G_TYPE_UINT);
40 
41     /// The fundamental type corresponding to C `long`
42     pub const I_LONG: Self = Self(gobject_ffi::G_TYPE_LONG);
43 
44     /// The fundamental type corresponding to C `unsigned long`
45     pub const U_LONG: Self = Self(gobject_ffi::G_TYPE_ULONG);
46 
47     /// The fundamental type corresponding to `i64`
48     pub const I64: Self = Self(gobject_ffi::G_TYPE_INT64);
49 
50     /// The fundamental type corresponding to `u64`
51     pub const U64: Self = Self(gobject_ffi::G_TYPE_UINT64);
52 
53     /// The fundamental type corresponding to `f32`
54     pub const F32: Self = Self(gobject_ffi::G_TYPE_FLOAT);
55 
56     /// The fundamental type corresponding to `f64`
57     pub const F64: Self = Self(gobject_ffi::G_TYPE_DOUBLE);
58 
59     /// The fundamental type corresponding to `String`
60     pub const STRING: Self = Self(gobject_ffi::G_TYPE_STRING);
61 
62     /// The fundamental type corresponding to a pointer
63     pub const POINTER: Self = Self(gobject_ffi::G_TYPE_POINTER);
64 
65     /// The fundamental type of GVariant
66     pub const VARIANT: Self = Self(gobject_ffi::G_TYPE_VARIANT);
67 
68     /// The fundamental type from which all interfaces are derived
69     pub const INTERFACE: Self = Self(gobject_ffi::G_TYPE_INTERFACE);
70 
71     /// The fundamental type from which all enumeration types are derived
72     pub const ENUM: Self = Self(gobject_ffi::G_TYPE_ENUM);
73 
74     /// The fundamental type from which all flags types are derived
75     pub const FLAGS: Self = Self(gobject_ffi::G_TYPE_FLAGS);
76 
77     /// The fundamental type from which all boxed types are derived
78     pub const BOXED: Self = Self(gobject_ffi::G_TYPE_BOXED);
79 
80     /// The fundamental type from which all `GParamSpec` types are derived
81     pub const PARAM_SPEC: Self = Self(gobject_ffi::G_TYPE_PARAM);
82 
83     /// The fundamental type from which all objects are derived
84     pub const OBJECT: Self = Self(gobject_ffi::G_TYPE_OBJECT);
85 
86     #[doc(alias = "g_type_name")]
name<'a>(self) -> &'a str87     pub fn name<'a>(self) -> &'a str {
88         match self.into_glib() {
89             gobject_ffi::G_TYPE_INVALID => "<invalid>",
90             x => unsafe {
91                 let ptr = gobject_ffi::g_type_name(x);
92                 std::ffi::CStr::from_ptr(ptr).to_str().unwrap()
93             },
94         }
95     }
96 
97     #[doc(alias = "g_type_qname")]
qname(self) -> crate::Quark98     pub fn qname(self) -> crate::Quark {
99         match self.into_glib() {
100             gobject_ffi::G_TYPE_INVALID => crate::Quark::from_string("<invalid>"),
101             x => unsafe { from_glib(gobject_ffi::g_type_qname(x)) },
102         }
103     }
104 
105     #[doc(alias = "g_type_is_a")]
is_a(self, other: Self) -> bool106     pub fn is_a(self, other: Self) -> bool {
107         unsafe {
108             from_glib(gobject_ffi::g_type_is_a(
109                 self.into_glib(),
110                 other.into_glib(),
111             ))
112         }
113     }
114 
115     #[doc(alias = "g_type_parent")]
parent(self) -> Option<Self>116     pub fn parent(self) -> Option<Self> {
117         unsafe {
118             let parent: Self = from_glib(gobject_ffi::g_type_parent(self.into_glib()));
119             Some(parent).filter(|t| t.is_valid())
120         }
121     }
122 
123     #[doc(alias = "g_type_children")]
children(self) -> Vec<Self>124     pub fn children(self) -> Vec<Self> {
125         unsafe {
126             let mut n_children = 0u32;
127             let children = gobject_ffi::g_type_children(self.into_glib(), &mut n_children);
128 
129             FromGlibContainerAsVec::from_glib_full_num_as_vec(children, n_children as usize)
130         }
131     }
132 
133     #[doc(alias = "g_type_interfaces")]
interfaces(self) -> Vec<Self>134     pub fn interfaces(self) -> Vec<Self> {
135         unsafe {
136             let mut n_interfaces = 0u32;
137             let interfaces = gobject_ffi::g_type_interfaces(self.into_glib(), &mut n_interfaces);
138 
139             FromGlibContainerAsVec::from_glib_full_num_as_vec(interfaces, n_interfaces as usize)
140         }
141     }
142 
143     #[doc(alias = "g_type_interface_prerequisites")]
interface_prerequisites(self) -> Vec<Self>144     pub fn interface_prerequisites(self) -> Vec<Self> {
145         match self {
146             t if !t.is_a(Self::INTERFACE) => vec![],
147             _ => unsafe {
148                 let mut n_prereqs = 0u32;
149                 let prereqs =
150                     gobject_ffi::g_type_interface_prerequisites(self.into_glib(), &mut n_prereqs);
151 
152                 FromGlibContainerAsVec::from_glib_full_num_as_vec(prereqs, n_prereqs as usize)
153             },
154         }
155     }
156 
157     #[doc(alias = "g_type_from_name")]
from_name<'a, P: Into<&'a str>>(name: P) -> Option<Self>158     pub fn from_name<'a, P: Into<&'a str>>(name: P) -> Option<Self> {
159         unsafe {
160             let type_: Self =
161                 from_glib(gobject_ffi::g_type_from_name(name.into().to_glib_none().0));
162             Some(type_).filter(|t| t.is_valid())
163         }
164     }
165 
166     /// Checks that the type is not [`INVALID`](Self::INVALID)
167     #[inline]
is_valid(self) -> bool168     pub fn is_valid(self) -> bool {
169         self != Self::INVALID
170     }
171 }
172 
173 impl fmt::Debug for Type {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result174     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
175         f.write_str(self.name())
176     }
177 }
178 
179 impl fmt::Display for Type {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result180     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
181         f.write_str(self.name())
182     }
183 }
184 
185 /// Types that are supported by GLib dynamic typing.
186 pub trait StaticType {
187     /// Returns the type identifier of `Self`.
static_type() -> Type188     fn static_type() -> Type;
189 }
190 
191 impl StaticType for Type {
192     #[doc(alias = "g_gtype_get_type")]
static_type() -> Type193     fn static_type() -> Type {
194         unsafe { from_glib(gobject_ffi::g_gtype_get_type()) }
195     }
196 }
197 
198 #[doc(hidden)]
199 impl crate::value::ValueType for Type {
200     type Type = Type;
201 }
202 
203 #[doc(hidden)]
204 unsafe impl<'a> crate::value::FromValue<'a> for Type {
205     type Checker = crate::value::GenericValueTypeChecker<Self>;
206 
from_value(value: &'a crate::Value) -> Self207     unsafe fn from_value(value: &'a crate::Value) -> Self {
208         from_glib(gobject_ffi::g_value_get_gtype(value.to_glib_none().0))
209     }
210 }
211 
212 #[doc(hidden)]
213 impl crate::value::ToValue for Type {
to_value(&self) -> crate::Value214     fn to_value(&self) -> crate::Value {
215         unsafe {
216             let mut value = crate::Value::from_type(Type::static_type());
217             gobject_ffi::g_value_set_gtype(value.to_glib_none_mut().0, self.into_glib());
218             value
219         }
220     }
221 
value_type(&self) -> crate::Type222     fn value_type(&self) -> crate::Type {
223         Type::static_type()
224     }
225 }
226 
227 impl<'a, T: ?Sized + StaticType> StaticType for &'a T {
static_type() -> Type228     fn static_type() -> Type {
229         T::static_type()
230     }
231 }
232 
233 impl<'a, T: ?Sized + StaticType> StaticType for &'a mut T {
static_type() -> Type234     fn static_type() -> Type {
235         T::static_type()
236     }
237 }
238 
239 macro_rules! builtin {
240     ($name:ty, $val:ident) => {
241         impl StaticType for $name {
242             fn static_type() -> Type {
243                 Type::$val
244             }
245         }
246     };
247 }
248 
249 #[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
250 pub struct ILong(pub libc::c_long);
251 
252 impl std::ops::Deref for ILong {
253     type Target = libc::c_long;
254 
deref(&self) -> &Self::Target255     fn deref(&self) -> &Self::Target {
256         &self.0
257     }
258 }
259 
260 impl std::ops::DerefMut for ILong {
deref_mut(&mut self) -> &mut Self::Target261     fn deref_mut(&mut self) -> &mut Self::Target {
262         &mut self.0
263     }
264 }
265 
266 impl From<libc::c_long> for ILong {
from(v: libc::c_long) -> ILong267     fn from(v: libc::c_long) -> ILong {
268         ILong(v)
269     }
270 }
271 
272 impl From<ILong> for libc::c_long {
from(v: ILong) -> libc::c_long273     fn from(v: ILong) -> libc::c_long {
274         v.0
275     }
276 }
277 
278 impl PartialEq<libc::c_long> for ILong {
eq(&self, other: &libc::c_long) -> bool279     fn eq(&self, other: &libc::c_long) -> bool {
280         &self.0 == other
281     }
282 }
283 
284 impl PartialEq<ILong> for libc::c_long {
eq(&self, other: &ILong) -> bool285     fn eq(&self, other: &ILong) -> bool {
286         self == &other.0
287     }
288 }
289 
290 impl PartialOrd<libc::c_long> for ILong {
partial_cmp(&self, other: &libc::c_long) -> Option<std::cmp::Ordering>291     fn partial_cmp(&self, other: &libc::c_long) -> Option<std::cmp::Ordering> {
292         self.0.partial_cmp(other)
293     }
294 }
295 
296 impl PartialOrd<ILong> for libc::c_long {
partial_cmp(&self, other: &ILong) -> Option<std::cmp::Ordering>297     fn partial_cmp(&self, other: &ILong) -> Option<std::cmp::Ordering> {
298         self.partial_cmp(&other.0)
299     }
300 }
301 
302 #[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
303 pub struct ULong(pub libc::c_ulong);
304 
305 impl std::ops::Deref for ULong {
306     type Target = libc::c_ulong;
307 
deref(&self) -> &Self::Target308     fn deref(&self) -> &Self::Target {
309         &self.0
310     }
311 }
312 
313 impl std::ops::DerefMut for ULong {
deref_mut(&mut self) -> &mut Self::Target314     fn deref_mut(&mut self) -> &mut Self::Target {
315         &mut self.0
316     }
317 }
318 
319 impl From<libc::c_ulong> for ULong {
from(v: libc::c_ulong) -> ULong320     fn from(v: libc::c_ulong) -> ULong {
321         ULong(v)
322     }
323 }
324 
325 impl From<ULong> for libc::c_ulong {
from(v: ULong) -> libc::c_ulong326     fn from(v: ULong) -> libc::c_ulong {
327         v.0
328     }
329 }
330 
331 impl PartialEq<libc::c_ulong> for ULong {
eq(&self, other: &libc::c_ulong) -> bool332     fn eq(&self, other: &libc::c_ulong) -> bool {
333         &self.0 == other
334     }
335 }
336 
337 impl PartialEq<ULong> for libc::c_ulong {
eq(&self, other: &ULong) -> bool338     fn eq(&self, other: &ULong) -> bool {
339         self == &other.0
340     }
341 }
342 
343 impl PartialOrd<libc::c_ulong> for ULong {
partial_cmp(&self, other: &libc::c_ulong) -> Option<std::cmp::Ordering>344     fn partial_cmp(&self, other: &libc::c_ulong) -> Option<std::cmp::Ordering> {
345         self.0.partial_cmp(other)
346     }
347 }
348 
349 impl PartialOrd<ULong> for libc::c_ulong {
partial_cmp(&self, other: &ULong) -> Option<std::cmp::Ordering>350     fn partial_cmp(&self, other: &ULong) -> Option<std::cmp::Ordering> {
351         self.partial_cmp(&other.0)
352     }
353 }
354 
355 builtin!(bool, BOOL);
356 builtin!(i8, I8);
357 builtin!(u8, U8);
358 builtin!(i32, I32);
359 builtin!(u32, U32);
360 builtin!(i64, I64);
361 builtin!(u64, U64);
362 builtin!(ILong, I_LONG);
363 builtin!(ULong, U_LONG);
364 builtin!(f32, F32);
365 builtin!(f64, F64);
366 builtin!(str, STRING);
367 builtin!(String, STRING);
368 
369 impl<'a> StaticType for [&'a str] {
static_type() -> Type370     fn static_type() -> Type {
371         unsafe { from_glib(ffi::g_strv_get_type()) }
372     }
373 }
374 
375 impl StaticType for Vec<String> {
static_type() -> Type376     fn static_type() -> Type {
377         unsafe { from_glib(ffi::g_strv_get_type()) }
378     }
379 }
380 
381 impl StaticType for () {
static_type() -> Type382     fn static_type() -> Type {
383         Type::UNIT
384     }
385 }
386 
387 #[inline]
instance_of<C: StaticType>(ptr: ffi::gconstpointer) -> bool388 pub unsafe fn instance_of<C: StaticType>(ptr: ffi::gconstpointer) -> bool {
389     from_glib(gobject_ffi::g_type_check_instance_is_a(
390         ptr as *mut _,
391         <C as StaticType>::static_type().into_glib(),
392     ))
393 }
394 
395 impl FromGlib<ffi::GType> for Type {
396     #[inline]
from_glib(val: ffi::GType) -> Self397     unsafe fn from_glib(val: ffi::GType) -> Self {
398         Self(val)
399     }
400 }
401 
402 impl IntoGlib for Type {
403     type GlibType = ffi::GType;
404 
405     #[inline]
into_glib(self) -> ffi::GType406     fn into_glib(self) -> ffi::GType {
407         self.0
408     }
409 }
410 
411 impl<'a> ToGlibContainerFromSlice<'a, *mut ffi::GType> for Type {
412     type Storage = Option<Vec<ffi::GType>>;
413 
to_glib_none_from_slice(t: &'a [Type]) -> (*mut ffi::GType, Self::Storage)414     fn to_glib_none_from_slice(t: &'a [Type]) -> (*mut ffi::GType, Self::Storage) {
415         let mut vec = t.iter().map(|t| t.into_glib()).collect::<Vec<_>>();
416 
417         (vec.as_mut_ptr(), Some(vec))
418     }
419 
to_glib_container_from_slice(t: &'a [Type]) -> (*mut ffi::GType, Self::Storage)420     fn to_glib_container_from_slice(t: &'a [Type]) -> (*mut ffi::GType, Self::Storage) {
421         (Self::to_glib_full_from_slice(t), None)
422     }
423 
to_glib_full_from_slice(t: &[Type]) -> *mut ffi::GType424     fn to_glib_full_from_slice(t: &[Type]) -> *mut ffi::GType {
425         if t.is_empty() {
426             return ptr::null_mut();
427         }
428 
429         unsafe {
430             let res =
431                 ffi::g_malloc0(mem::size_of::<ffi::GType>() * (t.len() + 1)) as *mut ffi::GType;
432             for (i, v) in t.iter().enumerate() {
433                 *res.add(i) = v.into_glib();
434             }
435             res
436         }
437     }
438 }
439 
440 impl FromGlibContainerAsVec<Type, *const ffi::GType> for Type {
from_glib_none_num_as_vec(ptr: *const ffi::GType, num: usize) -> Vec<Self>441     unsafe fn from_glib_none_num_as_vec(ptr: *const ffi::GType, num: usize) -> Vec<Self> {
442         if num == 0 || ptr.is_null() {
443             return Vec::new();
444         }
445 
446         let mut res = Vec::with_capacity(num);
447         for i in 0..num {
448             res.push(from_glib(*ptr.add(i)));
449         }
450         res
451     }
452 
from_glib_container_num_as_vec(_: *const ffi::GType, _: usize) -> Vec<Self>453     unsafe fn from_glib_container_num_as_vec(_: *const ffi::GType, _: usize) -> Vec<Self> {
454         // Can't really free a *const
455         unimplemented!();
456     }
457 
from_glib_full_num_as_vec(_: *const ffi::GType, _: usize) -> Vec<Self>458     unsafe fn from_glib_full_num_as_vec(_: *const ffi::GType, _: usize) -> Vec<Self> {
459         // Can't really free a *const
460         unimplemented!();
461     }
462 }
463 
464 impl FromGlibContainerAsVec<Type, *mut ffi::GType> for Type {
from_glib_none_num_as_vec(ptr: *mut ffi::GType, num: usize) -> Vec<Self>465     unsafe fn from_glib_none_num_as_vec(ptr: *mut ffi::GType, num: usize) -> Vec<Self> {
466         FromGlibContainerAsVec::from_glib_none_num_as_vec(ptr as *const _, num)
467     }
468 
from_glib_container_num_as_vec(ptr: *mut ffi::GType, num: usize) -> Vec<Self>469     unsafe fn from_glib_container_num_as_vec(ptr: *mut ffi::GType, num: usize) -> Vec<Self> {
470         let res = FromGlibContainerAsVec::from_glib_none_num_as_vec(ptr, num);
471         ffi::g_free(ptr as *mut _);
472         res
473     }
474 
from_glib_full_num_as_vec(ptr: *mut ffi::GType, num: usize) -> Vec<Self>475     unsafe fn from_glib_full_num_as_vec(ptr: *mut ffi::GType, num: usize) -> Vec<Self> {
476         FromGlibContainerAsVec::from_glib_container_num_as_vec(ptr, num)
477     }
478 }
479 
480 #[cfg(test)]
481 mod tests {
482     use super::*;
483     use crate::InitiallyUnowned;
484     use std::collections::{BTreeSet, HashSet};
485 
486     #[test]
invalid()487     fn invalid() {
488         let invalid = Type::INVALID;
489 
490         assert_eq!(invalid.name(), "<invalid>");
491         assert_eq!(invalid.qname(), crate::Quark::from_string("<invalid>"));
492         assert!(invalid.is_a(Type::INVALID));
493         assert!(!invalid.is_a(Type::STRING));
494         assert_eq!(invalid.parent(), None);
495         assert_eq!(invalid.children(), vec![]);
496         assert_eq!(invalid.interfaces(), vec![]);
497         assert_eq!(invalid.interface_prerequisites(), vec![]);
498         assert!(!invalid.is_valid());
499         dbg!(&invalid);
500     }
501 
502     #[test]
hash()503     fn hash() {
504         // Get this first so the type is registered
505         let iu_type = InitiallyUnowned::static_type();
506 
507         let set = Type::OBJECT.children().into_iter().collect::<HashSet<_>>();
508         assert!(set.contains(&iu_type));
509     }
510 
511     #[test]
ord()512     fn ord() {
513         // Get this first so the type is registered
514         let iu_type = InitiallyUnowned::static_type();
515         assert!(Type::OBJECT < iu_type);
516 
517         let set = Type::OBJECT.children().into_iter().collect::<BTreeSet<_>>();
518         assert!(set.contains(&iu_type));
519     }
520 }
521