glib/
enums.rs

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