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