Skip to main content

glib/
enums.rs

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