glib/
types.rs

1// Copyright 2015-2016, The Gtk-rs Project Developers.
2// See the COPYRIGHT file at the top-level directory of this distribution.
3// Licensed under the MIT license, see the LICENSE file or <http://opensource.org/licenses/MIT>
4
5//! Runtime type information.
6
7use glib_sys;
8use gobject_sys;
9use translate::{
10    from_glib, from_glib_none, FromGlib, FromGlibContainerAsVec, ToGlib, ToGlibContainerFromSlice,
11    ToGlibPtr, ToGlibPtrMut,
12};
13use value::{FromValue, FromValueOptional, SetValue, Value};
14
15use std::fmt;
16use std::mem;
17use std::ptr;
18
19/// A GLib or GLib-based library type
20#[derive(Clone, Copy, PartialEq, Eq)]
21pub enum Type {
22    /// An invalid `Type` used as error return value in some functions
23    Invalid,
24    /// The fundamental type corresponding to the unit type `()`
25    Unit,
26    /// The fundamental type corresponding to `i8`
27    I8,
28    /// The fundamental type corresponding to `u8`
29    U8,
30    /// The fundamental type corresponding to `bool`
31    Bool,
32    /// The fundamental type corresponding to `i32`
33    I32,
34    /// The fundamental type corresponding to `u32`
35    U32,
36    /// The fundamental type corresponding to C `long`
37    ILong,
38    /// The fundamental type corresponding to C `unsigned long`
39    ULong,
40    /// The fundamental type corresponding to `i64`
41    I64,
42    /// The fundamental type corresponding to `u64`
43    U64,
44    /// The fundamental type corresponding to `f32`
45    F32,
46    /// The fundamental type corresponding to `f64`
47    F64,
48    /// The fundamental type corresponding to `String`
49    String,
50    /// The fundamental type corresponding to a pointer
51    Pointer,
52    /// The fundamental type of GVariant
53    Variant,
54    /// The fundamental type from which all interfaces are derived
55    BaseInterface,
56    /// The fundamental type from which all enumeration types are derived
57    BaseEnum,
58    /// The fundamental type from which all flags types are derived
59    BaseFlags,
60    /// The fundamental type from which all boxed types are derived
61    BaseBoxed,
62    /// The fundamental type from which all `GParamSpec` types are derived
63    BaseParamSpec,
64    /// The fundamental type from which all objects are derived
65    BaseObject,
66    /// A non-fundamental type identified by value of type `usize`
67    Other(usize),
68}
69
70impl Type {
71    pub fn name(&self) -> String {
72        unsafe { from_glib_none(gobject_sys::g_type_name(self.to_glib())) }
73    }
74
75    pub fn qname(&self) -> ::Quark {
76        unsafe { from_glib(gobject_sys::g_type_qname(self.to_glib())) }
77    }
78
79    pub fn is_a(&self, other: &Type) -> bool {
80        unsafe { from_glib(gobject_sys::g_type_is_a(self.to_glib(), other.to_glib())) }
81    }
82
83    pub fn parent(&self) -> Option<Self> {
84        unsafe {
85            let parent = gobject_sys::g_type_parent(self.to_glib());
86            if parent == gobject_sys::G_TYPE_INVALID {
87                None
88            } else {
89                Some(from_glib(parent))
90            }
91        }
92    }
93
94    pub fn children(&self) -> Vec<Self> {
95        unsafe {
96            let mut n_children = 0u32;
97            let children = gobject_sys::g_type_children(self.to_glib(), &mut n_children);
98
99            FromGlibContainerAsVec::from_glib_full_num_as_vec(children, n_children as usize)
100        }
101    }
102
103    pub fn interfaces(&self) -> Vec<Self> {
104        unsafe {
105            let mut n_interfaces = 0u32;
106            let interfaces = gobject_sys::g_type_interfaces(self.to_glib(), &mut n_interfaces);
107
108            FromGlibContainerAsVec::from_glib_full_num_as_vec(interfaces, n_interfaces as usize)
109        }
110    }
111    pub fn interface_prerequisites(&self) -> Vec<Self> {
112        unsafe {
113            let mut n_prereqs = 0u32;
114            let prereqs =
115                gobject_sys::g_type_interface_prerequisites(self.to_glib(), &mut n_prereqs);
116
117            FromGlibContainerAsVec::from_glib_full_num_as_vec(prereqs, n_prereqs as usize)
118        }
119    }
120
121    pub fn from_name<'a, P: Into<&'a str>>(name: P) -> Option<Self> {
122        unsafe {
123            let type_ = gobject_sys::g_type_from_name(name.into().to_glib_none().0);
124            if type_ == gobject_sys::G_TYPE_INVALID {
125                None
126            } else {
127                Some(from_glib(type_))
128            }
129        }
130    }
131}
132
133impl fmt::Debug for Type {
134    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
135        f.write_str(&self.name())
136    }
137}
138
139impl fmt::Display for Type {
140    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
141        f.write_str(&self.name())
142    }
143}
144
145/// Types that are supported by GLib dynamic typing.
146pub trait StaticType {
147    /// Returns the type identifier of `Self`.
148    fn static_type() -> Type;
149}
150
151impl StaticType for Type {
152    fn static_type() -> Type {
153        unsafe { from_glib(gobject_sys::g_gtype_get_type()) }
154    }
155}
156
157impl<'a> FromValueOptional<'a> for Type {
158    unsafe fn from_value_optional(value: &'a Value) -> Option<Self> {
159        Some(from_glib(gobject_sys::g_value_get_gtype(
160            value.to_glib_none().0,
161        )))
162    }
163}
164
165impl<'a> FromValue<'a> for Type {
166    unsafe fn from_value(value: &'a Value) -> Self {
167        from_glib(gobject_sys::g_value_get_gtype(value.to_glib_none().0))
168    }
169}
170
171impl SetValue for Type {
172    unsafe fn set_value(value: &mut Value, this: &Self) {
173        gobject_sys::g_value_set_gtype(value.to_glib_none_mut().0, this.to_glib())
174    }
175}
176
177impl<'a, T: ?Sized + StaticType> StaticType for &'a T {
178    fn static_type() -> Type {
179        T::static_type()
180    }
181}
182
183impl<'a, T: ?Sized + StaticType> StaticType for &'a mut T {
184    fn static_type() -> Type {
185        T::static_type()
186    }
187}
188
189macro_rules! builtin {
190    ($name:ident, $val:ident) => {
191        impl StaticType for $name {
192            fn static_type() -> Type {
193                Type::$val
194            }
195        }
196    };
197}
198
199builtin!(bool, Bool);
200builtin!(i8, I8);
201builtin!(u8, U8);
202builtin!(i32, I32);
203builtin!(u32, U32);
204builtin!(i64, I64);
205builtin!(u64, U64);
206builtin!(f32, F32);
207builtin!(f64, F64);
208builtin!(str, String);
209builtin!(String, String);
210
211impl<'a> StaticType for [&'a str] {
212    fn static_type() -> Type {
213        unsafe { from_glib(glib_sys::g_strv_get_type()) }
214    }
215}
216
217impl StaticType for Vec<String> {
218    fn static_type() -> Type {
219        unsafe { from_glib(glib_sys::g_strv_get_type()) }
220    }
221}
222
223#[inline]
224pub unsafe fn instance_of<C: StaticType>(ptr: glib_sys::gconstpointer) -> bool {
225    from_glib(gobject_sys::g_type_check_instance_is_a(
226        ptr as *mut _,
227        <C as StaticType>::static_type().to_glib(),
228    ))
229}
230
231impl FromGlib<glib_sys::GType> for Type {
232    #[inline]
233    fn from_glib(val: glib_sys::GType) -> Type {
234        use self::Type::*;
235        match val {
236            gobject_sys::G_TYPE_INVALID => Invalid,
237            gobject_sys::G_TYPE_NONE => Unit,
238            gobject_sys::G_TYPE_INTERFACE => BaseInterface,
239            gobject_sys::G_TYPE_CHAR => I8,
240            gobject_sys::G_TYPE_UCHAR => U8,
241            gobject_sys::G_TYPE_BOOLEAN => Bool,
242            gobject_sys::G_TYPE_INT => I32,
243            gobject_sys::G_TYPE_UINT => U32,
244            gobject_sys::G_TYPE_LONG => ILong,
245            gobject_sys::G_TYPE_ULONG => ULong,
246            gobject_sys::G_TYPE_INT64 => I64,
247            gobject_sys::G_TYPE_UINT64 => U64,
248            gobject_sys::G_TYPE_ENUM => BaseEnum,
249            gobject_sys::G_TYPE_FLAGS => BaseFlags,
250            gobject_sys::G_TYPE_FLOAT => F32,
251            gobject_sys::G_TYPE_DOUBLE => F64,
252            gobject_sys::G_TYPE_STRING => String,
253            gobject_sys::G_TYPE_POINTER => Pointer,
254            gobject_sys::G_TYPE_BOXED => BaseBoxed,
255            gobject_sys::G_TYPE_PARAM => BaseParamSpec,
256            gobject_sys::G_TYPE_OBJECT => BaseObject,
257            gobject_sys::G_TYPE_VARIANT => Variant,
258            x => Other(x as usize),
259        }
260    }
261}
262
263impl ToGlib for Type {
264    type GlibType = glib_sys::GType;
265
266    fn to_glib(&self) -> glib_sys::GType {
267        use self::Type::*;
268        match *self {
269            Invalid => gobject_sys::G_TYPE_INVALID,
270            Unit => gobject_sys::G_TYPE_NONE,
271            BaseInterface => gobject_sys::G_TYPE_INTERFACE,
272            I8 => gobject_sys::G_TYPE_CHAR,
273            U8 => gobject_sys::G_TYPE_UCHAR,
274            Bool => gobject_sys::G_TYPE_BOOLEAN,
275            I32 => gobject_sys::G_TYPE_INT,
276            U32 => gobject_sys::G_TYPE_UINT,
277            ILong => gobject_sys::G_TYPE_LONG,
278            ULong => gobject_sys::G_TYPE_ULONG,
279            I64 => gobject_sys::G_TYPE_INT64,
280            U64 => gobject_sys::G_TYPE_UINT64,
281            BaseEnum => gobject_sys::G_TYPE_ENUM,
282            BaseFlags => gobject_sys::G_TYPE_FLAGS,
283            F32 => gobject_sys::G_TYPE_FLOAT,
284            F64 => gobject_sys::G_TYPE_DOUBLE,
285            String => gobject_sys::G_TYPE_STRING,
286            Pointer => gobject_sys::G_TYPE_POINTER,
287            BaseBoxed => gobject_sys::G_TYPE_BOXED,
288            BaseParamSpec => gobject_sys::G_TYPE_PARAM,
289            BaseObject => gobject_sys::G_TYPE_OBJECT,
290            Variant => gobject_sys::G_TYPE_VARIANT,
291            Other(x) => x as glib_sys::GType,
292        }
293    }
294}
295
296impl<'a> ToGlibContainerFromSlice<'a, *mut glib_sys::GType> for Type {
297    type Storage = Option<Vec<glib_sys::GType>>;
298
299    fn to_glib_none_from_slice(t: &'a [Type]) -> (*mut glib_sys::GType, Self::Storage) {
300        let mut vec = t.iter().map(ToGlib::to_glib).collect::<Vec<_>>();
301
302        (vec.as_mut_ptr(), Some(vec))
303    }
304
305    fn to_glib_container_from_slice(t: &'a [Type]) -> (*mut glib_sys::GType, Self::Storage) {
306        (Self::to_glib_full_from_slice(t), None)
307    }
308
309    fn to_glib_full_from_slice(t: &[Type]) -> *mut glib_sys::GType {
310        if t.is_empty() {
311            return ptr::null_mut();
312        }
313
314        unsafe {
315            let res = glib_sys::g_malloc0(mem::size_of::<glib_sys::GType>() * (t.len() + 1))
316                as *mut glib_sys::GType;
317            for (i, v) in t.iter().enumerate() {
318                *res.add(i) = v.to_glib();
319            }
320            res
321        }
322    }
323}
324
325impl FromGlibContainerAsVec<Type, *const glib_sys::GType> for Type {
326    unsafe fn from_glib_none_num_as_vec(ptr: *const glib_sys::GType, num: usize) -> Vec<Self> {
327        if num == 0 || ptr.is_null() {
328            return Vec::new();
329        }
330
331        let mut res = Vec::with_capacity(num);
332        for i in 0..num {
333            res.push(from_glib(*ptr.add(i)));
334        }
335        res
336    }
337
338    unsafe fn from_glib_container_num_as_vec(_: *const glib_sys::GType, _: usize) -> Vec<Self> {
339        // Can't really free a *const
340        unimplemented!();
341    }
342
343    unsafe fn from_glib_full_num_as_vec(_: *const glib_sys::GType, _: usize) -> Vec<Self> {
344        // Can't really free a *const
345        unimplemented!();
346    }
347}
348
349impl FromGlibContainerAsVec<Type, *mut glib_sys::GType> for Type {
350    unsafe fn from_glib_none_num_as_vec(ptr: *mut glib_sys::GType, num: usize) -> Vec<Self> {
351        FromGlibContainerAsVec::from_glib_none_num_as_vec(ptr as *const _, num)
352    }
353
354    unsafe fn from_glib_container_num_as_vec(ptr: *mut glib_sys::GType, num: usize) -> Vec<Self> {
355        let res = FromGlibContainerAsVec::from_glib_none_num_as_vec(ptr, num);
356        glib_sys::g_free(ptr as *mut _);
357        res
358    }
359
360    unsafe fn from_glib_full_num_as_vec(ptr: *mut glib_sys::GType, num: usize) -> Vec<Self> {
361        FromGlibContainerAsVec::from_glib_container_num_as_vec(ptr, num)
362    }
363}