1use 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
18pub struct VariantType {
25 ptr: *mut glib_sys::GVariantType,
28 len: usize,
31}
32
33impl VariantType {
34 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 VariantTy::from_ptr(ptr).to_owned()
124 }
125}
126
127#[derive(Debug, PartialEq, Eq, Hash)]
132pub struct VariantTy {
133 inner: str,
134}
135
136impl VariantTy {
137 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 pub unsafe fn from_str_unchecked(type_string: &str) -> &VariantTy {
160 &*(type_string as *const str as *const VariantTy)
161 }
162
163 #[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 #[doc(hidden)]
173 pub fn as_ptr(&self) -> *const glib_sys::GVariantType {
174 self.inner.as_ptr() as *const _
175 }
176
177 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}