1// Take a look at the license at the top of the repository in the LICENSE file.
2
3use std::{cmp, ffi::CStr, fmt, ops::Deref, ptr};
4
5use crate::{
6 ffi, gobject_ffi, prelude::*, translate::*, ParamSpecEnum, ParamSpecFlags, Type, TypeInfo,
7 Value,
8};
9
10#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash)]
11pub enum UserDirectory {
12 #[doc(alias = "G_USER_DIRECTORY_DESKTOP")]
13 Desktop,
14 #[doc(alias = "G_USER_DIRECTORY_DOCUMENTS")]
15 Documents,
16 #[doc(alias = "G_USER_DIRECTORY_DOWNLOAD")]
17 Downloads,
18 #[doc(alias = "G_USER_DIRECTORY_MUSIC")]
19 Music,
20 #[doc(alias = "G_USER_DIRECTORY_PICTURES")]
21 Pictures,
22 #[doc(alias = "G_USER_DIRECTORY_PUBLIC_SHARE")]
23 PublicShare,
24 #[doc(alias = "G_USER_DIRECTORY_TEMPLATES")]
25 Templates,
26 #[doc(alias = "G_USER_DIRECTORY_VIDEOS")]
27 Videos,
28}
29
30#[doc(hidden)]
31impl IntoGlib for UserDirectory {
32 type GlibType = ffi::GUserDirectory;
33
34 #[inline]
35 fn into_glib(self) -> ffi::GUserDirectory {
36 match self {
37 Self::Desktop => ffi::G_USER_DIRECTORY_DESKTOP,
38 Self::Documents => ffi::G_USER_DIRECTORY_DOCUMENTS,
39 Self::Downloads => ffi::G_USER_DIRECTORY_DOWNLOAD,
40 Self::Music => ffi::G_USER_DIRECTORY_MUSIC,
41 Self::Pictures => ffi::G_USER_DIRECTORY_PICTURES,
42 Self::PublicShare => ffi::G_USER_DIRECTORY_PUBLIC_SHARE,
43 Self::Templates => ffi::G_USER_DIRECTORY_TEMPLATES,
44 Self::Videos => ffi::G_USER_DIRECTORY_VIDEOS,
45 }
46 }
47}
48
49// rustdoc-stripper-ignore-next
50/// Representation of an `enum` for dynamically, at runtime, querying the values of the enum and
51/// using them.
52#[doc(alias = "GEnumClass")]
53#[repr(transparent)]
54pub struct EnumClass(ptr::NonNull<gobject_ffi::GEnumClass>);
55
56unsafe impl Send for EnumClass {}
57unsafe impl Sync for EnumClass {}
58
59impl fmt::Debug for EnumClass {
60 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
61 f&mut DebugStruct<'_, '_>.debug_struct("EnumClass")
62 .field("type", &self.type_())
63 .field(name:"values", &self.values())
64 .finish()
65 }
66}
67
68impl EnumClass {
69 // rustdoc-stripper-ignore-next
70 /// Create a new `EnumClass` from a static type `T`.
71 ///
72 /// Panics if `T` is not representing an enum.
73 pub fn new<T: StaticType + HasParamSpec<ParamSpec = ParamSpecEnum>>() -> Self {
74 Self::with_type(T::static_type()).expect("invalid enum class")
75 }
76 // rustdoc-stripper-ignore-next
77 /// Create a new `EnumClass` from a `Type`.
78 ///
79 /// Returns `None` if `type_` is not representing an enum.
80 pub fn with_type(type_: Type) -> Option<Self> {
81 unsafe {
82 let is_enum: bool = from_glib(gobject_ffi::g_type_is_a(
83 type_.into_glib(),
84 gobject_ffi::G_TYPE_ENUM,
85 ));
86 if !is_enum {
87 return None;
88 }
89
90 Some(EnumClass(
91 ptr::NonNull::new(gobject_ffi::g_type_class_ref(type_.into_glib()) as *mut _)
92 .unwrap(),
93 ))
94 }
95 }
96
97 // rustdoc-stripper-ignore-next
98 /// `Type` of the enum.
99 pub fn type_(&self) -> Type {
100 unsafe { from_glib(self.0.as_ref().g_type_class.g_type) }
101 }
102
103 // rustdoc-stripper-ignore-next
104 /// Gets `EnumValue` by integer `value`, if existing.
105 ///
106 /// Returns `None` if the enum does not contain any value
107 /// with `value`.
108 #[doc(alias = "g_enum_get_value")]
109 #[doc(alias = "get_value")]
110 pub fn value(&self, value: i32) -> Option<&EnumValue> {
111 unsafe {
112 let v = gobject_ffi::g_enum_get_value(self.0.as_ptr(), value);
113 if v.is_null() {
114 None
115 } else {
116 Some(&*(v as *const EnumValue))
117 }
118 }
119 }
120
121 // rustdoc-stripper-ignore-next
122 /// Gets `EnumValue` by string name `name`, if existing.
123 ///
124 /// Returns `None` if the enum does not contain any value
125 /// with name `name`.
126 #[doc(alias = "g_enum_get_value_by_name")]
127 #[doc(alias = "get_value_by_name")]
128 pub fn value_by_name(&self, name: &str) -> Option<&EnumValue> {
129 unsafe {
130 let v = gobject_ffi::g_enum_get_value_by_name(self.0.as_ptr(), name.to_glib_none().0);
131 if v.is_null() {
132 None
133 } else {
134 Some(&*(v as *const EnumValue))
135 }
136 }
137 }
138
139 // rustdoc-stripper-ignore-next
140 /// Gets `EnumValue` by string nick `nick`, if existing.
141 ///
142 /// Returns `None` if the enum does not contain any value
143 /// with nick `nick`.
144 #[doc(alias = "g_enum_get_value_by_nick")]
145 #[doc(alias = "get_value_by_nick")]
146 pub fn value_by_nick(&self, nick: &str) -> Option<&EnumValue> {
147 unsafe {
148 let v = gobject_ffi::g_enum_get_value_by_nick(self.0.as_ptr(), nick.to_glib_none().0);
149 if v.is_null() {
150 None
151 } else {
152 Some(&*(v as *const EnumValue))
153 }
154 }
155 }
156
157 // rustdoc-stripper-ignore-next
158 /// Gets all `EnumValue` of this `EnumClass`.
159 #[doc(alias = "get_values")]
160 pub fn values(&self) -> &[EnumValue] {
161 unsafe {
162 if self.0.as_ref().n_values == 0 {
163 return &[];
164 }
165 std::slice::from_raw_parts(
166 self.0.as_ref().values as *const EnumValue,
167 self.0.as_ref().n_values as usize,
168 )
169 }
170 }
171
172 // rustdoc-stripper-ignore-next
173 /// Converts integer `value` to a `Value`, if part of the enum.
174 pub fn to_value(&self, value: i32) -> Option<Value> {
175 self.value(value).map(|v| v.to_value(self))
176 }
177
178 // rustdoc-stripper-ignore-next
179 /// Converts string name `name` to a `Value`, if part of the enum.
180 pub fn to_value_by_name(&self, name: &str) -> Option<Value> {
181 self.value_by_name(name).map(|v| v.to_value(self))
182 }
183
184 // rustdoc-stripper-ignore-next
185 /// Converts string nick `nick` to a `Value`, if part of the enum.
186 pub fn to_value_by_nick(&self, nick: &str) -> Option<Value> {
187 self.value_by_nick(nick).map(|v| v.to_value(self))
188 }
189
190 // rustdoc-stripper-ignore-next
191 /// Complete `TypeInfo` for an enum with values.
192 /// This is an associated function. A method would result in a stack overflow due to a recurvice call:
193 /// callers should first create an `EnumClass` instance by calling `EnumClass::with_type()` which indirectly
194 /// calls `TypePluginRegisterImpl::register_dynamic_enum()` and `TypePluginImpl::complete_type_info()`
195 /// and one of them should call `EnumClass::with_type()` before calling this method.
196 /// `const_static_values` is a reference on a wrapper of a slice of `EnumValue`.
197 /// It must be static to ensure enumeration values are never dropped, and ensures that slice is terminated
198 /// by an `EnumValue` with all members being 0, as expected by GLib.
199 #[doc(alias = "g_enum_complete_type_info")]
200 pub fn complete_type_info(
201 type_: Type,
202 const_static_values: &'static EnumValues,
203 ) -> Option<TypeInfo> {
204 unsafe {
205 let is_enum: bool = from_glib(gobject_ffi::g_type_is_a(
206 type_.into_glib(),
207 gobject_ffi::G_TYPE_ENUM,
208 ));
209 if !is_enum {
210 return None;
211 }
212
213 let info = TypeInfo::default();
214 gobject_ffi::g_enum_complete_type_info(
215 type_.into_glib(),
216 info.as_ptr(),
217 const_static_values.to_glib_none().0,
218 );
219 Some(info)
220 }
221 }
222}
223
224impl Drop for EnumClass {
225 #[inline]
226 fn drop(&mut self) {
227 unsafe {
228 gobject_ffi::g_type_class_unref(self.0.as_ptr() as *mut _);
229 }
230 }
231}
232
233impl Clone for EnumClass {
234 #[inline]
235 fn clone(&self) -> Self {
236 unsafe {
237 Self(ptr::NonNull::new(ptr:gobject_ffi::g_type_class_ref(self.type_().into_glib()) as *mut _).unwrap())
238 }
239 }
240}
241
242// rustdoc-stripper-ignore-next
243/// Representation of a single enum value of an `EnumClass`.
244#[doc(alias = "GEnumValue")]
245#[derive(Copy, Clone)]
246#[repr(transparent)]
247pub struct EnumValue(gobject_ffi::GEnumValue);
248
249unsafe impl Send for EnumValue {}
250unsafe impl Sync for EnumValue {}
251
252impl fmt::Debug for EnumValue {
253 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
254 f&mut DebugStruct<'_, '_>.debug_struct("EnumValue")
255 .field("value", &self.value())
256 .field("name", &self.name())
257 .field(name:"nick", &self.nick())
258 .finish()
259 }
260}
261
262impl EnumValue {
263 // rustdoc-stripper-ignore-next
264 /// # Safety
265 ///
266 /// It is the responsibility of the caller to ensure `GEnumValue` is
267 /// valid.
268 pub const unsafe fn unsafe_from(g_value: gobject_ffi::GEnumValue) -> Self {
269 Self(g_value)
270 }
271
272 // rustdoc-stripper-ignore-next
273 /// Get integer value corresponding to the value.
274 #[doc(alias = "get_value")]
275 pub fn value(&self) -> i32 {
276 self.0.value
277 }
278
279 // rustdoc-stripper-ignore-next
280 /// Get name corresponding to the value.
281 #[doc(alias = "get_name")]
282 pub fn name(&self) -> &str {
283 unsafe { CStr::from_ptr(self.0.value_name).to_str().unwrap() }
284 }
285
286 // rustdoc-stripper-ignore-next
287 /// Get nick corresponding to the value.
288 #[doc(alias = "get_nick")]
289 pub fn nick(&self) -> &str {
290 unsafe { CStr::from_ptr(self.0.value_nick).to_str().unwrap() }
291 }
292
293 // rustdoc-stripper-ignore-next
294 /// Convert enum value to a `Value`.
295 pub fn to_value(&self, enum_: &EnumClass) -> Value {
296 unsafe {
297 let mut v = Value::from_type_unchecked(enum_.type_());
298 gobject_ffi::g_value_set_enum(v.to_glib_none_mut().0, self.0.value);
299 v
300 }
301 }
302
303 // rustdoc-stripper-ignore-next
304 /// Convert enum value from a `Value`.
305 pub fn from_value(value: &Value) -> Option<(EnumClass, &EnumValue)> {
306 unsafe {
307 let enum_class = EnumClass::with_type(value.type_())?;
308 let v = enum_class.value(gobject_ffi::g_value_get_enum(value.to_glib_none().0))?;
309 let v = &*(v as *const EnumValue);
310 Some((enum_class, v))
311 }
312 }
313}
314
315impl PartialEq for EnumValue {
316 fn eq(&self, other: &Self) -> bool {
317 self.value().eq(&other.value())
318 }
319}
320
321impl Eq for EnumValue {}
322
323impl PartialOrd for EnumValue {
324 fn partial_cmp(&self, other: &Self) -> Option<cmp::Ordering> {
325 Some(self.cmp(other))
326 }
327}
328
329impl Ord for EnumValue {
330 fn cmp(&self, other: &Self) -> cmp::Ordering {
331 self.value().cmp(&other.value())
332 }
333}
334
335impl UnsafeFrom<gobject_ffi::GEnumValue> for EnumValue {
336 unsafe fn unsafe_from(g_value: gobject_ffi::GEnumValue) -> Self {
337 Self::unsafe_from(g_value)
338 }
339}
340
341unsafe impl<'a> crate::value::FromValue<'a> for &EnumValue {
342 type Checker = EnumTypeChecker;
343
344 unsafe fn from_value(value: &'a Value) -> Self {
345 let (_, v: &EnumValue) = EnumValue::from_value(value).unwrap();
346 // SAFETY: The enum class and its values live forever
347 std::mem::transmute(src:v)
348 }
349}
350
351// rustdoc-stripper-ignore-next
352/// Define the zero value and the associated GLib type.
353impl EnumerationValue<EnumValue> for EnumValue {
354 type GlibType = gobject_ffi::GEnumValue;
355 const ZERO: EnumValue = unsafe {
356 EnumValue::unsafe_from(g_value:gobject_ffi::GEnumValue {
357 value: 0,
358 value_name: ptr::null(),
359 value_nick: ptr::null(),
360 })
361 };
362}
363
364// rustdoc-stripper-ignore-next
365/// Storage of enum values.
366pub type EnumValuesStorage<const N: usize> = EnumerationValuesStorage<EnumValue, N>;
367
368// rustdoc-stripper-ignore-next
369/// Representation of enum values wrapped by `EnumValuesStorage`
370pub type EnumValues = EnumerationValues<EnumValue>;
371
372pub struct EnumTypeChecker();
373unsafe impl crate::value::ValueTypeChecker for EnumTypeChecker {
374 type Error = InvalidEnumError;
375
376 fn check(value: &Value) -> Result<(), Self::Error> {
377 let t: Type = value.type_();
378 if t.is_a(Type::ENUM) {
379 Ok(())
380 } else {
381 Err(InvalidEnumError)
382 }
383 }
384}
385
386// rustdoc-stripper-ignore-next
387/// An error returned from the [`get`](struct.Value.html#method.get) function
388/// on a [`Value`](struct.Value.html) for enum types.
389#[derive(Clone, PartialEq, Eq, Debug)]
390pub struct InvalidEnumError;
391
392impl fmt::Display for InvalidEnumError {
393 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
394 write!(f, "Value is not an enum")
395 }
396}
397
398impl std::error::Error for InvalidEnumError {}
399
400// rustdoc-stripper-ignore-next
401/// Representation of a `flags` for dynamically, at runtime, querying the values of the enum and
402/// using them
403#[doc(alias = "GFlagsClass")]
404#[repr(transparent)]
405pub struct FlagsClass(ptr::NonNull<gobject_ffi::GFlagsClass>);
406
407unsafe impl Send for FlagsClass {}
408unsafe impl Sync for FlagsClass {}
409
410impl fmt::Debug for FlagsClass {
411 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
412 f&mut DebugStruct<'_, '_>.debug_struct("FlagsClass")
413 .field("type", &self.type_())
414 .field(name:"values", &self.values())
415 .finish()
416 }
417}
418
419impl FlagsClass {
420 // rustdoc-stripper-ignore-next
421 /// Create a new `FlagsClass` from a static type `T`.
422 ///
423 /// Panics if `T` is not representing an flags type.
424 pub fn new<T: StaticType + HasParamSpec<ParamSpec = ParamSpecFlags>>() -> Self {
425 Self::with_type(T::static_type()).expect("invalid flags class")
426 }
427 // rustdoc-stripper-ignore-next
428 /// Create a new `FlagsClass` from a `Type`
429 ///
430 /// Returns `None` if `type_` is not representing a flags type.
431 pub fn with_type(type_: Type) -> Option<Self> {
432 unsafe {
433 let is_flags: bool = from_glib(gobject_ffi::g_type_is_a(
434 type_.into_glib(),
435 gobject_ffi::G_TYPE_FLAGS,
436 ));
437 if !is_flags {
438 return None;
439 }
440
441 Some(FlagsClass(
442 ptr::NonNull::new(gobject_ffi::g_type_class_ref(type_.into_glib()) as *mut _)
443 .unwrap(),
444 ))
445 }
446 }
447
448 // rustdoc-stripper-ignore-next
449 /// `Type` of the flags.
450 pub fn type_(&self) -> Type {
451 unsafe { from_glib(self.0.as_ref().g_type_class.g_type) }
452 }
453
454 // rustdoc-stripper-ignore-next
455 /// Gets `FlagsValue` by integer `value`, if existing.
456 ///
457 /// Returns `None` if the flags do not contain any value
458 /// with `value`.
459 #[doc(alias = "g_flags_get_first_value")]
460 #[doc(alias = "get_value")]
461 pub fn value(&self, value: u32) -> Option<&FlagsValue> {
462 unsafe {
463 let v = gobject_ffi::g_flags_get_first_value(self.0.as_ptr(), value);
464 if v.is_null() {
465 None
466 } else {
467 Some(&*(v as *const FlagsValue))
468 }
469 }
470 }
471
472 // rustdoc-stripper-ignore-next
473 /// Gets `FlagsValue` by string name `name`, if existing.
474 ///
475 /// Returns `None` if the flags do not contain any value
476 /// with name `name`.
477 #[doc(alias = "g_flags_get_value_by_name")]
478 #[doc(alias = "get_value_by_name")]
479 pub fn value_by_name(&self, name: &str) -> Option<&FlagsValue> {
480 unsafe {
481 let v = gobject_ffi::g_flags_get_value_by_name(self.0.as_ptr(), name.to_glib_none().0);
482 if v.is_null() {
483 None
484 } else {
485 Some(&*(v as *const FlagsValue))
486 }
487 }
488 }
489
490 // rustdoc-stripper-ignore-next
491 /// Gets `FlagsValue` by string nick `nick`, if existing.
492 ///
493 /// Returns `None` if the flags do not contain any value
494 /// with nick `nick`.
495 #[doc(alias = "g_flags_get_value_by_nick")]
496 #[doc(alias = "get_value_by_nick")]
497 pub fn value_by_nick(&self, nick: &str) -> Option<&FlagsValue> {
498 unsafe {
499 let v = gobject_ffi::g_flags_get_value_by_nick(self.0.as_ptr(), nick.to_glib_none().0);
500 if v.is_null() {
501 None
502 } else {
503 Some(&*(v as *const FlagsValue))
504 }
505 }
506 }
507
508 // rustdoc-stripper-ignore-next
509 /// Gets all `FlagsValue` of this `FlagsClass`.
510 #[doc(alias = "get_values")]
511 pub fn values(&self) -> &[FlagsValue] {
512 unsafe {
513 if self.0.as_ref().n_values == 0 {
514 return &[];
515 }
516 std::slice::from_raw_parts(
517 self.0.as_ref().values as *const FlagsValue,
518 self.0.as_ref().n_values as usize,
519 )
520 }
521 }
522
523 // rustdoc-stripper-ignore-next
524 /// Converts integer `value` to a `Value`, if part of the flags.
525 pub fn to_value(&self, value: u32) -> Option<Value> {
526 self.value(value).map(|v| v.to_value(self))
527 }
528
529 // rustdoc-stripper-ignore-next
530 /// Converts string name `name` to a `Value`, if part of the flags.
531 pub fn to_value_by_name(&self, name: &str) -> Option<Value> {
532 self.value_by_name(name).map(|v| v.to_value(self))
533 }
534
535 // rustdoc-stripper-ignore-next
536 /// Converts string nick `nick` to a `Value`, if part of the flags.
537 pub fn to_value_by_nick(&self, nick: &str) -> Option<Value> {
538 self.value_by_nick(nick).map(|v| v.to_value(self))
539 }
540
541 // rustdoc-stripper-ignore-next
542 /// Checks if the flags corresponding to integer `f` is set in `value`.
543 pub fn is_set(&self, value: &Value, f: u32) -> bool {
544 unsafe {
545 if self.type_() != value.type_() {
546 return false;
547 }
548
549 let flags = gobject_ffi::g_value_get_flags(value.to_glib_none().0);
550 flags & f != 0
551 }
552 }
553
554 // rustdoc-stripper-ignore-next
555 /// Checks if the flags corresponding to string name `name` is set in `value`.
556 pub fn is_set_by_name(&self, value: &Value, name: &str) -> bool {
557 unsafe {
558 if self.type_() != value.type_() {
559 return false;
560 }
561
562 if let Some(f) = self.value_by_name(name) {
563 let flags = gobject_ffi::g_value_get_flags(value.to_glib_none().0);
564 flags & f.value() != 0
565 } else {
566 false
567 }
568 }
569 }
570
571 // rustdoc-stripper-ignore-next
572 /// Checks if the flags corresponding to string nick `nick` is set in `value`.
573 pub fn is_set_by_nick(&self, value: &Value, nick: &str) -> bool {
574 unsafe {
575 if self.type_() != value.type_() {
576 return false;
577 }
578
579 if let Some(f) = self.value_by_nick(nick) {
580 let flags = gobject_ffi::g_value_get_flags(value.to_glib_none().0);
581 flags & f.value() != 0
582 } else {
583 false
584 }
585 }
586 }
587
588 // rustdoc-stripper-ignore-next
589 /// Set flags value corresponding to integer `f` in `value`, if part of that flags. If the
590 /// flag is already set, it will succeed without doing any changes.
591 ///
592 /// Returns `Ok(value)` with the flag set if successful, or `Err(value)` with the original
593 /// value otherwise.
594 #[doc(alias = "g_value_set_flags")]
595 pub fn set(&self, mut value: Value, f: u32) -> Result<Value, Value> {
596 unsafe {
597 if self.type_() != value.type_() {
598 return Err(value);
599 }
600
601 if let Some(f) = self.value(f) {
602 let flags = gobject_ffi::g_value_get_flags(value.to_glib_none().0);
603 gobject_ffi::g_value_set_flags(value.to_glib_none_mut().0, flags | f.value());
604 Ok(value)
605 } else {
606 Err(value)
607 }
608 }
609 }
610
611 // rustdoc-stripper-ignore-next
612 /// Set flags value corresponding to string name `name` in `value`, if part of that flags.
613 /// If the flag is already set, it will succeed without doing any changes.
614 ///
615 /// Returns `Ok(value)` with the flag set if successful, or `Err(value)` with the original
616 /// value otherwise.
617 pub fn set_by_name(&self, mut value: Value, name: &str) -> Result<Value, Value> {
618 unsafe {
619 if self.type_() != value.type_() {
620 return Err(value);
621 }
622
623 if let Some(f) = self.value_by_name(name) {
624 let flags = gobject_ffi::g_value_get_flags(value.to_glib_none().0);
625 gobject_ffi::g_value_set_flags(value.to_glib_none_mut().0, flags | f.value());
626 Ok(value)
627 } else {
628 Err(value)
629 }
630 }
631 }
632
633 // rustdoc-stripper-ignore-next
634 /// Set flags value corresponding to string nick `nick` in `value`, if part of that flags.
635 /// If the flag is already set, it will succeed without doing any changes.
636 ///
637 /// Returns `Ok(value)` with the flag set if successful, or `Err(value)` with the original
638 /// value otherwise.
639 pub fn set_by_nick(&self, mut value: Value, nick: &str) -> Result<Value, Value> {
640 unsafe {
641 if self.type_() != value.type_() {
642 return Err(value);
643 }
644
645 if let Some(f) = self.value_by_nick(nick) {
646 let flags = gobject_ffi::g_value_get_flags(value.to_glib_none().0);
647 gobject_ffi::g_value_set_flags(value.to_glib_none_mut().0, flags | f.value());
648 Ok(value)
649 } else {
650 Err(value)
651 }
652 }
653 }
654
655 // rustdoc-stripper-ignore-next
656 /// Unset flags value corresponding to integer `f` in `value`, if part of that flags.
657 /// If the flag is already unset, it will succeed without doing any changes.
658 ///
659 /// Returns `Ok(value)` with the flag unset if successful, or `Err(value)` with the original
660 /// value otherwise.
661 pub fn unset(&self, mut value: Value, f: u32) -> Result<Value, Value> {
662 unsafe {
663 if self.type_() != value.type_() {
664 return Err(value);
665 }
666
667 if let Some(f) = self.value(f) {
668 let flags = gobject_ffi::g_value_get_flags(value.to_glib_none().0);
669 gobject_ffi::g_value_set_flags(value.to_glib_none_mut().0, flags & !f.value());
670 Ok(value)
671 } else {
672 Err(value)
673 }
674 }
675 }
676
677 // rustdoc-stripper-ignore-next
678 /// Unset flags value corresponding to string name `name` in `value`, if part of that flags.
679 /// If the flag is already unset, it will succeed without doing any changes.
680 ///
681 /// Returns `Ok(value)` with the flag unset if successful, or `Err(value)` with the original
682 /// value otherwise.
683 pub fn unset_by_name(&self, mut value: Value, name: &str) -> Result<Value, Value> {
684 unsafe {
685 if self.type_() != value.type_() {
686 return Err(value);
687 }
688
689 if let Some(f) = self.value_by_name(name) {
690 let flags = gobject_ffi::g_value_get_flags(value.to_glib_none().0);
691 gobject_ffi::g_value_set_flags(value.to_glib_none_mut().0, flags & !f.value());
692 Ok(value)
693 } else {
694 Err(value)
695 }
696 }
697 }
698
699 // rustdoc-stripper-ignore-next
700 /// Unset flags value corresponding to string nick `nick` in `value`, if part of that flags.
701 /// If the flag is already unset, it will succeed without doing any changes.
702 ///
703 /// Returns `Ok(value)` with the flag unset if successful, or `Err(value)` with the original
704 /// value otherwise.
705 pub fn unset_by_nick(&self, mut value: Value, nick: &str) -> Result<Value, Value> {
706 unsafe {
707 if self.type_() != value.type_() {
708 return Err(value);
709 }
710
711 if let Some(f) = self.value_by_nick(nick) {
712 let flags = gobject_ffi::g_value_get_flags(value.to_glib_none().0);
713 gobject_ffi::g_value_set_flags(value.to_glib_none_mut().0, flags & !f.value());
714 Ok(value)
715 } else {
716 Err(value)
717 }
718 }
719 }
720
721 // rustdoc-stripper-ignore-next
722 /// Converts an integer `value` to a string of nicks separated by `|`.
723 pub fn to_nick_string(&self, mut value: u32) -> String {
724 let mut s = String::new();
725 for val in self.values() {
726 let v = val.value();
727 if v != 0 && (value & v) == v {
728 value &= !v;
729 if !s.is_empty() {
730 s.push('|');
731 }
732 s.push_str(val.nick());
733 }
734 }
735 s
736 }
737
738 // rustdoc-stripper-ignore-next
739 /// Converts a string of nicks `s` separated by `|` to an integer value.
740 pub fn from_nick_string(&self, s: &str) -> Result<u32, ParseFlagsError> {
741 s.split('|').try_fold(0u32, |acc, flag| {
742 self.value_by_nick(flag.trim())
743 .map(|v| acc + v.value())
744 .ok_or_else(|| ParseFlagsError(flag.to_owned()))
745 })
746 }
747
748 // rustdoc-stripper-ignore-next
749 /// Returns a new `FlagsBuilder` for conveniently setting/unsetting flags
750 /// and building a `Value`.
751 pub fn builder(&self) -> FlagsBuilder {
752 FlagsBuilder::new(self)
753 }
754
755 // rustdoc-stripper-ignore-next
756 /// Returns a new `FlagsBuilder` for conveniently setting/unsetting flags
757 /// and building a `Value`. The `Value` is initialized with `value`.
758 pub fn builder_with_value(&self, value: Value) -> Option<FlagsBuilder> {
759 if self.type_() != value.type_() {
760 return None;
761 }
762
763 Some(FlagsBuilder::with_value(self, value))
764 }
765
766 // rustdoc-stripper-ignore-next
767 /// Complete `TypeInfo` for the flags with values.
768 /// This is an associated function. A method would result in a stack overflow due to a recurvice call:
769 /// callers should first create an `FlagsClass` instance by calling `FlagsClass::with_type()` which indirectly
770 /// calls `TypePluginRegisterImpl::register_dynamic_flags()` and `TypePluginImpl::complete_type_info()`
771 /// and one of them should call `FlagsClass::with_type()` before calling this method.
772 /// `const_static_values` is a reference on a wrapper of a slice of `FlagsValue`.
773 /// It must be static to ensure flags values are never dropped, and ensures that slice is terminated
774 /// by an `FlagsValue` with all members being 0, as expected by GLib.
775 #[doc(alias = "g_flags_complete_type_info")]
776 pub fn complete_type_info(
777 type_: Type,
778 const_static_values: &'static FlagsValues,
779 ) -> Option<TypeInfo> {
780 unsafe {
781 let is_flags: bool = from_glib(gobject_ffi::g_type_is_a(
782 type_.into_glib(),
783 gobject_ffi::G_TYPE_FLAGS,
784 ));
785 if !is_flags {
786 return None;
787 }
788
789 let info = TypeInfo::default();
790 gobject_ffi::g_flags_complete_type_info(
791 type_.into_glib(),
792 info.as_ptr(),
793 const_static_values.to_glib_none().0,
794 );
795 Some(info)
796 }
797 }
798}
799
800impl Drop for FlagsClass {
801 #[inline]
802 fn drop(&mut self) {
803 unsafe {
804 gobject_ffi::g_type_class_unref(self.0.as_ptr() as *mut _);
805 }
806 }
807}
808
809impl Clone for FlagsClass {
810 #[inline]
811 fn clone(&self) -> Self {
812 unsafe {
813 Self(ptr::NonNull::new(ptr:gobject_ffi::g_type_class_ref(self.type_().into_glib()) as *mut _).unwrap())
814 }
815 }
816}
817
818#[derive(Debug)]
819pub struct ParseFlagsError(String);
820
821impl std::error::Error for ParseFlagsError {}
822
823impl fmt::Display for ParseFlagsError {
824 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
825 write!(f, "Unknown flag: '{}'", self.0)
826 }
827}
828
829impl ParseFlagsError {
830 pub fn flag(&self) -> &str {
831 &self.0
832 }
833}
834
835// rustdoc-stripper-ignore-next
836/// Representation of a single flags value of a `FlagsClass`.
837#[doc(alias = "GFlagsValue")]
838#[derive(Copy, Clone)]
839#[repr(transparent)]
840pub struct FlagsValue(gobject_ffi::GFlagsValue);
841
842unsafe impl Send for FlagsValue {}
843unsafe impl Sync for FlagsValue {}
844
845impl fmt::Debug for FlagsValue {
846 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
847 f&mut DebugStruct<'_, '_>.debug_struct("FlagsValue")
848 .field("value", &self.value())
849 .field("name", &self.name())
850 .field(name:"nick", &self.nick())
851 .finish()
852 }
853}
854
855impl FlagsValue {
856 // rustdoc-stripper-ignore-next
857 /// # Safety
858 ///
859 /// It is the responsibility of the caller to ensure `GFlagsValue` is
860 /// valid.
861 pub const unsafe fn unsafe_from(g_value: gobject_ffi::GFlagsValue) -> Self {
862 Self(g_value)
863 }
864
865 // rustdoc-stripper-ignore-next
866 /// Get integer value corresponding to the value.
867 #[doc(alias = "get_value")]
868 pub fn value(&self) -> u32 {
869 self.0.value
870 }
871
872 // rustdoc-stripper-ignore-next
873 /// Get name corresponding to the value.
874 #[doc(alias = "get_name")]
875 pub fn name(&self) -> &str {
876 unsafe { CStr::from_ptr(self.0.value_name).to_str().unwrap() }
877 }
878
879 // rustdoc-stripper-ignore-next
880 /// Get nick corresponding to the value.
881 #[doc(alias = "get_nick")]
882 pub fn nick(&self) -> &str {
883 unsafe { CStr::from_ptr(self.0.value_nick).to_str().unwrap() }
884 }
885
886 // rustdoc-stripper-ignore-next
887 /// Convert flags value to a `Value`.
888 pub fn to_value(&self, flags: &FlagsClass) -> Value {
889 unsafe {
890 let mut v = Value::from_type_unchecked(flags.type_());
891 gobject_ffi::g_value_set_flags(v.to_glib_none_mut().0, self.0.value);
892 v
893 }
894 }
895
896 // rustdoc-stripper-ignore-next
897 /// Convert flags values from a `Value`. This returns all flags that are set.
898 pub fn from_value(value: &Value) -> Option<(FlagsClass, Vec<&FlagsValue>)> {
899 unsafe {
900 let flags_class = FlagsClass::with_type(value.type_())?;
901 let mut res = Vec::new();
902 let f = gobject_ffi::g_value_get_flags(value.to_glib_none().0);
903 for v in flags_class.values() {
904 if v.value() & f != 0 {
905 res.push(&*(v as *const FlagsValue));
906 }
907 }
908 Some((flags_class, res))
909 }
910 }
911}
912
913impl PartialEq for FlagsValue {
914 fn eq(&self, other: &Self) -> bool {
915 self.value().eq(&other.value())
916 }
917}
918
919impl Eq for FlagsValue {}
920
921impl UnsafeFrom<gobject_ffi::GFlagsValue> for FlagsValue {
922 unsafe fn unsafe_from(g_value: gobject_ffi::GFlagsValue) -> Self {
923 Self::unsafe_from(g_value)
924 }
925}
926
927// rustdoc-stripper-ignore-next
928/// Define the zero value and the associated GLib type.
929impl EnumerationValue<FlagsValue> for FlagsValue {
930 type GlibType = gobject_ffi::GFlagsValue;
931 const ZERO: FlagsValue = unsafe {
932 FlagsValue::unsafe_from(g_value:gobject_ffi::GFlagsValue {
933 value: 0,
934 value_name: ptr::null(),
935 value_nick: ptr::null(),
936 })
937 };
938}
939
940// rustdoc-stripper-ignore-next
941/// Storage of flags values.
942pub type FlagsValuesStorage<const N: usize> = EnumerationValuesStorage<FlagsValue, N>;
943
944// rustdoc-stripper-ignore-next
945/// Representation of flags values wrapped by `FlagsValuesStorage`
946pub type FlagsValues = EnumerationValues<FlagsValue>;
947
948// rustdoc-stripper-ignore-next
949/// Builder for conveniently setting/unsetting flags and returning a `Value`.
950///
951/// Example for getting a flags property, unsetting some flags and setting the updated flags on the
952/// object again:
953///
954/// ```ignore
955/// let flags = obj.property("flags").unwrap();
956/// let flags_class = FlagsClass::new(flags.type_()).unwrap();
957/// let flags = flags_class.builder_with_value(flags).unwrap()
958/// .unset_by_nick("some-flag")
959/// .unset_by_nick("some-other-flag")
960/// .build()
961/// .unwrap();
962/// obj.set_property("flags", &flags).unwrap();
963/// ```
964///
965/// If setting/unsetting any value fails, `build()` returns `None`.
966#[must_use = "The builder must be built to be used"]
967pub struct FlagsBuilder<'a>(&'a FlagsClass, Option<Value>);
968impl FlagsBuilder<'_> {
969 fn new(flags_class: &FlagsClass) -> FlagsBuilder {
970 let value = unsafe { Value::from_type_unchecked(flags_class.type_()) };
971 FlagsBuilder(flags_class, Some(value))
972 }
973
974 fn with_value(flags_class: &FlagsClass, value: Value) -> FlagsBuilder {
975 FlagsBuilder(flags_class, Some(value))
976 }
977
978 // rustdoc-stripper-ignore-next
979 /// Set flags corresponding to integer value `f`.
980 pub fn set(mut self, f: u32) -> Self {
981 if let Some(value) = self.1.take() {
982 self.1 = self.0.set(value, f).ok();
983 }
984
985 self
986 }
987
988 // rustdoc-stripper-ignore-next
989 /// Set flags corresponding to string name `name`.
990 pub fn set_by_name(mut self, name: &str) -> Self {
991 if let Some(value) = self.1.take() {
992 self.1 = self.0.set_by_name(value, name).ok();
993 }
994
995 self
996 }
997
998 // rustdoc-stripper-ignore-next
999 /// Set flags corresponding to string nick `nick`.
1000 pub fn set_by_nick(mut self, nick: &str) -> Self {
1001 if let Some(value) = self.1.take() {
1002 self.1 = self.0.set_by_nick(value, nick).ok();
1003 }
1004
1005 self
1006 }
1007
1008 // rustdoc-stripper-ignore-next
1009 /// Unsets flags corresponding to integer value `f`.
1010 pub fn unset(mut self, f: u32) -> Self {
1011 if let Some(value) = self.1.take() {
1012 self.1 = self.0.unset(value, f).ok();
1013 }
1014
1015 self
1016 }
1017
1018 // rustdoc-stripper-ignore-next
1019 /// Unset flags corresponding to string name `name`.
1020 pub fn unset_by_name(mut self, name: &str) -> Self {
1021 if let Some(value) = self.1.take() {
1022 self.1 = self.0.unset_by_name(value, name).ok();
1023 }
1024
1025 self
1026 }
1027
1028 // rustdoc-stripper-ignore-next
1029 /// Unset flags corresponding to string nick `nick`.
1030 pub fn unset_by_nick(mut self, nick: &str) -> Self {
1031 if let Some(value) = self.1.take() {
1032 self.1 = self.0.unset_by_nick(value, nick).ok();
1033 }
1034
1035 self
1036 }
1037
1038 // rustdoc-stripper-ignore-next
1039 /// Converts to the final `Value`, unless any previous setting/unsetting of flags failed.
1040 #[must_use = "Value returned from the builder should probably be used"]
1041 pub fn build(self) -> Option<Value> {
1042 self.1
1043 }
1044}
1045
1046unsafe impl<'a> crate::value::FromValue<'a> for Vec<&FlagsValue> {
1047 type Checker = FlagsTypeChecker;
1048
1049 unsafe fn from_value(value: &'a Value) -> Self {
1050 let (_, v: Vec<&FlagsValue>) = FlagsValue::from_value(value).unwrap();
1051 // SAFETY: The enum class and its values live forever
1052 std::mem::transmute(src:v)
1053 }
1054}
1055
1056pub struct FlagsTypeChecker();
1057unsafe impl crate::value::ValueTypeChecker for FlagsTypeChecker {
1058 type Error = InvalidFlagsError;
1059
1060 fn check(value: &Value) -> Result<(), Self::Error> {
1061 let t: Type = value.type_();
1062 if t.is_a(Type::FLAGS) {
1063 Ok(())
1064 } else {
1065 Err(InvalidFlagsError)
1066 }
1067 }
1068}
1069
1070// rustdoc-stripper-ignore-next
1071/// An error returned from the [`get`](struct.Value.html#method.get) function
1072/// on a [`Value`](struct.Value.html) for flags types.
1073#[derive(Clone, PartialEq, Eq, Debug)]
1074pub struct InvalidFlagsError;
1075
1076impl fmt::Display for InvalidFlagsError {
1077 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1078 write!(f, "Value is not a flags")
1079 }
1080}
1081
1082impl std::error::Error for InvalidFlagsError {}
1083
1084// rustdoc-stripper-ignore-next
1085/// helper trait to define the zero value and the associated GLib type.
1086pub trait EnumerationValue<E>: Copy {
1087 type GlibType;
1088 const ZERO: E;
1089}
1090
1091// rustdoc-stripper-ignore-next
1092/// Storage of enumeration values terminated by a zero value. Should be used
1093/// only as a storage location for `EnumValue` or `FlagsValue` when registering
1094/// an enum or flags as a dynamic type.
1095/// see `TypePluginRegisterImpl::register_dynamic_enum()`, `TypePluginRegisterImpl::register_dynamic_flags()`
1096/// and `TypePluginImpl::complete_type_info()`.
1097/// Inner is intentionally private to ensure other modules will not access the
1098/// enum (or flags) values by this way.
1099/// Use `EnumClass::values()` or `EnumClass::value()` to get the enum values.
1100/// Use `FlagsClass::values()` or `FlagsClass::value()` to get the flags values.
1101#[repr(C)]
1102pub struct EnumerationValuesStorage<E: EnumerationValue<E>, const S: usize>([E; S]);
1103
1104impl<E: EnumerationValue<E>, const S: usize> EnumerationValuesStorage<E, S> {
1105 // rustdoc-stripper-ignore-next
1106 /// creates a new `EnumerationValuesStorage` with the given values and a final zero value.
1107 pub const fn new<const N: usize>(values: [E; N]) -> Self {
1108 #[repr(C)]
1109 #[derive(Copy, Clone)]
1110 struct Both<E: Copy, const N: usize>([E; N], [E; 1]);
1111
1112 #[repr(C)]
1113 union Transmute<E: Copy, const N: usize, const S: usize> {
1114 from: Both<E, N>,
1115 to: [E; S],
1116 }
1117
1118 // SAFETY: Transmute is repr(C) and union fields are compatible in terms of size and alignment, so the access to union fields is safe.
1119 unsafe {
1120 // create an array with the values and terminated by a zero value.
1121 let all = Transmute {
1122 from: Both(values, [E::ZERO; 1]),
1123 }
1124 .to;
1125 Self(all)
1126 }
1127 }
1128}
1129
1130impl<E: EnumerationValue<E>, const S: usize> AsRef<EnumerationValues<E>>
1131 for EnumerationValuesStorage<E, S>
1132{
1133 fn as_ref(&self) -> &EnumerationValues<E> {
1134 // SAFETY: EnumerationStorage and EnumerationValues are repr(C) and their unique field are compatible (array and slice of the same type), so the cast is safe.
1135 unsafe { &*(&self.0 as *const [E] as *const EnumerationValues<E>) }
1136 }
1137}
1138
1139// rustdoc-stripper-ignore-next
1140/// Representation of enumeration values wrapped by `EnumerationValuesStorage`.
1141/// Easier to use because don't have a size parameter to be specify. Should be
1142/// used only to register an enum or flags as a dynamic type.
1143/// see `TypePluginRegisterImpl::register_dynamic_enum()`, `TypePluginRegisterImpl::register_dynamic_flags()`
1144/// and `TypePluginImpl::complete_type_info()`.
1145/// Field is intentionally private to ensure other modules will not access the
1146/// enum (or flags) values by this way.
1147/// Use `EnumClass::values()` or `EnumClass::value()` to get the enum values.
1148/// Use `FlagsClass::values()` or `FlagsClass::value()` to get the flags values.
1149#[repr(C)]
1150pub struct EnumerationValues<E: EnumerationValue<E>>([E]);
1151
1152impl<E: EnumerationValue<E>> Deref for EnumerationValues<E> {
1153 type Target = [E];
1154
1155 // rustdoc-stripper-ignore-next
1156 /// Dereferences the enumeration values as a slice, but excluding the last value which is zero.
1157 fn deref(&self) -> &Self::Target {
1158 // SAFETY: EnumerationValues contains at least the zero value which terminates the array.
1159 unsafe { std::slice::from_raw_parts(self.0.as_ptr(), self.0.len() - 1) }
1160 }
1161}
1162
1163#[doc(hidden)]
1164impl<'a, E: 'a + EnumerationValue<E>> ToGlibPtr<'a, *const E::GlibType> for EnumerationValues<E> {
1165 type Storage = &'a Self;
1166
1167 fn to_glib_none(&'a self) -> Stash<'a, *const E::GlibType, Self> {
1168 Stash(self.0.as_ptr() as *const E::GlibType, self)
1169 }
1170}
1171
1172#[cfg(test)]
1173mod tests {
1174 use super::*;
1175
1176 #[test]
1177 fn test_flags() {
1178 let flags = FlagsClass::new::<crate::BindingFlags>();
1179 let values = flags.values();
1180 let def1 = values
1181 .iter()
1182 .find(|v| v.name() == "G_BINDING_DEFAULT")
1183 .unwrap();
1184 let def2 = flags.value_by_name("G_BINDING_DEFAULT").unwrap();
1185 assert!(ptr::eq(def1, def2));
1186
1187 let value = flags.to_value(0).unwrap();
1188 let values = value.get::<Vec<&FlagsValue>>().unwrap();
1189 assert_eq!(values.len(), 0);
1190
1191 assert_eq!(def1.value(), crate::BindingFlags::DEFAULT.bits());
1192 }
1193}
1194