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