1// Take a look at the license at the top of the repository in the LICENSE file.
2
3use std::{
4 borrow::{Borrow, Cow, ToOwned},
5 cmp::{Eq, PartialEq},
6 fmt,
7 hash::{Hash, Hasher},
8 iter,
9 marker::PhantomData,
10 ops::Deref,
11 ptr, slice,
12 str::FromStr,
13};
14
15use crate::{prelude::*, translate::*, BoolError, Type};
16
17// rustdoc-stripper-ignore-next
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`).
24#[doc(alias = "GVariantType")]
25pub struct VariantType {
26 // GVariantType* essentially is a char*, that always is valid UTF-8 but
27 // isn't NUL-terminated.
28 ptr: ptr::NonNull<ffi::GVariantType>,
29 // We query the length on creation assuming it's cheap (because type strings
30 // are short) and likely to happen anyway.
31 len: usize,
32}
33
34impl VariantType {
35 // rustdoc-stripper-ignore-next
36 /// Tries to create a `VariantType` from a string slice.
37 ///
38 /// Returns `Ok` if the string is a valid type string, `Err` otherwise.
39 pub fn new(type_string: &str) -> Result<VariantType, BoolError> {
40 VariantTy::new(type_string).map(ToOwned::to_owned)
41 }
42
43 // rustdoc-stripper-ignore-next
44 /// Creates a `VariantType` from a key and value type.
45 #[doc(alias = "g_variant_type_new_dict_entry")]
46 pub fn new_dict_entry(key_type: &VariantTy, value_type: &VariantTy) -> VariantType {
47 unsafe {
48 from_glib_full(ffi::g_variant_type_new_dict_entry(
49 key_type.to_glib_none().0,
50 value_type.to_glib_none().0,
51 ))
52 }
53 }
54
55 // rustdoc-stripper-ignore-next
56 /// Creates a `VariantType` from an array element type.
57 #[doc(alias = "g_variant_type_new_array")]
58 pub fn new_array(elem_type: &VariantTy) -> VariantType {
59 unsafe { from_glib_full(ffi::g_variant_type_new_array(elem_type.to_glib_none().0)) }
60 }
61
62 // rustdoc-stripper-ignore-next
63 /// Creates a `VariantType` from a maybe element type.
64 #[doc(alias = "g_variant_type_new_maybe")]
65 pub fn new_maybe(child_type: &VariantTy) -> VariantType {
66 unsafe { from_glib_full(ffi::g_variant_type_new_maybe(child_type.to_glib_none().0)) }
67 }
68
69 // rustdoc-stripper-ignore-next
70 /// Creates a `VariantType` from a maybe element type.
71 #[doc(alias = "g_variant_type_new_tuple")]
72 pub fn new_tuple(items: impl IntoIterator<Item = impl AsRef<VariantTy>>) -> VariantType {
73 let mut builder = crate::GStringBuilder::new("(");
74
75 for ty in items {
76 builder.append(ty.as_ref().as_str());
77 }
78
79 builder.append_c(')');
80
81 VariantType::from_string(builder.into_string()).unwrap()
82 }
83
84 // rustdoc-stripper-ignore-next
85 /// Tries to create a `VariantType` from an owned string.
86 ///
87 /// Returns `Ok` if the string is a valid type string, `Err` otherwise.
88 pub fn from_string(type_string: impl Into<crate::GString>) -> Result<VariantType, BoolError> {
89 let type_string = type_string.into();
90 VariantTy::new(&type_string)?;
91
92 let len = type_string.len();
93 unsafe {
94 let ptr = type_string.into_glib_ptr();
95
96 Ok(VariantType {
97 ptr: ptr::NonNull::new_unchecked(ptr as *mut ffi::GVariantType),
98 len,
99 })
100 }
101 }
102}
103
104unsafe impl Send for VariantType {}
105unsafe impl Sync for VariantType {}
106
107impl Drop for VariantType {
108 #[inline]
109 fn drop(&mut self) {
110 unsafe { ffi::g_variant_type_free(self.ptr.as_ptr()) }
111 }
112}
113
114impl AsRef<VariantTy> for VariantType {
115 #[inline]
116 fn as_ref(&self) -> &VariantTy {
117 self
118 }
119}
120
121impl Borrow<VariantTy> for VariantType {
122 #[inline]
123 fn borrow(&self) -> &VariantTy {
124 self
125 }
126}
127
128impl Clone for VariantType {
129 #[inline]
130 fn clone(&self) -> VariantType {
131 unsafe {
132 VariantType {
133 ptr: ptr::NonNull::new_unchecked(ptr:ffi::g_variant_type_copy(self.ptr.as_ptr())),
134 len: self.len,
135 }
136 }
137 }
138}
139
140impl Deref for VariantType {
141 type Target = VariantTy;
142
143 #[allow(clippy::cast_slice_from_raw_parts)]
144 #[inline]
145 fn deref(&self) -> &VariantTy {
146 unsafe {
147 &*(slice::from_raw_parts(self.ptr.as_ptr() as *const u8, self.len) as *const [u8]
148 as *const VariantTy)
149 }
150 }
151}
152
153impl fmt::Debug for VariantType {
154 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
155 <VariantTy as fmt::Debug>::fmt(self, f)
156 }
157}
158
159impl fmt::Display for VariantType {
160 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
161 f.write_str(self.as_str())
162 }
163}
164
165impl FromStr for VariantType {
166 type Err = BoolError;
167
168 fn from_str(s: &str) -> Result<Self, Self::Err> {
169 Self::new(type_string:s)
170 }
171}
172
173impl Hash for VariantType {
174 #[inline]
175 fn hash<H: Hasher>(&self, state: &mut H) {
176 <VariantTy as Hash>::hash(self, state)
177 }
178}
179
180impl<'a> From<VariantType> for Cow<'a, VariantTy> {
181 #[inline]
182 fn from(ty: VariantType) -> Cow<'a, VariantTy> {
183 Cow::Owned(ty)
184 }
185}
186
187#[doc(hidden)]
188impl IntoGlibPtr<*mut ffi::GVariantType> for VariantType {
189 #[inline]
190 unsafe fn into_glib_ptr(self) -> *mut ffi::GVariantType {
191 std::mem::ManuallyDrop::new(self).to_glib_none().0
192 }
193}
194
195#[doc(hidden)]
196impl<'a> ToGlibPtr<'a, *const ffi::GVariantType> for VariantType {
197 type Storage = PhantomData<&'a Self>;
198
199 #[inline]
200 fn to_glib_none(&'a self) -> Stash<'a, *const ffi::GVariantType, Self> {
201 Stash(self.ptr.as_ptr(), PhantomData)
202 }
203
204 #[inline]
205 fn to_glib_full(&self) -> *const ffi::GVariantType {
206 unsafe { ffi::g_variant_type_copy(self.ptr.as_ptr()) }
207 }
208}
209
210#[doc(hidden)]
211impl<'a> ToGlibPtr<'a, *mut ffi::GVariantType> for VariantType {
212 type Storage = PhantomData<&'a Self>;
213
214 #[inline]
215 fn to_glib_none(&'a self) -> Stash<'a, *mut ffi::GVariantType, Self> {
216 Stash(self.ptr.as_ptr(), PhantomData)
217 }
218
219 #[inline]
220 fn to_glib_full(&self) -> *mut ffi::GVariantType {
221 unsafe { ffi::g_variant_type_copy(self.ptr.as_ptr()) }
222 }
223}
224
225#[doc(hidden)]
226impl<'a> ToGlibPtrMut<'a, *mut ffi::GVariantType> for VariantType {
227 type Storage = PhantomData<&'a mut Self>;
228
229 #[inline]
230 fn to_glib_none_mut(&'a mut self) -> StashMut<'a, *mut ffi::GVariantType, Self> {
231 StashMut(self.ptr.as_ptr(), PhantomData)
232 }
233}
234
235#[doc(hidden)]
236impl FromGlibPtrNone<*const ffi::GVariantType> for VariantType {
237 #[inline]
238 unsafe fn from_glib_none(ptr: *const ffi::GVariantType) -> VariantType {
239 VariantTy::from_ptr(ptr).to_owned()
240 }
241}
242
243#[doc(hidden)]
244impl FromGlibPtrFull<*const ffi::GVariantType> for VariantType {
245 #[inline]
246 unsafe fn from_glib_full(ptr: *const ffi::GVariantType) -> VariantType {
247 // Don't assume ownership of a const pointer.
248 // A transfer: full annotation on a `const GVariantType*` is likely a bug.
249 VariantTy::from_ptr(ptr).to_owned()
250 }
251}
252
253#[doc(hidden)]
254impl FromGlibPtrFull<*mut ffi::GVariantType> for VariantType {
255 #[inline]
256 unsafe fn from_glib_full(ptr: *mut ffi::GVariantType) -> VariantType {
257 debug_assert!(!ptr.is_null());
258 let len: usize = ffi::g_variant_type_get_string_length(type_:ptr) as _;
259 VariantType {
260 ptr: ptr::NonNull::new_unchecked(ptr),
261 len,
262 }
263 }
264}
265
266// rustdoc-stripper-ignore-next
267/// Describes `Variant` types.
268///
269/// This is a borrowed counterpart of [`VariantType`](struct.VariantType.html).
270/// Essentially it's a `str` statically guaranteed to be a valid type string.
271#[repr(transparent)]
272#[derive(Debug, PartialEq, Eq, Hash)]
273pub struct VariantTy {
274 inner: str,
275}
276
277impl VariantTy {
278 // rustdoc-stripper-ignore-next
279 /// `bool`.
280 #[doc(alias = "G_VARIANT_TYPE_BOOLEAN")]
281 pub const BOOLEAN: &'static VariantTy =
282 unsafe { VariantTy::from_str_unchecked(ffi::G_VARIANT_TYPE_BOOLEAN) };
283
284 // rustdoc-stripper-ignore-next
285 /// `u8`.
286 #[doc(alias = "G_VARIANT_TYPE_BYTE")]
287 pub const BYTE: &'static VariantTy =
288 unsafe { VariantTy::from_str_unchecked(ffi::G_VARIANT_TYPE_BYTE) };
289
290 // rustdoc-stripper-ignore-next
291 /// `i16`.
292 #[doc(alias = "G_VARIANT_TYPE_INT16")]
293 pub const INT16: &'static VariantTy =
294 unsafe { VariantTy::from_str_unchecked(ffi::G_VARIANT_TYPE_INT16) };
295
296 // rustdoc-stripper-ignore-next
297 /// `u16`.
298 #[doc(alias = "G_VARIANT_TYPE_UINT16")]
299 pub const UINT16: &'static VariantTy =
300 unsafe { VariantTy::from_str_unchecked(ffi::G_VARIANT_TYPE_UINT16) };
301
302 // rustdoc-stripper-ignore-next
303 /// `i32`.
304 #[doc(alias = "G_VARIANT_TYPE_INT32")]
305 pub const INT32: &'static VariantTy =
306 unsafe { VariantTy::from_str_unchecked(ffi::G_VARIANT_TYPE_INT32) };
307
308 // rustdoc-stripper-ignore-next
309 /// `u32`.
310 #[doc(alias = "G_VARIANT_TYPE_UINT32")]
311 pub const UINT32: &'static VariantTy =
312 unsafe { VariantTy::from_str_unchecked(ffi::G_VARIANT_TYPE_UINT32) };
313
314 // rustdoc-stripper-ignore-next
315 /// `i64`.
316 #[doc(alias = "G_VARIANT_TYPE_INT64")]
317 pub const INT64: &'static VariantTy =
318 unsafe { VariantTy::from_str_unchecked(ffi::G_VARIANT_TYPE_INT64) };
319
320 // rustdoc-stripper-ignore-next
321 /// `u64`.
322 #[doc(alias = "G_VARIANT_TYPE_UINT64")]
323 pub const UINT64: &'static VariantTy =
324 unsafe { VariantTy::from_str_unchecked(ffi::G_VARIANT_TYPE_UINT64) };
325
326 // rustdoc-stripper-ignore-next
327 /// `f64`.
328 #[doc(alias = "G_VARIANT_TYPE_DOUBLE")]
329 pub const DOUBLE: &'static VariantTy =
330 unsafe { VariantTy::from_str_unchecked(ffi::G_VARIANT_TYPE_DOUBLE) };
331
332 // rustdoc-stripper-ignore-next
333 /// `&str`.
334 #[doc(alias = "G_VARIANT_TYPE_STRING")]
335 pub const STRING: &'static VariantTy =
336 unsafe { VariantTy::from_str_unchecked(ffi::G_VARIANT_TYPE_STRING) };
337
338 // rustdoc-stripper-ignore-next
339 /// DBus object path.
340 #[doc(alias = "G_VARIANT_TYPE_OBJECT_PATH")]
341 pub const OBJECT_PATH: &'static VariantTy =
342 unsafe { VariantTy::from_str_unchecked(ffi::G_VARIANT_TYPE_OBJECT_PATH) };
343
344 // rustdoc-stripper-ignore-next
345 /// Type signature.
346 #[doc(alias = "G_VARIANT_TYPE_SIGNATURE")]
347 pub const SIGNATURE: &'static VariantTy =
348 unsafe { VariantTy::from_str_unchecked(ffi::G_VARIANT_TYPE_SIGNATURE) };
349
350 // rustdoc-stripper-ignore-next
351 /// Variant.
352 #[doc(alias = "G_VARIANT_TYPE_VARIANT")]
353 pub const VARIANT: &'static VariantTy =
354 unsafe { VariantTy::from_str_unchecked(ffi::G_VARIANT_TYPE_VARIANT) };
355
356 // rustdoc-stripper-ignore-next
357 /// Handle.
358 #[doc(alias = "G_VARIANT_TYPE_HANDLE")]
359 pub const HANDLE: &'static VariantTy =
360 unsafe { VariantTy::from_str_unchecked(ffi::G_VARIANT_TYPE_HANDLE) };
361
362 // rustdoc-stripper-ignore-next
363 /// Unit, i.e. `()`.
364 #[doc(alias = "G_VARIANT_TYPE_UNIT")]
365 pub const UNIT: &'static VariantTy =
366 unsafe { VariantTy::from_str_unchecked(ffi::G_VARIANT_TYPE_UNIT) };
367
368 // rustdoc-stripper-ignore-next
369 /// An indefinite type that is a supertype of every type (including itself).
370 #[doc(alias = "G_VARIANT_TYPE_ANY")]
371 pub const ANY: &'static VariantTy =
372 unsafe { VariantTy::from_str_unchecked(ffi::G_VARIANT_TYPE_ANY) };
373
374 // rustdoc-stripper-ignore-next
375 /// Any basic type.
376 #[doc(alias = "G_VARIANT_TYPE_BASIC")]
377 pub const BASIC: &'static VariantTy =
378 unsafe { VariantTy::from_str_unchecked(ffi::G_VARIANT_TYPE_BASIC) };
379
380 // rustdoc-stripper-ignore-next
381 /// Any maybe type, i.e. `Option<T>`.
382 #[doc(alias = "G_VARIANT_TYPE_MAYBE")]
383 pub const MAYBE: &'static VariantTy =
384 unsafe { VariantTy::from_str_unchecked(ffi::G_VARIANT_TYPE_MAYBE) };
385
386 // rustdoc-stripper-ignore-next
387 /// Any array type, i.e. `[T]`.
388 #[doc(alias = "G_VARIANT_TYPE_ARRAY")]
389 pub const ARRAY: &'static VariantTy =
390 unsafe { VariantTy::from_str_unchecked(ffi::G_VARIANT_TYPE_ARRAY) };
391
392 // rustdoc-stripper-ignore-next
393 /// Any tuple type, i.e. `(T)`, `(T, T)`, etc.
394 #[doc(alias = "G_VARIANT_TYPE_TUPLE")]
395 pub const TUPLE: &'static VariantTy =
396 unsafe { VariantTy::from_str_unchecked(ffi::G_VARIANT_TYPE_TUPLE) };
397
398 // rustdoc-stripper-ignore-next
399 /// Any dict entry type, i.e. `DictEntry<K, V>`.
400 #[doc(alias = "G_VARIANT_TYPE_DICT_ENTRY")]
401 pub const DICT_ENTRY: &'static VariantTy =
402 unsafe { VariantTy::from_str_unchecked(ffi::G_VARIANT_TYPE_DICT_ENTRY) };
403
404 // rustdoc-stripper-ignore-next
405 /// Any dictionary type, i.e. `HashMap<K, V>`, `BTreeMap<K, V>`.
406 #[doc(alias = "G_VARIANT_TYPE_DICTIONARY")]
407 pub const DICTIONARY: &'static VariantTy =
408 unsafe { VariantTy::from_str_unchecked(ffi::G_VARIANT_TYPE_DICTIONARY) };
409
410 // rustdoc-stripper-ignore-next
411 /// String array, i.e. `[&str]`.
412 #[doc(alias = "G_VARIANT_TYPE_STRING_ARRAY")]
413 pub const STRING_ARRAY: &'static VariantTy =
414 unsafe { VariantTy::from_str_unchecked(ffi::G_VARIANT_TYPE_STRING_ARRAY) };
415
416 // rustdoc-stripper-ignore-next
417 /// Object path array, i.e. `[&str]`.
418 #[doc(alias = "G_VARIANT_TYPE_OBJECT_PATH_ARRAY")]
419 pub const OBJECT_PATH_ARRAY: &'static VariantTy =
420 unsafe { VariantTy::from_str_unchecked(ffi::G_VARIANT_TYPE_OBJECT_PATH_ARRAY) };
421
422 // rustdoc-stripper-ignore-next
423 /// Byte string, i.e. `[u8]`.
424 #[doc(alias = "G_VARIANT_TYPE_BYTE_STRING")]
425 pub const BYTE_STRING: &'static VariantTy =
426 unsafe { VariantTy::from_str_unchecked(ffi::G_VARIANT_TYPE_BYTE_STRING) };
427
428 // rustdoc-stripper-ignore-next
429 /// Byte string array, i.e. `[[u8]]`.
430 #[doc(alias = "G_VARIANT_TYPE_BYTE_STRING_ARRAY")]
431 pub const BYTE_STRING_ARRAY: &'static VariantTy =
432 unsafe { VariantTy::from_str_unchecked(ffi::G_VARIANT_TYPE_BYTE_STRING_ARRAY) };
433
434 // rustdoc-stripper-ignore-next
435 /// Variant dictionary, i.e. `HashMap<String, Variant>`, `BTreeMap<String, Variant>`, etc.
436 #[doc(alias = "G_VARIANT_TYPE_VARDICT")]
437 pub const VARDICT: &'static VariantTy =
438 unsafe { VariantTy::from_str_unchecked(ffi::G_VARIANT_TYPE_VARDICT) };
439
440 // rustdoc-stripper-ignore-next
441 /// Tries to create a `&VariantTy` from a string slice.
442 ///
443 /// Returns `Ok` if the string is a valid type string, `Err` otherwise.
444 pub fn new(type_string: &str) -> Result<&VariantTy, BoolError> {
445 unsafe {
446 let ptr = type_string.as_ptr();
447 let limit = ptr.add(type_string.len());
448 let mut end = ptr::null();
449
450 let ok = from_glib(ffi::g_variant_type_string_scan(
451 ptr as *const _,
452 limit as *const _,
453 &mut end,
454 ));
455 if ok && end as *const _ == limit {
456 Ok(&*(type_string.as_bytes() as *const [u8] as *const VariantTy))
457 } else {
458 Err(bool_error!("Invalid type string: '{}'", type_string))
459 }
460 }
461 }
462
463 // rustdoc-stripper-ignore-next
464 /// Converts a type string into `&VariantTy` without any checks.
465 ///
466 /// # Safety
467 ///
468 /// The caller is responsible for passing in only a valid variant type string.
469 #[inline]
470 pub const unsafe fn from_str_unchecked(type_string: &str) -> &VariantTy {
471 std::mem::transmute::<&str, &VariantTy>(type_string)
472 }
473
474 // rustdoc-stripper-ignore-next
475 /// Creates `&VariantTy` with a wildcard lifetime from a `GVariantType`
476 /// pointer.
477 #[doc(hidden)]
478 #[allow(clippy::cast_slice_from_raw_parts)]
479 #[inline]
480 pub unsafe fn from_ptr<'a>(ptr: *const ffi::GVariantType) -> &'a VariantTy {
481 debug_assert!(!ptr.is_null());
482 let len: usize = ffi::g_variant_type_get_string_length(ptr) as _;
483 debug_assert!(len > 0);
484 &*(slice::from_raw_parts(ptr as *const u8, len) as *const [u8] as *const VariantTy)
485 }
486
487 // rustdoc-stripper-ignore-next
488 /// Returns a `GVariantType` pointer.
489 #[doc(hidden)]
490 #[inline]
491 pub fn as_ptr(&self) -> *const ffi::GVariantType {
492 self.inner.as_ptr() as *const _
493 }
494
495 // rustdoc-stripper-ignore-next
496 /// Converts to a string slice.
497 #[inline]
498 pub fn as_str(&self) -> &str {
499 &self.inner
500 }
501
502 // rustdoc-stripper-ignore-next
503 /// Check if this variant type is a definite type.
504 #[doc(alias = "g_variant_type_is_definite")]
505 pub fn is_definite(&self) -> bool {
506 unsafe { from_glib(ffi::g_variant_type_is_definite(self.to_glib_none().0)) }
507 }
508
509 // rustdoc-stripper-ignore-next
510 /// Check if this variant type is a container type.
511 #[doc(alias = "g_variant_type_is_container")]
512 pub fn is_container(&self) -> bool {
513 unsafe { from_glib(ffi::g_variant_type_is_container(self.to_glib_none().0)) }
514 }
515
516 // rustdoc-stripper-ignore-next
517 /// Check if this variant type is a basic type.
518 #[doc(alias = "g_variant_type_is_basic")]
519 pub fn is_basic(&self) -> bool {
520 unsafe { from_glib(ffi::g_variant_type_is_basic(self.to_glib_none().0)) }
521 }
522
523 // rustdoc-stripper-ignore-next
524 /// Check if this variant type is a maybe type.
525 #[doc(alias = "g_variant_type_is_maybe")]
526 pub fn is_maybe(&self) -> bool {
527 unsafe { from_glib(ffi::g_variant_type_is_maybe(self.to_glib_none().0)) }
528 }
529
530 // rustdoc-stripper-ignore-next
531 /// Check if this variant type is an array type.
532 #[doc(alias = "g_variant_type_is_array")]
533 pub fn is_array(&self) -> bool {
534 unsafe { from_glib(ffi::g_variant_type_is_array(self.to_glib_none().0)) }
535 }
536
537 // rustdoc-stripper-ignore-next
538 /// Check if this variant type is a tuple type.
539 #[doc(alias = "g_variant_type_is_tuple")]
540 pub fn is_tuple(&self) -> bool {
541 unsafe { from_glib(ffi::g_variant_type_is_tuple(self.to_glib_none().0)) }
542 }
543
544 // rustdoc-stripper-ignore-next
545 /// Check if this variant type is a dict entry type.
546 #[doc(alias = "g_variant_type_is_dict_entry")]
547 pub fn is_dict_entry(&self) -> bool {
548 unsafe { from_glib(ffi::g_variant_type_is_dict_entry(self.to_glib_none().0)) }
549 }
550
551 // rustdoc-stripper-ignore-next
552 /// Check if this variant type is a variant.
553 #[doc(alias = "g_variant_type_is_variant")]
554 pub fn is_variant(&self) -> bool {
555 unsafe { from_glib(ffi::g_variant_type_is_variant(self.to_glib_none().0)) }
556 }
557
558 // rustdoc-stripper-ignore-next
559 /// Check if this variant type is a subtype of another.
560 #[doc(alias = "g_variant_type_is_subtype_of")]
561 pub fn is_subtype_of(&self, supertype: &Self) -> bool {
562 unsafe {
563 from_glib(ffi::g_variant_type_is_subtype_of(
564 self.to_glib_none().0,
565 supertype.to_glib_none().0,
566 ))
567 }
568 }
569
570 // rustdoc-stripper-ignore-next
571 /// Return the element type of this variant type.
572 ///
573 /// # Panics
574 ///
575 /// This function panics if not called with an array or maybe type.
576 #[doc(alias = "g_variant_type_element")]
577 pub fn element(&self) -> &VariantTy {
578 assert!(self.is_array() || self.is_maybe());
579
580 unsafe {
581 let element = ffi::g_variant_type_element(self.to_glib_none().0);
582 Self::from_ptr(element)
583 }
584 }
585
586 // rustdoc-stripper-ignore-next
587 /// Iterate over the types of this variant type.
588 ///
589 /// # Panics
590 ///
591 /// This function panics if not called with a tuple or dictionary entry type.
592 pub fn tuple_types(&self) -> VariantTyIterator {
593 VariantTyIterator::new(self).expect("VariantTy does not represent a tuple")
594 }
595
596 // rustdoc-stripper-ignore-next
597 /// Return the first type of this variant type.
598 ///
599 /// # Panics
600 ///
601 /// This function panics if not called with a tuple or dictionary entry type.
602 #[doc(alias = "g_variant_type_first")]
603 pub fn first(&self) -> Option<&VariantTy> {
604 assert!(self.as_str().starts_with('(') || self.as_str().starts_with('{'));
605
606 unsafe {
607 let first = ffi::g_variant_type_first(self.to_glib_none().0);
608 if first.is_null() {
609 None
610 } else {
611 Some(Self::from_ptr(first))
612 }
613 }
614 }
615
616 // rustdoc-stripper-ignore-next
617 /// Return the next type of this variant type.
618 #[doc(alias = "g_variant_type_next")]
619 pub fn next(&self) -> Option<&VariantTy> {
620 unsafe {
621 let next = ffi::g_variant_type_next(self.to_glib_none().0);
622 if next.is_null() {
623 None
624 } else {
625 Some(Self::from_ptr(next))
626 }
627 }
628 }
629
630 // rustdoc-stripper-ignore-next
631 /// Return the number of items in this variant type.
632 #[doc(alias = "g_variant_type_n_items")]
633 pub fn n_items(&self) -> usize {
634 unsafe { ffi::g_variant_type_n_items(self.to_glib_none().0) }
635 }
636
637 // rustdoc-stripper-ignore-next
638 /// Return the key type of this variant type.
639 ///
640 /// # Panics
641 ///
642 /// This function panics if not called with a dictionary entry type.
643 #[doc(alias = "g_variant_type_key")]
644 pub fn key(&self) -> &VariantTy {
645 assert!(self.as_str().starts_with('{'));
646
647 unsafe {
648 let key = ffi::g_variant_type_key(self.to_glib_none().0);
649 Self::from_ptr(key)
650 }
651 }
652
653 // rustdoc-stripper-ignore-next
654 /// Return the value type of this variant type.
655 ///
656 /// # Panics
657 ///
658 /// This function panics if not called with a dictionary entry type.
659 #[doc(alias = "g_variant_type_value")]
660 pub fn value(&self) -> &VariantTy {
661 assert!(self.as_str().starts_with('{'));
662
663 unsafe {
664 let value = ffi::g_variant_type_value(self.to_glib_none().0);
665 Self::from_ptr(value)
666 }
667 }
668
669 // rustdoc-stripper-ignore-next
670 /// Return this type as an array.
671 pub(crate) fn as_array<'a>(&self) -> Cow<'a, VariantTy> {
672 if self == VariantTy::STRING {
673 Cow::Borrowed(VariantTy::STRING_ARRAY)
674 } else if self == VariantTy::BYTE {
675 Cow::Borrowed(VariantTy::BYTE_STRING)
676 } else if self == VariantTy::BYTE_STRING {
677 Cow::Borrowed(VariantTy::BYTE_STRING_ARRAY)
678 } else if self == VariantTy::OBJECT_PATH {
679 Cow::Borrowed(VariantTy::OBJECT_PATH_ARRAY)
680 } else if self == VariantTy::DICT_ENTRY {
681 Cow::Borrowed(VariantTy::DICTIONARY)
682 } else {
683 Cow::Owned(VariantType::new_array(self))
684 }
685 }
686}
687
688unsafe impl Sync for VariantTy {}
689
690#[doc(hidden)]
691impl<'a> ToGlibPtr<'a, *const ffi::GVariantType> for VariantTy {
692 type Storage = PhantomData<&'a Self>;
693
694 #[inline]
695 fn to_glib_none(&'a self) -> Stash<'a, *const ffi::GVariantType, Self> {
696 Stash(self.as_ptr(), PhantomData)
697 }
698}
699
700impl fmt::Display for VariantTy {
701 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
702 f.write_str(self.as_str())
703 }
704}
705
706impl<'a> From<&'a VariantTy> for Cow<'a, VariantTy> {
707 #[inline]
708 fn from(ty: &'a VariantTy) -> Cow<'a, VariantTy> {
709 Cow::Borrowed(ty)
710 }
711}
712
713impl AsRef<VariantTy> for VariantTy {
714 #[inline]
715 fn as_ref(&self) -> &Self {
716 self
717 }
718}
719
720impl ToOwned for VariantTy {
721 type Owned = VariantType;
722
723 #[inline]
724 fn to_owned(&self) -> VariantType {
725 unsafe {
726 VariantType {
727 ptr: ptr::NonNull::new_unchecked(ptr:ffi::g_variant_type_copy(self.as_ptr())),
728 len: self.inner.len(),
729 }
730 }
731 }
732}
733
734impl StaticType for VariantTy {
735 #[inline]
736 fn static_type() -> Type {
737 unsafe { from_glib(val:ffi::g_variant_type_get_gtype()) }
738 }
739}
740
741#[doc(hidden)]
742unsafe impl<'a> crate::value::FromValue<'a> for &'a VariantTy {
743 type Checker = crate::value::GenericValueTypeOrNoneChecker<Self>;
744
745 unsafe fn from_value(value: &'a crate::Value) -> Self {
746 let ptr: *mut c_void = gobject_ffi::g_value_get_boxed(value.to_glib_none().0);
747 debug_assert!(!ptr.is_null());
748 VariantTy::from_ptr(ptr as *const ffi::GVariantType)
749 }
750}
751
752#[doc(hidden)]
753impl crate::value::ToValue for VariantTy {
754 fn to_value(&self) -> crate::Value {
755 unsafe {
756 let mut value: Value = crate::Value::from_type_unchecked(type_:VariantTy::static_type());
757 gobject_ffi::g_value_set_boxed(
758 value:value.to_glib_none_mut().0,
759 self.to_glib_none().0 as *mut _,
760 );
761 value
762 }
763 }
764
765 fn value_type(&self) -> crate::Type {
766 VariantTy::static_type()
767 }
768}
769
770#[doc(hidden)]
771impl crate::value::ToValue for &VariantTy {
772 fn to_value(&self) -> crate::Value {
773 (*self).to_value()
774 }
775
776 #[inline]
777 fn value_type(&self) -> crate::Type {
778 VariantTy::static_type()
779 }
780}
781
782#[doc(hidden)]
783impl crate::value::ToValueOptional for &VariantTy {
784 fn to_value_optional(s: Option<&Self>) -> crate::Value {
785 let mut value: Value = crate::Value::for_value_type::<VariantType>();
786 unsafe {
787 gobject_ffi::g_value_set_boxed(
788 value:value.to_glib_none_mut().0,
789 v_boxed:s.to_glib_none().0 as *mut _,
790 );
791 }
792
793 value
794 }
795}
796
797impl StaticType for VariantType {
798 #[inline]
799 fn static_type() -> Type {
800 unsafe { from_glib(val:ffi::g_variant_type_get_gtype()) }
801 }
802}
803
804#[doc(hidden)]
805impl crate::value::ValueType for VariantType {
806 type Type = VariantType;
807}
808
809#[doc(hidden)]
810impl crate::value::ValueTypeOptional for VariantType {}
811
812#[doc(hidden)]
813unsafe impl<'a> crate::value::FromValue<'a> for VariantType {
814 type Checker = crate::value::GenericValueTypeOrNoneChecker<Self>;
815
816 unsafe fn from_value(value: &'a crate::Value) -> Self {
817 let ptr: *mut c_void = gobject_ffi::g_value_get_boxed(value.to_glib_none().0);
818 debug_assert!(!ptr.is_null());
819 from_glib_none(ptr as *const ffi::GVariantType)
820 }
821}
822
823#[doc(hidden)]
824impl crate::value::ToValue for VariantType {
825 fn to_value(&self) -> crate::Value {
826 unsafe {
827 let mut value: Value = crate::Value::from_type_unchecked(type_:VariantType::static_type());
828 gobject_ffi::g_value_set_boxed(
829 value:value.to_glib_none_mut().0,
830 v_boxed:ToGlibPtr::<*mut _>::to_glib_none(&self).0 as *mut _,
831 );
832 value
833 }
834 }
835
836 fn value_type(&self) -> crate::Type {
837 VariantType::static_type()
838 }
839}
840
841#[doc(hidden)]
842impl From<VariantType> for crate::Value {
843 fn from(t: VariantType) -> Self {
844 unsafe {
845 let mut value: Value = crate::Value::from_type_unchecked(type_:VariantType::static_type());
846 gobject_ffi::g_value_take_boxed(
847 value:value.to_glib_none_mut().0,
848 v_boxed:IntoGlibPtr::<*mut _>::into_glib_ptr(self:t) as *mut _,
849 );
850 value
851 }
852 }
853}
854
855#[doc(hidden)]
856impl crate::value::ToValueOptional for VariantType {
857 fn to_value_optional(s: Option<&Self>) -> crate::Value {
858 let mut value: Value = crate::Value::for_value_type::<Self>();
859 unsafe {
860 gobject_ffi::g_value_set_boxed(
861 value:value.to_glib_none_mut().0,
862 v_boxed:ToGlibPtr::<*mut _>::to_glib_none(&s).0 as *mut _,
863 );
864 }
865
866 value
867 }
868}
869
870impl PartialEq for VariantType {
871 #[inline]
872 fn eq(&self, other: &Self) -> bool {
873 <VariantTy as PartialEq>::eq(self, other)
874 }
875}
876
877macro_rules! impl_eq {
878 ($lhs:ty, $rhs: ty) => {
879 #[allow(clippy::extra_unused_lifetimes)]
880 impl<'a, 'b> PartialEq<$rhs> for $lhs {
881 #[inline]
882 fn eq(&self, other: &$rhs) -> bool {
883 <VariantTy as PartialEq>::eq(self, other)
884 }
885 }
886
887 #[allow(clippy::extra_unused_lifetimes)]
888 impl<'a, 'b> PartialEq<$lhs> for $rhs {
889 #[inline]
890 fn eq(&self, other: &$lhs) -> bool {
891 <VariantTy as PartialEq>::eq(self, other)
892 }
893 }
894 };
895}
896
897impl_eq!(VariantType, VariantTy);
898impl_eq!(VariantType, &'a VariantTy);
899impl_eq!(VariantType, Cow<'a, VariantTy>);
900impl_eq!(&'a VariantTy, Cow<'b, VariantTy>);
901
902macro_rules! impl_str_eq {
903 ($lhs:ty, $rhs: ty) => {
904 #[allow(clippy::redundant_slicing)]
905 #[allow(clippy::extra_unused_lifetimes)]
906 impl<'a, 'b> PartialEq<$rhs> for $lhs {
907 #[inline]
908 fn eq(&self, other: &$rhs) -> bool {
909 self.as_str().eq(&other[..])
910 }
911 }
912
913 #[allow(clippy::extra_unused_lifetimes)]
914 impl<'a, 'b> PartialEq<$lhs> for $rhs {
915 #[inline]
916 fn eq(&self, other: &$lhs) -> bool {
917 self[..].eq(other.as_str())
918 }
919 }
920 };
921}
922
923impl_str_eq!(VariantTy, str);
924impl_str_eq!(VariantTy, &'a str);
925impl_str_eq!(&'a VariantTy, str);
926impl_str_eq!(VariantTy, String);
927impl_str_eq!(&'a VariantTy, String);
928impl_str_eq!(VariantType, str);
929impl_str_eq!(VariantType, &'a str);
930impl_str_eq!(VariantType, String);
931
932impl Eq for VariantType {}
933
934// rustdoc-stripper-ignore-next
935/// An iterator over the individual components of a tuple [VariantTy].
936///
937/// This can be conveniently constructed using [VariantTy::tuple_types].
938#[derive(Debug, Copy, Clone)]
939pub struct VariantTyIterator<'a> {
940 elem: Option<&'a VariantTy>,
941}
942
943impl<'a> VariantTyIterator<'a> {
944 // rustdoc-stripper-ignore-next
945 /// Creates a new iterator over the types of the specified [VariantTy].
946 ///
947 /// Returns `Ok` if the type is a definite tuple or dictionary entry type,
948 /// `Err` otherwise.
949 pub fn new(ty: &'a VariantTy) -> Result<Self, BoolError> {
950 if (ty.is_tuple() && ty != VariantTy::TUPLE) || ty.is_dict_entry() {
951 Ok(Self { elem: ty.first() })
952 } else {
953 Err(bool_error!(
954 "Expected a definite tuple or dictionary entry type"
955 ))
956 }
957 }
958}
959
960impl<'a> Iterator for VariantTyIterator<'a> {
961 type Item = &'a VariantTy;
962
963 #[doc(alias = "g_variant_type_next")]
964 fn next(&mut self) -> Option<Self::Item> {
965 let elem: &VariantTy = self.elem?;
966 self.elem = elem.next();
967 Some(elem)
968 }
969}
970
971impl<'a> iter::FusedIterator for VariantTyIterator<'a> {}
972
973#[cfg(test)]
974mod tests {
975 use super::*;
976
977 unsafe fn equal<T, U>(ptr1: *const T, ptr2: *const U) -> bool {
978 from_glib(ffi::g_variant_type_equal(
979 ptr1 as *const _,
980 ptr2 as *const _,
981 ))
982 }
983
984 #[test]
985 fn new() {
986 let ty = VariantTy::new("((iii)s)").unwrap();
987 unsafe {
988 assert!(equal(ty.as_ptr(), b"((iii)s)\0" as *const u8));
989 }
990 }
991
992 #[test]
993 fn new_empty() {
994 assert!(VariantTy::new("").is_err());
995 }
996
997 #[test]
998 fn new_with_nul() {
999 assert!(VariantTy::new("((iii\0)s)").is_err());
1000 }
1001
1002 #[test]
1003 fn new_too_short() {
1004 assert!(VariantTy::new("((iii").is_err());
1005 }
1006
1007 #[test]
1008 fn new_too_long() {
1009 assert!(VariantTy::new("(iii)s").is_err());
1010 }
1011
1012 #[test]
1013 fn eq() {
1014 let ty1 = VariantTy::new("((iii)s)").unwrap();
1015 let ty2 = VariantTy::new("((iii)s)").unwrap();
1016 assert_eq!(ty1, ty2);
1017 assert_eq!(ty1, "((iii)s)");
1018 unsafe {
1019 assert!(equal(ty1.as_ptr(), ty2.as_ptr()));
1020 }
1021 }
1022
1023 #[test]
1024 fn ne() {
1025 let ty1 = VariantTy::new("((iii)s)").unwrap();
1026 let ty2 = VariantTy::new("((iii)o)").unwrap();
1027 assert_ne!(ty1, ty2);
1028 assert_ne!(ty1, "((iii)o)");
1029 unsafe {
1030 assert!(!equal(ty1.as_ptr(), ty2.as_ptr()));
1031 }
1032 }
1033
1034 #[test]
1035 fn from_bytes() {
1036 unsafe {
1037 let ty = VariantTy::from_ptr(b"((iii)s)" as *const u8 as *const _);
1038 assert_eq!(ty, "((iii)s)");
1039 assert!(equal(ty.as_ptr(), "((iii)s)".as_ptr()));
1040 }
1041 }
1042
1043 #[test]
1044 fn to_owned() {
1045 let ty1 = VariantTy::new("((iii)s)").unwrap();
1046 let ty2 = ty1.to_owned();
1047 assert_eq!(ty1, ty2);
1048 assert_eq!(ty2, "((iii)s)");
1049 unsafe {
1050 assert!(equal(ty1.as_ptr(), ty2.as_ptr()));
1051 }
1052 }
1053
1054 #[test]
1055 fn value() {
1056 let ty1 = VariantType::new("*").unwrap();
1057 let tyv = ty1.to_value();
1058 let ty2 = tyv.get::<VariantType>().unwrap();
1059 assert_eq!(ty1, ty2);
1060
1061 let ty3 = VariantTy::new("*").unwrap();
1062 let tyv2 = ty3.to_value();
1063 let ty4 = tyv2.get::<VariantType>().unwrap();
1064 assert_eq!(ty3, ty4);
1065
1066 let ty5 = VariantTy::ANY;
1067 let tyv3 = ty5.to_value();
1068 let ty6 = tyv3.get::<VariantType>().unwrap();
1069 assert_eq!(ty5, ty6);
1070 }
1071
1072 #[test]
1073 fn type_() {
1074 assert_eq!(VariantTy::static_type(), VariantType::static_type())
1075 }
1076
1077 #[test]
1078 fn tuple_iter() {
1079 let ty = VariantTy::new("((iii)s)").unwrap();
1080 let types: Vec<_> = ty.tuple_types().map(|t| t.as_str()).collect();
1081 assert_eq!(&types, &["(iii)", "s"]);
1082 }
1083}
1084