1use 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::{ffi, gobject_ffi, prelude::*, translate::*, Slice, TypeFlags, TypePlugin};
16
17#[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 #[doc(alias = "G_TYPE_INVALID")]
32 pub const INVALID: Self = Self(gobject_ffi::G_TYPE_INVALID);
33
34 #[doc(alias = "G_TYPE_NONE")]
37 pub const UNIT: Self = Self(gobject_ffi::G_TYPE_NONE);
38
39 #[doc(alias = "G_TYPE_CHAR")]
42 pub const I8: Self = Self(gobject_ffi::G_TYPE_CHAR);
43
44 #[doc(alias = "G_TYPE_UCHAR")]
47 pub const U8: Self = Self(gobject_ffi::G_TYPE_UCHAR);
48
49 #[doc(alias = "G_TYPE_BOOLEAN")]
52 pub const BOOL: Self = Self(gobject_ffi::G_TYPE_BOOLEAN);
53
54 #[doc(alias = "G_TYPE_INT")]
57 pub const I32: Self = Self(gobject_ffi::G_TYPE_INT);
58
59 #[doc(alias = "G_TYPE_UINT")]
62 pub const U32: Self = Self(gobject_ffi::G_TYPE_UINT);
63
64 #[doc(alias = "G_TYPE_LONG")]
67 pub const I_LONG: Self = Self(gobject_ffi::G_TYPE_LONG);
68
69 #[doc(alias = "G_TYPE_ULONG")]
72 pub const U_LONG: Self = Self(gobject_ffi::G_TYPE_ULONG);
73
74 #[doc(alias = "G_TYPE_INT64")]
77 pub const I64: Self = Self(gobject_ffi::G_TYPE_INT64);
78
79 #[doc(alias = "G_TYPE_UINT64")]
82 pub const U64: Self = Self(gobject_ffi::G_TYPE_UINT64);
83
84 #[doc(alias = "G_TYPE_FLOAT")]
87 pub const F32: Self = Self(gobject_ffi::G_TYPE_FLOAT);
88
89 #[doc(alias = "G_TYPE_DOUBLE")]
92 pub const F64: Self = Self(gobject_ffi::G_TYPE_DOUBLE);
93
94 #[doc(alias = "G_TYPE_STRING")]
97 pub const STRING: Self = Self(gobject_ffi::G_TYPE_STRING);
98
99 #[doc(alias = "G_TYPE_POINTER")]
102 pub const POINTER: Self = Self(gobject_ffi::G_TYPE_POINTER);
103
104 #[doc(alias = "G_TYPE_VARIANT")]
107 pub const VARIANT: Self = Self(gobject_ffi::G_TYPE_VARIANT);
108
109 #[doc(alias = "G_TYPE_INTERFACE")]
112 pub const INTERFACE: Self = Self(gobject_ffi::G_TYPE_INTERFACE);
113
114 #[doc(alias = "G_TYPE_ENUM")]
117 pub const ENUM: Self = Self(gobject_ffi::G_TYPE_ENUM);
118
119 #[doc(alias = "G_TYPE_FLAGS")]
122 pub const FLAGS: Self = Self(gobject_ffi::G_TYPE_FLAGS);
123
124 #[doc(alias = "G_TYPE_BOXED")]
127 pub const BOXED: Self = Self(gobject_ffi::G_TYPE_BOXED);
128
129 #[doc(alias = "G_TYPE_PARAM")]
132 pub const PARAM_SPEC: Self = Self(gobject_ffi::G_TYPE_PARAM);
133
134 #[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 #[doc(alias = "g_type_get_plugin")]
227 pub fn plugin(self) -> Option<TypePlugin> {
228 unsafe {
229 let plugin_ptr = gobject_ffi::g_type_get_plugin(self.into_glib());
230 if plugin_ptr.is_null() {
231 None
232 } else {
233 Some(TypePlugin::from_glib_none(plugin_ptr))
234 }
235 }
236 }
237
238 #[doc(alias = "g_type_register_dynamic")]
239 pub fn register_dynamic(
240 parent_type: Self,
241 name: impl IntoGStr,
242 plugin: &TypePlugin,
243 flags: TypeFlags,
244 ) -> Self {
245 unsafe {
246 name.run_with_gstr(|name| {
247 Self::from_glib(gobject_ffi::g_type_register_dynamic(
248 parent_type.into_glib(),
249 name.as_ptr(),
250 plugin.as_ptr(),
251 flags.into_glib(),
252 ))
253 })
254 }
255 }
256
257 #[doc(alias = "g_type_add_interface_dynamic")]
258 pub fn add_interface_dynamic(self, interface_type: Self, plugin: &TypePlugin) {
259 unsafe {
260 gobject_ffi::g_type_add_interface_dynamic(
261 self.into_glib(),
262 interface_type.into_glib(),
263 plugin.as_ptr(),
264 );
265 }
266 }
267
268 #[inline]
271 pub fn is_valid(self) -> bool {
272 self != Self::INVALID
273 }
274}
275
276impl fmt::Debug for Type {
277 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
278 f.write_str(self.name())
279 }
280}
281
282impl fmt::Display for Type {
283 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
284 f.write_str(self.name())
285 }
286}
287
288pub trait StaticType {
291 fn static_type() -> Type;
294}
295
296impl StaticType for Type {
297 #[doc(alias = "g_gtype_get_type")]
298 #[inline]
299 fn static_type() -> Type {
300 unsafe { from_glib(gobject_ffi::g_gtype_get_type()) }
301 }
302}
303
304pub trait StaticTypeExt {
305 #[doc(alias = "g_type_ensure")]
308 fn ensure_type();
309}
310
311impl<T: StaticType> StaticTypeExt for T {
312 #[inline]
313 fn ensure_type() {
314 T::static_type();
315 }
316}
317
318#[doc(hidden)]
319impl crate::value::ValueType for Type {
320 type Type = Type;
321}
322
323#[doc(hidden)]
324unsafe impl<'a> crate::value::FromValue<'a> for Type {
325 type Checker = crate::value::GenericValueTypeChecker<Self>;
326
327 #[inline]
328 unsafe fn from_value(value: &'a crate::Value) -> Self {
329 from_glib(gobject_ffi::g_value_get_gtype(value.to_glib_none().0))
330 }
331}
332
333#[doc(hidden)]
334impl crate::value::ToValue for Type {
335 #[inline]
336 fn to_value(&self) -> crate::Value {
337 unsafe {
338 let mut value = crate::Value::from_type_unchecked(Type::static_type());
339 gobject_ffi::g_value_set_gtype(value.to_glib_none_mut().0, self.into_glib());
340 value
341 }
342 }
343
344 #[inline]
345 fn value_type(&self) -> crate::Type {
346 Type::static_type()
347 }
348}
349
350#[doc(hidden)]
351impl From<Type> for crate::Value {
352 #[inline]
353 fn from(t: Type) -> Self {
354 crate::value::ToValue::to_value(&t)
355 }
356}
357
358impl<T: ?Sized + StaticType> StaticType for &'_ T {
359 #[inline]
360 fn static_type() -> Type {
361 T::static_type()
362 }
363}
364
365impl<T: ?Sized + StaticType> StaticType for &'_ mut T {
366 #[inline]
367 fn static_type() -> Type {
368 T::static_type()
369 }
370}
371
372macro_rules! builtin {
373 ($name:ty, $val:ident) => {
374 impl StaticType for $name {
375 #[inline]
376 fn static_type() -> Type {
377 Type::$val
378 }
379 }
380 };
381}
382
383pub type Pointer = ffi::gpointer;
388
389pub type Pointee = libc::c_void;
405
406impl StaticType for ptr::NonNull<Pointee> {
407 #[inline]
408 fn static_type() -> Type {
409 Pointer::static_type()
410 }
411}
412
413#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
414pub struct ILong(pub libc::c_long);
415
416impl std::ops::Deref for ILong {
417 type Target = libc::c_long;
418
419 #[inline]
420 fn deref(&self) -> &Self::Target {
421 &self.0
422 }
423}
424
425impl std::ops::DerefMut for ILong {
426 #[inline]
427 fn deref_mut(&mut self) -> &mut Self::Target {
428 &mut self.0
429 }
430}
431
432impl From<libc::c_long> for ILong {
433 #[inline]
434 fn from(v: libc::c_long) -> ILong {
435 ILong(v)
436 }
437}
438
439impl From<ILong> for libc::c_long {
440 #[inline]
441 fn from(v: ILong) -> libc::c_long {
442 v.0
443 }
444}
445
446impl PartialEq<libc::c_long> for ILong {
447 #[inline]
448 fn eq(&self, other: &libc::c_long) -> bool {
449 &self.0 == other
450 }
451}
452
453impl PartialEq<ILong> for libc::c_long {
454 #[inline]
455 fn eq(&self, other: &ILong) -> bool {
456 self == &other.0
457 }
458}
459
460impl PartialOrd<libc::c_long> for ILong {
461 #[inline]
462 fn partial_cmp(&self, other: &libc::c_long) -> Option<std::cmp::Ordering> {
463 self.0.partial_cmp(other)
464 }
465}
466
467impl PartialOrd<ILong> for libc::c_long {
468 #[inline]
469 fn partial_cmp(&self, other: &ILong) -> Option<std::cmp::Ordering> {
470 self.partial_cmp(&other.0)
471 }
472}
473
474#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
475pub struct ULong(pub libc::c_ulong);
476
477impl std::ops::Deref for ULong {
478 type Target = libc::c_ulong;
479
480 #[inline]
481 fn deref(&self) -> &Self::Target {
482 &self.0
483 }
484}
485
486impl std::ops::DerefMut for ULong {
487 #[inline]
488 fn deref_mut(&mut self) -> &mut Self::Target {
489 &mut self.0
490 }
491}
492
493impl From<libc::c_ulong> for ULong {
494 #[inline]
495 fn from(v: libc::c_ulong) -> ULong {
496 ULong(v)
497 }
498}
499
500impl From<ULong> for libc::c_ulong {
501 #[inline]
502 fn from(v: ULong) -> libc::c_ulong {
503 v.0
504 }
505}
506
507impl PartialEq<libc::c_ulong> for ULong {
508 #[inline]
509 fn eq(&self, other: &libc::c_ulong) -> bool {
510 &self.0 == other
511 }
512}
513
514impl PartialEq<ULong> for libc::c_ulong {
515 #[inline]
516 fn eq(&self, other: &ULong) -> bool {
517 self == &other.0
518 }
519}
520
521impl PartialOrd<libc::c_ulong> for ULong {
522 #[inline]
523 fn partial_cmp(&self, other: &libc::c_ulong) -> Option<std::cmp::Ordering> {
524 self.0.partial_cmp(other)
525 }
526}
527
528impl PartialOrd<ULong> for libc::c_ulong {
529 #[inline]
530 fn partial_cmp(&self, other: &ULong) -> Option<std::cmp::Ordering> {
531 self.partial_cmp(&other.0)
532 }
533}
534
535builtin!(bool, BOOL);
536builtin!(i8, I8);
537builtin!(NonZeroI8, I8);
538builtin!(u8, U8);
539builtin!(NonZeroU8, U8);
540builtin!(i32, I32);
541builtin!(NonZeroI32, I32);
542builtin!(u32, U32);
543builtin!(NonZeroU32, U32);
544builtin!(i64, I64);
545builtin!(NonZeroI64, I64);
546builtin!(u64, U64);
547builtin!(NonZeroU64, U64);
548builtin!(ILong, I_LONG);
549builtin!(ULong, U_LONG);
550builtin!(f32, F32);
551builtin!(f64, F64);
552builtin!(str, STRING);
553builtin!(String, STRING);
554builtin!(PathBuf, STRING);
555builtin!(Path, STRING);
556builtin!(Pointer, POINTER);
557
558impl StaticType for [&'_ str] {
559 #[inline]
560 fn static_type() -> Type {
561 unsafe { from_glib(ffi::g_strv_get_type()) }
562 }
563}
564
565impl StaticType for Vec<String> {
566 #[inline]
567 fn static_type() -> Type {
568 unsafe { from_glib(ffi::g_strv_get_type()) }
569 }
570}
571
572impl StaticType for () {
573 #[inline]
574 fn static_type() -> Type {
575 Type::UNIT
576 }
577}
578
579#[inline]
580pub unsafe fn instance_of<C: StaticType>(ptr: ffi::gconstpointer) -> bool {
581 from_glib(gobject_ffi::g_type_check_instance_is_a(
582 ptr as *mut _,
583 <C as StaticType>::static_type().into_glib(),
584 ))
585}
586
587impl FromGlib<ffi::GType> for Type {
588 #[inline]
589 unsafe fn from_glib(val: ffi::GType) -> Self {
590 Self(val)
591 }
592}
593
594impl IntoGlib for Type {
595 type GlibType = ffi::GType;
596
597 #[inline]
598 fn into_glib(self) -> ffi::GType {
599 self.0
600 }
601}
602
603impl<'a> ToGlibContainerFromSlice<'a, *mut ffi::GType> for Type {
604 type Storage = PhantomData<&'a [Type]>;
605
606 #[inline]
607 fn to_glib_none_from_slice(t: &'a [Type]) -> (*mut ffi::GType, Self::Storage) {
608 (t.as_ptr() as *mut ffi::GType, PhantomData)
609 }
610
611 #[inline]
612 fn to_glib_container_from_slice(t: &'a [Type]) -> (*mut ffi::GType, Self::Storage) {
613 (Self::to_glib_full_from_slice(t), PhantomData)
614 }
615
616 fn to_glib_full_from_slice(t: &[Type]) -> *mut ffi::GType {
617 if t.is_empty() {
618 return ptr::null_mut();
619 }
620
621 unsafe {
622 let res =
623 ffi::g_malloc(mem::size_of::<ffi::GType>() * (t.len() + 1)) as *mut ffi::GType;
624 std::ptr::copy_nonoverlapping(t.as_ptr() as *const ffi::GType, res, t.len());
625 *res.add(t.len()) = 0;
626 res
627 }
628 }
629}
630
631impl FromGlibContainerAsVec<Type, *const ffi::GType> for Type {
632 unsafe fn from_glib_none_num_as_vec(ptr: *const ffi::GType, num: usize) -> Vec<Self> {
633 if num == 0 || ptr.is_null() {
634 return Vec::new();
635 }
636
637 let mut res = Vec::<Self>::with_capacity(num);
638 let res_ptr = res.as_mut_ptr() as *mut ffi::GType;
639 std::ptr::copy_nonoverlapping(ptr, res_ptr, num);
640 res.set_len(num);
641 res
642 }
643
644 unsafe fn from_glib_container_num_as_vec(_: *const ffi::GType, _: usize) -> Vec<Self> {
645 unimplemented!();
647 }
648
649 unsafe fn from_glib_full_num_as_vec(_: *const ffi::GType, _: usize) -> Vec<Self> {
650 unimplemented!();
652 }
653}
654
655impl FromGlibContainerAsVec<Type, *mut ffi::GType> for Type {
656 unsafe fn from_glib_none_num_as_vec(ptr: *mut ffi::GType, num: usize) -> Vec<Self> {
657 FromGlibContainerAsVec::from_glib_none_num_as_vec(ptr as *const _, num)
658 }
659
660 unsafe fn from_glib_container_num_as_vec(ptr: *mut ffi::GType, num: usize) -> Vec<Self> {
661 let res = FromGlibContainerAsVec::from_glib_none_num_as_vec(ptr, num);
662 ffi::g_free(ptr as *mut _);
663 res
664 }
665
666 unsafe fn from_glib_full_num_as_vec(ptr: *mut ffi::GType, num: usize) -> Vec<Self> {
667 FromGlibContainerAsVec::from_glib_container_num_as_vec(ptr, num)
668 }
669}
670
671#[cfg(test)]
672mod tests {
673 use std::collections::{BTreeSet, HashSet};
674
675 use super::*;
676 use crate::InitiallyUnowned;
677
678 #[test]
679 fn invalid() {
680 let invalid = Type::INVALID;
681
682 assert_eq!(invalid.name(), "<invalid>");
683 assert_eq!(invalid.qname(), crate::Quark::from_str("<invalid>"));
684 assert!(invalid.is_a(Type::INVALID));
685 assert!(!invalid.is_a(Type::STRING));
686 assert_eq!(invalid.parent(), None);
687 assert!(invalid.children().is_empty());
688 assert!(invalid.interfaces().is_empty());
689 assert!(invalid.interface_prerequisites().is_empty());
690 assert!(!invalid.is_valid());
691 dbg!(&invalid);
692 }
693
694 #[test]
695 fn hash() {
696 let iu_type = InitiallyUnowned::static_type();
698
699 let set = Type::OBJECT
700 .children()
701 .iter()
702 .copied()
703 .collect::<HashSet<_>>();
704 assert!(set.contains(&iu_type));
705 }
706
707 #[test]
708 fn ord() {
709 let iu_type = InitiallyUnowned::static_type();
711 assert!(Type::OBJECT < iu_type);
712
713 let set = Type::OBJECT
714 .children()
715 .iter()
716 .copied()
717 .collect::<BTreeSet<_>>();
718 assert!(set.contains(&iu_type));
719 }
720}