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