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    ffi, gobject_ffi, prelude::*, translate::*, ParamSpecEnum, ParamSpecFlags, Type, TypeInfo,
7    Value,
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        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        let (_, v) = EnumValue::from_value(value).unwrap();
356        // SAFETY: The enum class and its values live forever
357        std::mem::transmute(v)
358    }
359}
360
361// rustdoc-stripper-ignore-next
362/// Define the zero value and the associated GLib type.
363impl EnumerationValue<EnumValue> for EnumValue {
364    type GlibType = gobject_ffi::GEnumValue;
365    const ZERO: EnumValue = unsafe {
366        EnumValue::unsafe_from(gobject_ffi::GEnumValue {
367            value: 0,
368            value_name: ptr::null(),
369            value_nick: ptr::null(),
370        })
371    };
372}
373
374// rustdoc-stripper-ignore-next
375/// Storage of enum values.
376pub type EnumValuesStorage<const N: usize> = EnumerationValuesStorage<EnumValue, N>;
377
378// rustdoc-stripper-ignore-next
379/// Representation of enum values wrapped by `EnumValuesStorage`
380pub type EnumValues = EnumerationValues<EnumValue>;
381
382pub struct EnumTypeChecker();
383unsafe impl crate::value::ValueTypeChecker for EnumTypeChecker {
384    type Error = InvalidEnumError;
385
386    fn check(value: &Value) -> Result<(), Self::Error> {
387        let t = value.type_();
388        if t.is_a(Type::ENUM) {
389            Ok(())
390        } else {
391            Err(InvalidEnumError)
392        }
393    }
394}
395
396// rustdoc-stripper-ignore-next
397/// An error returned from the [`get`](struct.Value.html#method.get) function
398/// on a [`Value`](struct.Value.html) for enum types.
399#[derive(Clone, PartialEq, Eq, Debug)]
400pub struct InvalidEnumError;
401
402impl fmt::Display for InvalidEnumError {
403    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
404        write!(f, "Value is not an enum")
405    }
406}
407
408impl std::error::Error for InvalidEnumError {}
409
410// rustdoc-stripper-ignore-next
411/// Representation of a `flags` for dynamically, at runtime, querying the values of the enum and
412/// using them
413#[doc(alias = "GFlagsClass")]
414#[repr(transparent)]
415pub struct FlagsClass(ptr::NonNull<gobject_ffi::GFlagsClass>);
416
417unsafe impl Send for FlagsClass {}
418unsafe impl Sync for FlagsClass {}
419
420impl fmt::Debug for FlagsClass {
421    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
422        f.debug_struct("FlagsClass")
423            .field("type", &self.type_())
424            .field("values", &self.values())
425            .finish()
426    }
427}
428
429impl FlagsClass {
430    // rustdoc-stripper-ignore-next
431    /// Create a new `FlagsClass` from a static type `T`.
432    ///
433    /// Panics if `T` is not representing an flags type.
434    pub fn new<T: StaticType + HasParamSpec<ParamSpec = ParamSpecFlags>>() -> Self {
435        Self::with_type(T::static_type()).expect("invalid flags class")
436    }
437    // rustdoc-stripper-ignore-next
438    /// Create a new `FlagsClass` from a `Type`
439    ///
440    /// Returns `None` if `type_` is not representing a flags type.
441    pub fn with_type(type_: Type) -> Option<Self> {
442        unsafe {
443            let is_flags: bool = from_glib(gobject_ffi::g_type_is_a(
444                type_.into_glib(),
445                gobject_ffi::G_TYPE_FLAGS,
446            ));
447            if !is_flags {
448                return None;
449            }
450
451            Some(FlagsClass(
452                ptr::NonNull::new(gobject_ffi::g_type_class_ref(type_.into_glib()) as *mut _)
453                    .unwrap(),
454            ))
455        }
456    }
457
458    // rustdoc-stripper-ignore-next
459    /// `Type` of the flags.
460    pub fn type_(&self) -> Type {
461        unsafe { from_glib(self.0.as_ref().g_type_class.g_type) }
462    }
463
464    // rustdoc-stripper-ignore-next
465    /// Gets `FlagsValue` by integer `value`, if existing.
466    ///
467    /// Returns `None` if the flags do not contain any value
468    /// with `value`.
469    #[doc(alias = "g_flags_get_first_value")]
470    #[doc(alias = "get_value")]
471    pub fn value(&self, value: u32) -> Option<&FlagsValue> {
472        unsafe {
473            let v = gobject_ffi::g_flags_get_first_value(self.0.as_ptr(), value);
474            if v.is_null() {
475                None
476            } else {
477                Some(&*(v as *const FlagsValue))
478            }
479        }
480    }
481
482    // rustdoc-stripper-ignore-next
483    /// Gets `FlagsValue` by string name `name`, if existing.
484    ///
485    /// Returns `None` if the flags do not contain any value
486    /// with name `name`.
487    #[doc(alias = "g_flags_get_value_by_name")]
488    #[doc(alias = "get_value_by_name")]
489    pub fn value_by_name(&self, name: &str) -> Option<&FlagsValue> {
490        unsafe {
491            let v = gobject_ffi::g_flags_get_value_by_name(self.0.as_ptr(), name.to_glib_none().0);
492            if v.is_null() {
493                None
494            } else {
495                Some(&*(v as *const FlagsValue))
496            }
497        }
498    }
499
500    // rustdoc-stripper-ignore-next
501    /// Gets `FlagsValue` by string nick `nick`, if existing.
502    ///
503    /// Returns `None` if the flags do not contain any value
504    /// with nick `nick`.
505    #[doc(alias = "g_flags_get_value_by_nick")]
506    #[doc(alias = "get_value_by_nick")]
507    pub fn value_by_nick(&self, nick: &str) -> Option<&FlagsValue> {
508        unsafe {
509            let v = gobject_ffi::g_flags_get_value_by_nick(self.0.as_ptr(), nick.to_glib_none().0);
510            if v.is_null() {
511                None
512            } else {
513                Some(&*(v as *const FlagsValue))
514            }
515        }
516    }
517
518    // rustdoc-stripper-ignore-next
519    /// Gets all `FlagsValue` of this `FlagsClass`.
520    #[doc(alias = "get_values")]
521    pub fn values(&self) -> &[FlagsValue] {
522        unsafe {
523            if self.0.as_ref().n_values == 0 {
524                return &[];
525            }
526            std::slice::from_raw_parts(
527                self.0.as_ref().values as *const FlagsValue,
528                self.0.as_ref().n_values as usize,
529            )
530        }
531    }
532
533    // rustdoc-stripper-ignore-next
534    /// Converts integer `value` to a `Value`, if part of the flags.
535    pub fn to_value(&self, value: u32) -> Option<Value> {
536        self.value(value).map(|v| v.to_value(self))
537    }
538
539    // rustdoc-stripper-ignore-next
540    /// Converts string name `name` to a `Value`, if part of the flags.
541    pub fn to_value_by_name(&self, name: &str) -> Option<Value> {
542        self.value_by_name(name).map(|v| v.to_value(self))
543    }
544
545    // rustdoc-stripper-ignore-next
546    /// Converts string nick `nick` to a `Value`, if part of the flags.
547    pub fn to_value_by_nick(&self, nick: &str) -> Option<Value> {
548        self.value_by_nick(nick).map(|v| v.to_value(self))
549    }
550
551    // rustdoc-stripper-ignore-next
552    /// Checks if the flags corresponding to integer `f` is set in `value`.
553    pub fn is_set(&self, value: &Value, f: u32) -> bool {
554        unsafe {
555            if self.type_() != value.type_() {
556                return false;
557            }
558
559            let flags = gobject_ffi::g_value_get_flags(value.to_glib_none().0);
560            flags & f != 0
561        }
562    }
563
564    // rustdoc-stripper-ignore-next
565    /// Checks if the flags corresponding to string name `name` is set in `value`.
566    pub fn is_set_by_name(&self, value: &Value, name: &str) -> bool {
567        unsafe {
568            if self.type_() != value.type_() {
569                return false;
570            }
571
572            if let Some(f) = self.value_by_name(name) {
573                let flags = gobject_ffi::g_value_get_flags(value.to_glib_none().0);
574                flags & f.value() != 0
575            } else {
576                false
577            }
578        }
579    }
580
581    // rustdoc-stripper-ignore-next
582    /// Checks if the flags corresponding to string nick `nick` is set in `value`.
583    pub fn is_set_by_nick(&self, value: &Value, nick: &str) -> bool {
584        unsafe {
585            if self.type_() != value.type_() {
586                return false;
587            }
588
589            if let Some(f) = self.value_by_nick(nick) {
590                let flags = gobject_ffi::g_value_get_flags(value.to_glib_none().0);
591                flags & f.value() != 0
592            } else {
593                false
594            }
595        }
596    }
597
598    // rustdoc-stripper-ignore-next
599    /// Set flags value corresponding to integer `f` in `value`, if part of that flags. If the
600    /// flag is already set, it will succeed without doing any changes.
601    ///
602    /// Returns `Ok(value)` with the flag set if successful, or `Err(value)` with the original
603    /// value otherwise.
604    #[doc(alias = "g_value_set_flags")]
605    pub fn set(&self, mut value: Value, f: u32) -> Result<Value, Value> {
606        unsafe {
607            if self.type_() != value.type_() {
608                return Err(value);
609            }
610
611            if let Some(f) = self.value(f) {
612                let flags = gobject_ffi::g_value_get_flags(value.to_glib_none().0);
613                gobject_ffi::g_value_set_flags(value.to_glib_none_mut().0, flags | f.value());
614                Ok(value)
615            } else {
616                Err(value)
617            }
618        }
619    }
620
621    // rustdoc-stripper-ignore-next
622    /// Set flags value corresponding to string name `name` in `value`, if part of that flags.
623    /// If the flag is already set, it will succeed without doing any changes.
624    ///
625    /// Returns `Ok(value)` with the flag set if successful, or `Err(value)` with the original
626    /// value otherwise.
627    pub fn set_by_name(&self, mut value: Value, name: &str) -> Result<Value, Value> {
628        unsafe {
629            if self.type_() != value.type_() {
630                return Err(value);
631            }
632
633            if let Some(f) = self.value_by_name(name) {
634                let flags = gobject_ffi::g_value_get_flags(value.to_glib_none().0);
635                gobject_ffi::g_value_set_flags(value.to_glib_none_mut().0, flags | f.value());
636                Ok(value)
637            } else {
638                Err(value)
639            }
640        }
641    }
642
643    // rustdoc-stripper-ignore-next
644    /// Set flags value corresponding to string nick `nick` in `value`, if part of that flags.
645    /// If the flag is already set, it will succeed without doing any changes.
646    ///
647    /// Returns `Ok(value)` with the flag set if successful, or `Err(value)` with the original
648    /// value otherwise.
649    pub fn set_by_nick(&self, mut value: Value, nick: &str) -> Result<Value, Value> {
650        unsafe {
651            if self.type_() != value.type_() {
652                return Err(value);
653            }
654
655            if let Some(f) = self.value_by_nick(nick) {
656                let flags = gobject_ffi::g_value_get_flags(value.to_glib_none().0);
657                gobject_ffi::g_value_set_flags(value.to_glib_none_mut().0, flags | f.value());
658                Ok(value)
659            } else {
660                Err(value)
661            }
662        }
663    }
664
665    // rustdoc-stripper-ignore-next
666    /// Unset flags value corresponding to integer `f` in `value`, if part of that flags.
667    /// If the flag is already unset, it will succeed without doing any changes.
668    ///
669    /// Returns `Ok(value)` with the flag unset if successful, or `Err(value)` with the original
670    /// value otherwise.
671    pub fn unset(&self, mut value: Value, f: u32) -> Result<Value, Value> {
672        unsafe {
673            if self.type_() != value.type_() {
674                return Err(value);
675            }
676
677            if let Some(f) = self.value(f) {
678                let flags = gobject_ffi::g_value_get_flags(value.to_glib_none().0);
679                gobject_ffi::g_value_set_flags(value.to_glib_none_mut().0, flags & !f.value());
680                Ok(value)
681            } else {
682                Err(value)
683            }
684        }
685    }
686
687    // rustdoc-stripper-ignore-next
688    /// Unset flags value corresponding to string name `name` in `value`, if part of that flags.
689    /// If the flag is already unset, it will succeed without doing any changes.
690    ///
691    /// Returns `Ok(value)` with the flag unset if successful, or `Err(value)` with the original
692    /// value otherwise.
693    pub fn unset_by_name(&self, mut value: Value, name: &str) -> Result<Value, Value> {
694        unsafe {
695            if self.type_() != value.type_() {
696                return Err(value);
697            }
698
699            if let Some(f) = self.value_by_name(name) {
700                let flags = gobject_ffi::g_value_get_flags(value.to_glib_none().0);
701                gobject_ffi::g_value_set_flags(value.to_glib_none_mut().0, flags & !f.value());
702                Ok(value)
703            } else {
704                Err(value)
705            }
706        }
707    }
708
709    // rustdoc-stripper-ignore-next
710    /// Unset flags value corresponding to string nick `nick` in `value`, if part of that flags.
711    /// If the flag is already unset, it will succeed without doing any changes.
712    ///
713    /// Returns `Ok(value)` with the flag unset if successful, or `Err(value)` with the original
714    /// value otherwise.
715    pub fn unset_by_nick(&self, mut value: Value, nick: &str) -> Result<Value, Value> {
716        unsafe {
717            if self.type_() != value.type_() {
718                return Err(value);
719            }
720
721            if let Some(f) = self.value_by_nick(nick) {
722                let flags = gobject_ffi::g_value_get_flags(value.to_glib_none().0);
723                gobject_ffi::g_value_set_flags(value.to_glib_none_mut().0, flags & !f.value());
724                Ok(value)
725            } else {
726                Err(value)
727            }
728        }
729    }
730
731    // rustdoc-stripper-ignore-next
732    /// Converts an integer `value` to a string of nicks separated by `|`.
733    pub fn to_nick_string(&self, mut value: u32) -> String {
734        let mut s = String::new();
735        for val in self.values() {
736            let v = val.value();
737            if v != 0 && (value & v) == v {
738                value &= !v;
739                if !s.is_empty() {
740                    s.push('|');
741                }
742                s.push_str(val.nick());
743            }
744        }
745        s
746    }
747
748    // rustdoc-stripper-ignore-next
749    /// Converts a string of nicks `s` separated by `|` to an integer value.
750    pub fn from_nick_string(&self, s: &str) -> Result<u32, ParseFlagsError> {
751        s.split('|').try_fold(0u32, |acc, flag| {
752            self.value_by_nick(flag.trim())
753                .map(|v| acc + v.value())
754                .ok_or_else(|| ParseFlagsError(flag.to_owned()))
755        })
756    }
757
758    // rustdoc-stripper-ignore-next
759    /// Returns a new `FlagsBuilder` for conveniently setting/unsetting flags
760    /// and building a `Value`.
761    pub fn builder(&self) -> FlagsBuilder {
762        FlagsBuilder::new(self)
763    }
764
765    // rustdoc-stripper-ignore-next
766    /// Returns a new `FlagsBuilder` for conveniently setting/unsetting flags
767    /// and building a `Value`. The `Value` is initialized with `value`.
768    pub fn builder_with_value(&self, value: Value) -> Option<FlagsBuilder> {
769        if self.type_() != value.type_() {
770            return None;
771        }
772
773        Some(FlagsBuilder::with_value(self, value))
774    }
775
776    // rustdoc-stripper-ignore-next
777    /// Complete `TypeInfo` for the flags with values.
778    /// This is an associated function. A method would result in a stack overflow due to a recurvice call:
779    /// callers should first create an `FlagsClass` instance by calling `FlagsClass::with_type()` which indirectly
780    /// calls `TypePluginRegisterImpl::register_dynamic_flags()` and `TypePluginImpl::complete_type_info()`
781    /// and one of them should call `FlagsClass::with_type()` before calling this method.
782    /// `const_static_values` is a reference on a wrapper of a slice of `FlagsValue`.
783    /// It must be static to ensure flags values are never dropped, and ensures that slice is terminated
784    ///  by an `FlagsValue` with all members being 0, as expected by GLib.
785    #[doc(alias = "g_flags_complete_type_info")]
786    pub fn complete_type_info(
787        type_: Type,
788        const_static_values: &'static FlagsValues,
789    ) -> Option<TypeInfo> {
790        unsafe {
791            let is_flags: bool = from_glib(gobject_ffi::g_type_is_a(
792                type_.into_glib(),
793                gobject_ffi::G_TYPE_FLAGS,
794            ));
795            if !is_flags {
796                return None;
797            }
798
799            let info = TypeInfo::default();
800            gobject_ffi::g_flags_complete_type_info(
801                type_.into_glib(),
802                info.as_ptr(),
803                const_static_values.to_glib_none().0,
804            );
805            Some(info)
806        }
807    }
808}
809
810impl Drop for FlagsClass {
811    #[inline]
812    fn drop(&mut self) {
813        unsafe {
814            gobject_ffi::g_type_class_unref(self.0.as_ptr() as *mut _);
815        }
816    }
817}
818
819impl Clone for FlagsClass {
820    #[inline]
821    fn clone(&self) -> Self {
822        unsafe {
823            Self(ptr::NonNull::new(gobject_ffi::g_type_class_ref(self.type_().into_glib()) as *mut _).unwrap())
824        }
825    }
826}
827
828#[derive(Debug)]
829pub struct ParseFlagsError(String);
830
831impl std::error::Error for ParseFlagsError {}
832
833impl fmt::Display for ParseFlagsError {
834    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
835        write!(f, "Unknown flag: '{}'", self.0)
836    }
837}
838
839impl ParseFlagsError {
840    pub fn flag(&self) -> &str {
841        &self.0
842    }
843}
844
845// rustdoc-stripper-ignore-next
846/// Representation of a single flags value of a `FlagsClass`.
847// rustdoc-stripper-ignore-next-stop
848/// A structure which contains a single flags value, its name, and its
849/// nickname.
850#[doc(alias = "GFlagsValue")]
851#[derive(Copy, Clone)]
852#[repr(transparent)]
853pub struct FlagsValue(gobject_ffi::GFlagsValue);
854
855unsafe impl Send for FlagsValue {}
856unsafe impl Sync for FlagsValue {}
857
858impl fmt::Debug for FlagsValue {
859    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
860        f.debug_struct("FlagsValue")
861            .field("value", &self.value())
862            .field("name", &self.name())
863            .field("nick", &self.nick())
864            .finish()
865    }
866}
867
868impl FlagsValue {
869    // rustdoc-stripper-ignore-next
870    /// # Safety
871    ///
872    /// It is the responsibility of the caller to ensure `GFlagsValue` is
873    /// valid.
874    pub const unsafe fn unsafe_from(g_value: gobject_ffi::GFlagsValue) -> Self {
875        Self(g_value)
876    }
877
878    // rustdoc-stripper-ignore-next
879    /// Get integer value corresponding to the value.
880    #[doc(alias = "get_value")]
881    pub fn value(&self) -> u32 {
882        self.0.value
883    }
884
885    // rustdoc-stripper-ignore-next
886    /// Get name corresponding to the value.
887    #[doc(alias = "get_name")]
888    pub fn name(&self) -> &str {
889        unsafe { CStr::from_ptr(self.0.value_name).to_str().unwrap() }
890    }
891
892    // rustdoc-stripper-ignore-next
893    /// Get nick corresponding to the value.
894    #[doc(alias = "get_nick")]
895    pub fn nick(&self) -> &str {
896        unsafe { CStr::from_ptr(self.0.value_nick).to_str().unwrap() }
897    }
898
899    // rustdoc-stripper-ignore-next
900    /// Convert flags value to a `Value`.
901    pub fn to_value(&self, flags: &FlagsClass) -> Value {
902        unsafe {
903            let mut v = Value::from_type_unchecked(flags.type_());
904            gobject_ffi::g_value_set_flags(v.to_glib_none_mut().0, self.0.value);
905            v
906        }
907    }
908
909    // rustdoc-stripper-ignore-next
910    /// Convert flags values from a `Value`. This returns all flags that are set.
911    pub fn from_value(value: &Value) -> Option<(FlagsClass, Vec<&FlagsValue>)> {
912        unsafe {
913            let flags_class = FlagsClass::with_type(value.type_())?;
914            let mut res = Vec::new();
915            let f = gobject_ffi::g_value_get_flags(value.to_glib_none().0);
916            for v in flags_class.values() {
917                if v.value() & f != 0 {
918                    res.push(&*(v as *const FlagsValue));
919                }
920            }
921            Some((flags_class, res))
922        }
923    }
924}
925
926impl PartialEq for FlagsValue {
927    fn eq(&self, other: &Self) -> bool {
928        self.value().eq(&other.value())
929    }
930}
931
932impl Eq for FlagsValue {}
933
934impl UnsafeFrom<gobject_ffi::GFlagsValue> for FlagsValue {
935    unsafe fn unsafe_from(g_value: gobject_ffi::GFlagsValue) -> Self {
936        Self::unsafe_from(g_value)
937    }
938}
939
940// rustdoc-stripper-ignore-next
941/// Define the zero value and the associated GLib type.
942impl EnumerationValue<FlagsValue> for FlagsValue {
943    type GlibType = gobject_ffi::GFlagsValue;
944    const ZERO: FlagsValue = unsafe {
945        FlagsValue::unsafe_from(gobject_ffi::GFlagsValue {
946            value: 0,
947            value_name: ptr::null(),
948            value_nick: ptr::null(),
949        })
950    };
951}
952
953// rustdoc-stripper-ignore-next
954/// Storage of flags values.
955pub type FlagsValuesStorage<const N: usize> = EnumerationValuesStorage<FlagsValue, N>;
956
957// rustdoc-stripper-ignore-next
958/// Representation of flags values wrapped by `FlagsValuesStorage`
959pub type FlagsValues = EnumerationValues<FlagsValue>;
960
961// rustdoc-stripper-ignore-next
962/// Builder for conveniently setting/unsetting flags and returning a `Value`.
963///
964/// Example for getting a flags property, unsetting some flags and setting the updated flags on the
965/// object again:
966///
967/// ```ignore
968/// let flags = obj.property("flags").unwrap();
969/// let flags_class = FlagsClass::new(flags.type_()).unwrap();
970/// let flags = flags_class.builder_with_value(flags).unwrap()
971///     .unset_by_nick("some-flag")
972///     .unset_by_nick("some-other-flag")
973///     .build()
974///     .unwrap();
975/// obj.set_property("flags", &flags).unwrap();
976/// ```
977///
978/// If setting/unsetting any value fails, `build()` returns `None`.
979#[must_use = "The builder must be built to be used"]
980pub struct FlagsBuilder<'a>(&'a FlagsClass, Option<Value>);
981impl FlagsBuilder<'_> {
982    fn new(flags_class: &FlagsClass) -> FlagsBuilder {
983        let value = unsafe { Value::from_type_unchecked(flags_class.type_()) };
984        FlagsBuilder(flags_class, Some(value))
985    }
986
987    fn with_value(flags_class: &FlagsClass, value: Value) -> FlagsBuilder {
988        FlagsBuilder(flags_class, Some(value))
989    }
990
991    // rustdoc-stripper-ignore-next
992    /// Set flags corresponding to integer value `f`.
993    pub fn set(mut self, f: u32) -> Self {
994        if let Some(value) = self.1.take() {
995            self.1 = self.0.set(value, f).ok();
996        }
997
998        self
999    }
1000
1001    // rustdoc-stripper-ignore-next
1002    /// Set flags corresponding to string name `name`.
1003    pub fn set_by_name(mut self, name: &str) -> Self {
1004        if let Some(value) = self.1.take() {
1005            self.1 = self.0.set_by_name(value, name).ok();
1006        }
1007
1008        self
1009    }
1010
1011    // rustdoc-stripper-ignore-next
1012    /// Set flags corresponding to string nick `nick`.
1013    pub fn set_by_nick(mut self, nick: &str) -> Self {
1014        if let Some(value) = self.1.take() {
1015            self.1 = self.0.set_by_nick(value, nick).ok();
1016        }
1017
1018        self
1019    }
1020
1021    // rustdoc-stripper-ignore-next
1022    /// Unsets flags corresponding to integer value `f`.
1023    pub fn unset(mut self, f: u32) -> Self {
1024        if let Some(value) = self.1.take() {
1025            self.1 = self.0.unset(value, f).ok();
1026        }
1027
1028        self
1029    }
1030
1031    // rustdoc-stripper-ignore-next
1032    /// Unset flags corresponding to string name `name`.
1033    pub fn unset_by_name(mut self, name: &str) -> Self {
1034        if let Some(value) = self.1.take() {
1035            self.1 = self.0.unset_by_name(value, name).ok();
1036        }
1037
1038        self
1039    }
1040
1041    // rustdoc-stripper-ignore-next
1042    /// Unset flags corresponding to string nick `nick`.
1043    pub fn unset_by_nick(mut self, nick: &str) -> Self {
1044        if let Some(value) = self.1.take() {
1045            self.1 = self.0.unset_by_nick(value, nick).ok();
1046        }
1047
1048        self
1049    }
1050
1051    // rustdoc-stripper-ignore-next
1052    /// Converts to the final `Value`, unless any previous setting/unsetting of flags failed.
1053    #[must_use = "Value returned from the builder should probably be used"]
1054    pub fn build(self) -> Option<Value> {
1055        self.1
1056    }
1057}
1058
1059unsafe impl<'a> crate::value::FromValue<'a> for Vec<&FlagsValue> {
1060    type Checker = FlagsTypeChecker;
1061
1062    unsafe fn from_value(value: &'a Value) -> Self {
1063        let (_, v) = FlagsValue::from_value(value).unwrap();
1064        // SAFETY: The enum class and its values live forever
1065        std::mem::transmute(v)
1066    }
1067}
1068
1069pub struct FlagsTypeChecker();
1070unsafe impl crate::value::ValueTypeChecker for FlagsTypeChecker {
1071    type Error = InvalidFlagsError;
1072
1073    fn check(value: &Value) -> Result<(), Self::Error> {
1074        let t = value.type_();
1075        if t.is_a(Type::FLAGS) {
1076            Ok(())
1077        } else {
1078            Err(InvalidFlagsError)
1079        }
1080    }
1081}
1082
1083// rustdoc-stripper-ignore-next
1084/// An error returned from the [`get`](struct.Value.html#method.get) function
1085/// on a [`Value`](struct.Value.html) for flags types.
1086#[derive(Clone, PartialEq, Eq, Debug)]
1087pub struct InvalidFlagsError;
1088
1089impl fmt::Display for InvalidFlagsError {
1090    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1091        write!(f, "Value is not a flags")
1092    }
1093}
1094
1095impl std::error::Error for InvalidFlagsError {}
1096
1097// rustdoc-stripper-ignore-next
1098/// helper trait to define the zero value and the associated GLib type.
1099pub trait EnumerationValue<E>: Copy {
1100    type GlibType;
1101    const ZERO: E;
1102}
1103
1104// rustdoc-stripper-ignore-next
1105/// Storage of enumeration values terminated by a zero value. Should be used
1106/// only as a storage location for `EnumValue` or `FlagsValue` when registering
1107/// an enum or flags as a dynamic type.
1108/// see `TypePluginRegisterImpl::register_dynamic_enum()`, `TypePluginRegisterImpl::register_dynamic_flags()`
1109/// and `TypePluginImpl::complete_type_info()`.
1110/// Inner is intentionally private to ensure other modules will not access the
1111/// enum (or flags) values by this way.
1112/// Use `EnumClass::values()` or `EnumClass::value()` to get the enum values.
1113/// Use `FlagsClass::values()` or `FlagsClass::value()` to get the flags values.
1114#[repr(C)]
1115pub struct EnumerationValuesStorage<E: EnumerationValue<E>, const S: usize>([E; S]);
1116
1117impl<E: EnumerationValue<E>, const S: usize> EnumerationValuesStorage<E, S> {
1118    // rustdoc-stripper-ignore-next
1119    /// creates a new `EnumerationValuesStorage` with the given values and a final zero value.
1120    pub const fn new<const N: usize>(values: [E; N]) -> Self {
1121        #[repr(C)]
1122        #[derive(Copy, Clone)]
1123        struct Both<E: Copy, const N: usize>([E; N], [E; 1]);
1124
1125        #[repr(C)]
1126        union Transmute<E: Copy, const N: usize, const S: usize> {
1127            from: Both<E, N>,
1128            to: [E; S],
1129        }
1130
1131        // SAFETY: Transmute is repr(C) and union fields are compatible in terms of size and alignment, so the access to union fields is safe.
1132        unsafe {
1133            // create an array with the values and terminated by a zero value.
1134            let all = Transmute {
1135                from: Both(values, [E::ZERO; 1]),
1136            }
1137            .to;
1138            Self(all)
1139        }
1140    }
1141}
1142
1143impl<E: EnumerationValue<E>, const S: usize> AsRef<EnumerationValues<E>>
1144    for EnumerationValuesStorage<E, S>
1145{
1146    fn as_ref(&self) -> &EnumerationValues<E> {
1147        // 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.
1148        unsafe { &*(&self.0 as *const [E] as *const EnumerationValues<E>) }
1149    }
1150}
1151
1152// rustdoc-stripper-ignore-next
1153/// Representation of enumeration values wrapped by `EnumerationValuesStorage`.
1154/// Easier to use because don't have a size parameter to be specify. Should be
1155/// used only to register an enum or flags as a dynamic type.
1156/// see `TypePluginRegisterImpl::register_dynamic_enum()`, `TypePluginRegisterImpl::register_dynamic_flags()`
1157/// and `TypePluginImpl::complete_type_info()`.
1158/// Field is intentionally private to ensure other modules will not access the
1159/// enum (or flags) values by this way.
1160/// Use `EnumClass::values()` or `EnumClass::value()` to get the enum values.
1161/// Use `FlagsClass::values()` or `FlagsClass::value()` to get the flags values.
1162#[repr(C)]
1163pub struct EnumerationValues<E: EnumerationValue<E>>([E]);
1164
1165impl<E: EnumerationValue<E>> Deref for EnumerationValues<E> {
1166    type Target = [E];
1167
1168    // rustdoc-stripper-ignore-next
1169    /// Dereferences the enumeration values as a slice, but excluding the last value which is zero.
1170    fn deref(&self) -> &Self::Target {
1171        // SAFETY: EnumerationValues contains at least the zero value which terminates the array.
1172        unsafe { std::slice::from_raw_parts(self.0.as_ptr(), self.0.len() - 1) }
1173    }
1174}
1175
1176#[doc(hidden)]
1177impl<'a, E: 'a + EnumerationValue<E>> ToGlibPtr<'a, *const E::GlibType> for EnumerationValues<E> {
1178    type Storage = &'a Self;
1179
1180    fn to_glib_none(&'a self) -> Stash<'a, *const E::GlibType, Self> {
1181        Stash(self.0.as_ptr() as *const E::GlibType, self)
1182    }
1183}
1184
1185#[cfg(test)]
1186mod tests {
1187    use super::*;
1188
1189    #[test]
1190    fn test_flags() {
1191        let flags = FlagsClass::new::<crate::BindingFlags>();
1192        let values = flags.values();
1193        let def1 = values
1194            .iter()
1195            .find(|v| v.name() == "G_BINDING_DEFAULT")
1196            .unwrap();
1197        let def2 = flags.value_by_name("G_BINDING_DEFAULT").unwrap();
1198        assert!(ptr::eq(def1, def2));
1199
1200        let value = flags.to_value(0).unwrap();
1201        let values = value.get::<Vec<&FlagsValue>>().unwrap();
1202        assert_eq!(values.len(), 0);
1203
1204        assert_eq!(def1.value(), crate::BindingFlags::DEFAULT.bits());
1205    }
1206}