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