glib/
variant_type.rs

1// Copyright 2013-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
5use glib_sys;
6use gobject_sys;
7use std::borrow::{Borrow, Cow, ToOwned};
8use std::cmp::{Eq, PartialEq};
9use std::fmt;
10use std::hash::{Hash, Hasher};
11use std::ops::Deref;
12use std::slice;
13use translate::*;
14use types::StaticType;
15use types::Type;
16use value::{FromValueOptional, SetValue, SetValueOptional, Value};
17
18/// Describes `Variant` types.
19///
20/// The `Variant` type system (based on the D-Bus one) describes types with
21/// "type strings". `VariantType` is an owned immutable type string (you can
22/// think of it as a `Box<str>` statically guaranteed to be a valid type
23/// string), `&VariantTy` is a borrowed one (like `&str`).
24pub struct VariantType {
25    // GVariantType* essentially is a char*, that always is valid UTF-8 but
26    // isn't NUL-terminated.
27    ptr: *mut glib_sys::GVariantType,
28    // We query the length on creation assuming it's cheap (because type strings
29    // are short) and likely to happen anyway.
30    len: usize,
31}
32
33impl VariantType {
34    /// Tries to create a `VariantType` from a string slice.
35    ///
36    /// Returns `Ok` if the string is a valid type string, `Err` otherwise.
37    pub fn new(type_string: &str) -> Result<VariantType, ()> {
38        VariantTy::new(type_string).map(ToOwned::to_owned)
39    }
40}
41
42unsafe impl Send for VariantType {}
43unsafe impl Sync for VariantType {}
44
45impl Drop for VariantType {
46    fn drop(&mut self) {
47        unsafe { glib_sys::g_variant_type_free(self.ptr) }
48    }
49}
50
51impl Borrow<VariantTy> for VariantType {
52    fn borrow(&self) -> &VariantTy {
53        self
54    }
55}
56
57impl Clone for VariantType {
58    fn clone(&self) -> VariantType {
59        unsafe {
60            VariantType {
61                ptr: glib_sys::g_variant_type_copy(self.ptr),
62                len: self.len,
63            }
64        }
65    }
66}
67
68impl Deref for VariantType {
69    type Target = VariantTy;
70    fn deref(&self) -> &VariantTy {
71        unsafe {
72            &*(slice::from_raw_parts(self.ptr as *const u8, self.len) as *const [u8]
73                as *const VariantTy)
74        }
75    }
76}
77
78impl fmt::Debug for VariantType {
79    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
80        <VariantTy as fmt::Debug>::fmt(self, f)
81    }
82}
83
84impl fmt::Display for VariantType {
85    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
86        f.write_str(self.to_str())
87    }
88}
89
90impl Hash for VariantType {
91    fn hash<H: Hasher>(&self, state: &mut H) {
92        <VariantTy as Hash>::hash(self, state)
93    }
94}
95
96impl<'a> Into<Cow<'a, VariantTy>> for VariantType {
97    fn into(self) -> Cow<'a, VariantTy> {
98        Cow::Owned(self)
99    }
100}
101
102#[doc(hidden)]
103impl<'a> ToGlibPtrMut<'a, *mut glib_sys::GVariantType> for VariantType {
104    type Storage = &'a mut Self;
105
106    fn to_glib_none_mut(&'a mut self) -> StashMut<'a, *mut glib_sys::GVariantType, Self> {
107        StashMut(self.ptr, self)
108    }
109}
110
111#[doc(hidden)]
112impl FromGlibPtrNone<*const glib_sys::GVariantType> for VariantType {
113    unsafe fn from_glib_none(ptr: *const glib_sys::GVariantType) -> VariantType {
114        VariantTy::from_ptr(ptr).to_owned()
115    }
116}
117
118#[doc(hidden)]
119impl FromGlibPtrFull<*const glib_sys::GVariantType> for VariantType {
120    unsafe fn from_glib_full(ptr: *const glib_sys::GVariantType) -> VariantType {
121        // Don't assume ownership of a const pointer.
122        // A transfer: full annotation on a `const GVariantType*` is likely a bug.
123        VariantTy::from_ptr(ptr).to_owned()
124    }
125}
126
127/// Describes `Variant` types.
128///
129/// This is a borrowed counterpart of [`VariantType`](struct.VariantType.html).
130/// Essentially it's a `str` statically guaranteed to be a valid type string.
131#[derive(Debug, PartialEq, Eq, Hash)]
132pub struct VariantTy {
133    inner: str,
134}
135
136impl VariantTy {
137    /// Tries to create a `&VariantTy` from a string slice.
138    ///
139    /// Returns `Ok` if the string is a valid type string, `Err` otherwise.
140    pub fn new(type_string: &str) -> Result<&VariantTy, ()> {
141        let ptr = type_string.as_ptr();
142        let limit = ptr as usize + type_string.len();
143        let mut end = 0_usize;
144        unsafe {
145            let ok = from_glib(glib_sys::g_variant_type_string_scan(
146                ptr as *const _,
147                limit as *const _,
148                &mut end as *mut usize as *mut _,
149            ));
150            if ok && end == limit {
151                Ok(&*(type_string.as_bytes() as *const [u8] as *const VariantTy))
152            } else {
153                Err(())
154            }
155        }
156    }
157
158    /// Converts a type string into `&VariantTy` without any checks.
159    pub unsafe fn from_str_unchecked(type_string: &str) -> &VariantTy {
160        &*(type_string as *const str as *const VariantTy)
161    }
162
163    /// Creates `&VariantTy` with a wildcard lifetime from a `GVariantType`
164    /// pointer.
165    #[doc(hidden)]
166    pub unsafe fn from_ptr<'a>(ptr: *const glib_sys::GVariantType) -> &'a VariantTy {
167        let len = glib_sys::g_variant_type_get_string_length(ptr) as usize;
168        &*(slice::from_raw_parts(ptr as *const u8, len) as *const [u8] as *const VariantTy)
169    }
170
171    /// Returns a `GVariantType` pointer.
172    #[doc(hidden)]
173    pub fn as_ptr(&self) -> *const glib_sys::GVariantType {
174        self.inner.as_ptr() as *const _
175    }
176
177    /// Converts to a string slice.
178    pub fn to_str(&self) -> &str {
179        &self.inner
180    }
181}
182
183unsafe impl Sync for VariantTy {}
184
185#[doc(hidden)]
186impl<'a> ToGlibPtr<'a, *const glib_sys::GVariantType> for VariantTy {
187    type Storage = &'a Self;
188
189    fn to_glib_none(&'a self) -> Stash<'a, *const glib_sys::GVariantType, Self> {
190        Stash(self.as_ptr(), self)
191    }
192}
193
194impl fmt::Display for VariantTy {
195    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
196        f.write_str(self.to_str())
197    }
198}
199
200impl<'a> Into<Cow<'a, VariantTy>> for &'a VariantTy {
201    fn into(self) -> Cow<'a, VariantTy> {
202        Cow::Borrowed(self)
203    }
204}
205
206impl ToOwned for VariantTy {
207    type Owned = VariantType;
208
209    fn to_owned(&self) -> VariantType {
210        unsafe {
211            VariantType {
212                ptr: glib_sys::g_variant_type_copy(self.as_ptr()),
213                len: self.inner.len(),
214            }
215        }
216    }
217}
218
219impl StaticType for VariantTy {
220    fn static_type() -> Type {
221        unsafe { from_glib(glib_sys::g_variant_type_get_gtype()) }
222    }
223}
224
225impl SetValue for VariantTy {
226    unsafe fn set_value(value: &mut Value, this: &Self) {
227        gobject_sys::g_value_set_boxed(
228            value.to_glib_none_mut().0,
229            this.to_glib_none().0 as glib_sys::gpointer,
230        )
231    }
232}
233
234impl SetValueOptional for VariantTy {
235    unsafe fn set_value_optional(value: &mut Value, this: Option<&Self>) {
236        use std::ptr;
237        let p = match this {
238            Some(ref t) => t.to_glib_none().0 as glib_sys::gpointer,
239            None => ptr::null(),
240        };
241        gobject_sys::g_value_set_boxed(value.to_glib_none_mut().0, p)
242    }
243}
244
245impl<'a> FromValueOptional<'a> for &'a VariantTy {
246    unsafe fn from_value_optional(value: &'a Value) -> Option<Self> {
247        let cvty =
248            gobject_sys::g_value_get_boxed(value.to_glib_none().0) as *mut glib_sys::GVariantType;
249        if cvty.is_null() {
250            None
251        } else {
252            Some(VariantTy::from_ptr(cvty))
253        }
254    }
255}
256
257impl StaticType for VariantType {
258    fn static_type() -> Type {
259        unsafe { from_glib(glib_sys::g_variant_type_get_gtype()) }
260    }
261}
262
263impl SetValue for VariantType {
264    unsafe fn set_value(value: &mut Value, this: &Self) {
265        gobject_sys::g_value_set_boxed(
266            value.to_glib_none_mut().0,
267            this.to_glib_none().0 as glib_sys::gpointer,
268        )
269    }
270}
271
272impl SetValueOptional for VariantType {
273    unsafe fn set_value_optional(value: &mut Value, this: Option<&Self>) {
274        use std::ptr;
275        let p = match this {
276            Some(ref t) => t.to_glib_none().0 as glib_sys::gpointer,
277            None => ptr::null(),
278        };
279        gobject_sys::g_value_set_boxed(value.to_glib_none_mut().0, p)
280    }
281}
282
283impl<'a> FromValueOptional<'a> for VariantType {
284    unsafe fn from_value_optional(value: &'a Value) -> Option<Self> {
285        Option::<VariantType>::from_glib_none(
286            gobject_sys::g_value_get_boxed(value.to_glib_none().0) as *mut glib_sys::GVariantType,
287        )
288    }
289}
290
291impl PartialEq for VariantType {
292    #[inline]
293    fn eq(&self, other: &Self) -> bool {
294        <VariantTy as PartialEq>::eq(self, other)
295    }
296}
297
298macro_rules! impl_eq {
299    ($lhs:ty, $rhs: ty) => {
300        impl<'a, 'b> PartialEq<$rhs> for $lhs {
301            #[inline]
302            fn eq(&self, other: &$rhs) -> bool {
303                <VariantTy as PartialEq>::eq(self, other)
304            }
305        }
306
307        impl<'a, 'b> PartialEq<$lhs> for $rhs {
308            #[inline]
309            fn eq(&self, other: &$lhs) -> bool {
310                <VariantTy as PartialEq>::eq(self, other)
311            }
312        }
313    };
314}
315
316impl_eq!(VariantType, VariantTy);
317impl_eq!(VariantType, &'a VariantTy);
318impl_eq!(VariantType, Cow<'a, VariantTy>);
319impl_eq!(&'a VariantTy, Cow<'b, VariantTy>);
320
321macro_rules! impl_str_eq {
322    ($lhs:ty, $rhs: ty) => {
323        impl<'a, 'b> PartialEq<$rhs> for $lhs {
324            #[inline]
325            fn eq(&self, other: &$rhs) -> bool {
326                self.to_str().eq(&other[..])
327            }
328        }
329
330        impl<'a, 'b> PartialEq<$lhs> for $rhs {
331            #[inline]
332            fn eq(&self, other: &$lhs) -> bool {
333                self[..].eq(other.to_str())
334            }
335        }
336    };
337}
338
339impl_str_eq!(VariantTy, str);
340impl_str_eq!(VariantTy, &'a str);
341impl_str_eq!(&'a VariantTy, str);
342impl_str_eq!(VariantTy, String);
343impl_str_eq!(&'a VariantTy, String);
344impl_str_eq!(VariantType, str);
345impl_str_eq!(VariantType, &'a str);
346impl_str_eq!(VariantType, String);
347
348impl Eq for VariantType {}
349
350#[cfg(test)]
351mod tests {
352    use super::*;
353    use glib_sys;
354    use translate::*;
355    use value::ToValue;
356
357    unsafe fn equal<T, U>(ptr1: *const T, ptr2: *const U) -> bool {
358        from_glib(glib_sys::g_variant_type_equal(
359            ptr1 as *const _,
360            ptr2 as *const _,
361        ))
362    }
363
364    #[test]
365    fn new() {
366        let ty = VariantTy::new("((iii)s)").unwrap();
367        unsafe {
368            assert!(equal(ty.as_ptr(), b"((iii)s)\0" as *const u8));
369        }
370    }
371
372    #[test]
373    fn new_empty() {
374        assert!(VariantTy::new("").is_err());
375    }
376
377    #[test]
378    fn new_with_nul() {
379        assert!(VariantTy::new("((iii\0)s)").is_err());
380    }
381
382    #[test]
383    fn new_too_short() {
384        assert!(VariantTy::new("((iii").is_err());
385    }
386
387    #[test]
388    fn new_too_long() {
389        assert!(VariantTy::new("(iii)s").is_err());
390    }
391
392    #[test]
393    fn eq() {
394        let ty1 = VariantTy::new("((iii)s)").unwrap();
395        let ty2 = VariantTy::new("((iii)s)").unwrap();
396        assert_eq!(ty1, ty2);
397        assert_eq!(ty1, "((iii)s)");
398        unsafe {
399            assert!(equal(ty1.as_ptr(), ty2.as_ptr()));
400        }
401    }
402
403    #[test]
404    fn ne() {
405        let ty1 = VariantTy::new("((iii)s)").unwrap();
406        let ty2 = VariantTy::new("((iii)o)").unwrap();
407        assert!(ty1 != ty2);
408        assert!(ty1 != "((iii)o)");
409        unsafe {
410            assert!(!equal(ty1.as_ptr(), ty2.as_ptr()));
411        }
412    }
413
414    #[test]
415    fn from_bytes() {
416        unsafe {
417            let ty = VariantTy::from_ptr(b"((iii)s)" as *const u8 as *const _);
418            assert_eq!(ty, "((iii)s)");
419            assert!(equal(ty.as_ptr(), "((iii)s)".as_ptr()));
420        }
421    }
422
423    #[test]
424    fn to_owned() {
425        let ty1 = VariantTy::new("((iii)s)").unwrap();
426        let ty2 = ty1.to_owned();
427        assert_eq!(ty1, ty2);
428        assert_eq!(ty2, "((iii)s)");
429        unsafe {
430            assert!(equal(ty1.as_ptr(), ty2.as_ptr()));
431        }
432    }
433
434    #[test]
435    fn value() {
436        let ty1 = VariantType::new("*").unwrap();
437        let tyv = ty1.to_value();
438        let ty2 = tyv.get::<VariantType>().unwrap();
439        assert_eq!(ty1, ty2);
440
441        let ty3 = VariantTy::new("*").unwrap();
442        let tyv2 = ty1.to_value();
443        let ty4 = tyv2.get::<VariantType>().unwrap();
444        assert_eq!(ty3, ty4);
445
446        assert_eq!(VariantTy::static_type(), VariantTy::static_type());
447    }
448
449}