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, 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 | |
15 | use 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" )] |
25 | pub 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 | |
34 | impl 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 | |
104 | unsafe impl Send for VariantType {} |
105 | unsafe impl Sync for VariantType {} |
106 | |
107 | impl Drop for VariantType { |
108 | #[inline ] |
109 | fn drop(&mut self) { |
110 | unsafe { ffi::g_variant_type_free(self.ptr.as_ptr()) } |
111 | } |
112 | } |
113 | |
114 | impl AsRef<VariantTy> for VariantType { |
115 | #[inline ] |
116 | fn as_ref(&self) -> &VariantTy { |
117 | self |
118 | } |
119 | } |
120 | |
121 | impl Borrow<VariantTy> for VariantType { |
122 | #[inline ] |
123 | fn borrow(&self) -> &VariantTy { |
124 | self |
125 | } |
126 | } |
127 | |
128 | impl 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 | |
140 | impl 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 | |
153 | impl 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 | |
159 | impl fmt::Display for VariantType { |
160 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { |
161 | f.write_str(self.as_str()) |
162 | } |
163 | } |
164 | |
165 | impl 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 | |
173 | impl Hash for VariantType { |
174 | #[inline ] |
175 | fn hash<H: Hasher>(&self, state: &mut H) { |
176 | <VariantTy as Hash>::hash(self, state) |
177 | } |
178 | } |
179 | |
180 | impl<'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)] |
188 | impl 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)] |
196 | impl<'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)] |
211 | impl<'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)] |
226 | impl<'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)] |
236 | impl 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)] |
244 | impl 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)] |
254 | impl 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)] |
273 | pub struct VariantTy { |
274 | inner: str, |
275 | } |
276 | |
277 | impl 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 | |
688 | unsafe impl Sync for VariantTy {} |
689 | |
690 | #[doc (hidden)] |
691 | impl<'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 | |
700 | impl fmt::Display for VariantTy { |
701 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { |
702 | f.write_str(self.as_str()) |
703 | } |
704 | } |
705 | |
706 | impl<'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 | |
713 | impl AsRef<VariantTy> for VariantTy { |
714 | #[inline ] |
715 | fn as_ref(&self) -> &Self { |
716 | self |
717 | } |
718 | } |
719 | |
720 | impl 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 | |
734 | impl 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)] |
742 | unsafe 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)] |
753 | impl 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)] |
771 | impl 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)] |
783 | impl 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 | |
797 | impl 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)] |
805 | impl crate::value::ValueType for VariantType { |
806 | type Type = VariantType; |
807 | } |
808 | |
809 | #[doc (hidden)] |
810 | impl crate::value::ValueTypeOptional for VariantType {} |
811 | |
812 | #[doc (hidden)] |
813 | unsafe 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)] |
824 | impl 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)] |
842 | impl 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)] |
856 | impl 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 | |
870 | impl PartialEq for VariantType { |
871 | #[inline ] |
872 | fn eq(&self, other: &Self) -> bool { |
873 | <VariantTy as PartialEq>::eq(self, other) |
874 | } |
875 | } |
876 | |
877 | macro_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 | |
897 | impl_eq!(VariantType, VariantTy); |
898 | impl_eq!(VariantType, &'a VariantTy); |
899 | impl_eq!(VariantType, Cow<'a, VariantTy>); |
900 | impl_eq!(&'a VariantTy, Cow<'b, VariantTy>); |
901 | |
902 | macro_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 | |
923 | impl_str_eq!(VariantTy, str); |
924 | impl_str_eq!(VariantTy, &'a str); |
925 | impl_str_eq!(&'a VariantTy, str); |
926 | impl_str_eq!(VariantTy, String); |
927 | impl_str_eq!(&'a VariantTy, String); |
928 | impl_str_eq!(VariantType, str); |
929 | impl_str_eq!(VariantType, &'a str); |
930 | impl_str_eq!(VariantType, String); |
931 | |
932 | impl 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)] |
939 | pub struct VariantTyIterator<'a> { |
940 | elem: Option<&'a VariantTy>, |
941 | } |
942 | |
943 | impl<'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 | |
960 | impl<'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 | |
971 | impl<'a> iter::FusedIterator for VariantTyIterator<'a> {} |
972 | |
973 | #[cfg (test)] |
974 | mod 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 | |