Skip to main content

glib/
translate.rs

1// Take a look at the license at the top of the repository in the LICENSE file.
2
3// rustdoc-stripper-ignore-next
4//! Translation between GLib/GLib-based FFI types and their Rust counterparts.
5//!
6//! This module allows library bindings authors to decouple type translation
7//! logic and use unified idioms at FFI boundaries. It also implements
8//! translation of GLib core data types.
9//!
10//! `FromGlib`, `from_glib` and `IntoGlib` translate simple types like `bool`.
11//!
12//! ```ignore
13//!     pub fn set_accept_focus(&self, accept_focus: bool) {
14//!         unsafe { gdk::ffi::gdk_window_set_accept_focus(self.pointer, accept_focus.into_glib()) }
15//!     }
16//!
17//!     pub fn get_accept_focus(&self) -> bool {
18//!         unsafe { from_glib(gdk::ffi::gdk_window_get_accept_focus(self.pointer)) }
19//!     }
20//! ```
21//!
22//! Implementing [`OptionIntoGlib`] on a Rust type `T` allows specifying a sentinel to indicate
23//! a `None` value and auto-implementing [`FromGlib`] for `Option<T>`, which would not be
24//! possible in dependent crates due to the [orphan rule](https://doc.rust-lang.org/book/ch10-02-traits.html#implementing-a-trait-on-a-type).
25//! In the example below, [`IntoGlib`] is auto-implemented for `Option<SpecialU32>`.
26//!
27//! ```
28//! # use glib::translate::*;
29//! struct SpecialU32(u32);
30//! impl IntoGlib for SpecialU32 {
31//!     type GlibType = libc::c_uint;
32//!     fn into_glib(self) -> libc::c_uint {
33//!         self.0 as libc::c_uint
34//!     }
35//! }
36//! impl OptionIntoGlib for SpecialU32 {
37//!     const GLIB_NONE: Self::GlibType = 0xFFFFFF;
38//! }
39//! ```
40//!
41//! In order to auto-implement [`FromGlib`] for `Option<SpecialU32>`, proceed as follows:
42//!
43//! ```
44//! # use glib::translate::*;
45//! # struct SpecialU32(u32);
46//! # impl IntoGlib for SpecialU32 {
47//! #     type GlibType = libc::c_uint;
48//! #     fn into_glib(self) -> libc::c_uint {
49//! #         self.0 as libc::c_uint
50//! #     }
51//! # }
52//! # impl OptionIntoGlib for SpecialU32 {
53//! #     const GLIB_NONE: Self::GlibType = 0xFFFFFF;
54//! # }
55//! impl TryFromGlib<libc::c_uint> for SpecialU32 {
56//!     type Error = GlibNoneError;
57//!     unsafe fn try_from_glib(val: libc::c_uint) -> Result<Self, GlibNoneError> {
58//!         if val == SpecialU32::GLIB_NONE {
59//!             return Err(GlibNoneError);
60//!         }
61//!         Ok(SpecialU32(val as u32))
62//!     }
63//! }
64//! ```
65//!
66//! The [`TryFromGlib`] trait can also be implemented when the Glib type range is larger than the
67//! target Rust type's range. In the example below, the Rust type `U32` can be built from a signed
68//! [`libc::c_long`], which means that the negative range is not valid.
69//!
70//! ```
71//! # use std::convert::TryFrom;
72//! # use std::num::TryFromIntError;
73//! # use glib::translate::*;
74//! struct U32(u32);
75//! impl TryFromGlib<libc::c_long> for U32 {
76//!     type Error = TryFromIntError;
77//!     unsafe fn try_from_glib(val: libc::c_long) -> Result<Self, TryFromIntError> {
78//!         Ok(U32(u32::try_from(val)?))
79//!     }
80//! }
81//! ```
82//!
83//! Finally, you can define [`TryFromGlib`] with both `None` and `Invalid` alternatives by setting
84//! the associated `type Error = GlibNoneOrInvalidError<I>` (where `I` is the `Error` type
85//! when the value is invalid), which results in auto-implementing [`FromGlib`] for
86//! `Result<Option<T>, I>`.
87//!
88//! `ToGlibPtr`, `FromGlibPtrNone`, `FromGlibPtrFull` and `FromGlibPtrBorrow` work on `gpointer`s
89//! and ensure correct ownership of values
90//! according to [Glib ownership transfer rules](https://gi.readthedocs.io/en/latest/annotations/giannotations.html).
91//!
92//! `FromGlibPtrNone` and `FromGlibPtrFull`
93//! must be called on values obtained from C,
94//! according to their `transfer` annotations.
95//! They acquire non-gobject types,
96//! as well as turning floating references to strong ones,
97//! which are the only ones properly handled by the Rust bindings.
98//!
99//! For more information about floating references, please refer to the "Floating references" section
100//! of [the gobject reference](https://docs.gtk.org/gobject/floating-refs.html).
101//!
102//! ```ignore
103//!     fn get_title(&self) -> Option<String> {
104//!         unsafe {
105//!             let title = gtk::ffi::gtk_window_get_title(self.pointer);
106//!             from_glib_none(title)
107//!         }
108//!     }
109//!     fn create_bool(value: gboolean) -> Variant {
110//!         unsafe {
111//!             let variant = ffi::g_variant_new_boolean(value);
112//!             // g_variant_new_boolean has `transfer none`
113//!             from_glib_none(variant)
114//!         }
115//!     }
116//! ```
117//!
118//! Letting the foreign library borrow pointers from the Rust side often
119//! requires having a temporary variable of an intermediate type (e.g. `CString`).
120//! A `Stash` contains the temporary storage and a pointer into it that
121//! is valid for the lifetime of the `Stash`. As the lifetime of the `Stash` returned
122//! from `to_glib_none` is at least the enclosing statement, you can avoid explicitly
123//! binding the stash in most cases and just take the pointer out of it:
124//!
125//! ```ignore
126//!     pub fn set_icon_name(&self, name: &str) {
127//!         unsafe {
128//!             gdk::ffi::gdk_window_set_icon_name(self.pointer, name.to_glib_none().0)
129//!         }
130//!     }
131//! ```
132
133#[cfg(not(windows))]
134use std::os::unix::prelude::*;
135use std::{
136    borrow::Cow,
137    char,
138    cmp::Ordering,
139    collections::HashMap,
140    error::Error,
141    ffi::{CStr, CString, OsStr, OsString},
142    fmt,
143    marker::PhantomData,
144    mem,
145    path::{Path, PathBuf},
146    ptr,
147};
148
149pub use crate::collections::{ptr_slice::IntoPtrSlice, strv::IntoStrV};
150use crate::ffi;
151pub use crate::gstring::{IntoGStr, IntoOptionalGStr};
152
153use libc::{c_char, size_t};
154
155// rustdoc-stripper-ignore-next
156/// A pointer
157pub trait Ptr: Copy + 'static {
158    fn is_null(&self) -> bool;
159    fn from<X>(ptr: *mut X) -> Self;
160    fn to<X>(self) -> *mut X;
161}
162
163impl<T: 'static> Ptr for *const T {
164    #[inline]
165    fn is_null(&self) -> bool {
166        (*self).is_null()
167    }
168
169    #[inline]
170    fn from<X>(ptr: *mut X) -> *const T {
171        ptr as *const T
172    }
173
174    #[inline]
175    fn to<X>(self) -> *mut X {
176        self as *mut X
177    }
178}
179
180impl<T: 'static> Ptr for *mut T {
181    #[inline]
182    fn is_null(&self) -> bool {
183        (*self).is_null()
184    }
185
186    #[inline]
187    fn from<X>(ptr: *mut X) -> *mut T {
188        ptr as *mut T
189    }
190
191    #[inline]
192    fn to<X>(self) -> *mut X {
193        self as *mut X
194    }
195}
196
197// rustdoc-stripper-ignore-next
198/// Overrides pointer mutability.
199///
200/// Use when the C API should be specifying a const pointer but doesn't.
201#[inline]
202pub fn mut_override<T>(ptr: *const T) -> *mut T {
203    ptr as *mut T
204}
205
206// rustdoc-stripper-ignore-next
207/// Overrides pointer constness.
208///
209/// Use when the C API need const pointer, but function with `IsA<T>` constraint,
210/// that usually don't have const pointer conversion.
211#[inline]
212pub fn const_override<T>(ptr: *mut T) -> *const T {
213    ptr as *const T
214}
215
216// rustdoc-stripper-ignore-next
217/// A trait for creating an uninitialized value. Handy for receiving outparams.
218pub trait Uninitialized {
219    // Returns an uninitialized value.
220    unsafe fn uninitialized() -> Self;
221}
222
223// rustdoc-stripper-ignore-next
224/// Returns an uninitialized value.
225#[inline]
226pub unsafe fn uninitialized<T: Uninitialized>() -> T {
227    unsafe { T::uninitialized() }
228}
229
230// rustdoc-stripper-ignore-next
231/// Helper type that stores temporary values used for translation.
232///
233/// `P` is the foreign type pointer and the first element of the tuple.
234///
235/// `T` is the Rust type that is translated.
236///
237/// The second element of the tuple is the temporary storage defined
238/// by the implementation of `ToGlibPtr<P> for T`
239///
240/// Say you want to pass a `*mut GdkWindowAttr` to a foreign function. The `Stash`
241/// will own a `GdkWindowAttr` and a `CString` that `GdkWindowAttr::title` points into.
242///
243/// ```ignore
244/// impl <'a> ToGlibPtr<'a, *mut ffi::GdkWindowAttr> for WindowAttr {
245///     type Storage = (Box<ffi::GdkWindowAttr>, Stash<'a, *const c_char, Option<String>>);
246///
247///     fn to_glib_none(&'a self) -> Stash<*mut ffi::GdkWindowAttr, WindowAttr> {
248///         let title = self.title.to_glib_none();
249///
250///         let mut attrs = Box::new(ffi::GdkWindowAttr {
251///             title: title.0,
252///             // ....
253///         });
254///
255///         Stash(&mut *attrs, (attrs, title))
256///     }
257/// }
258/// ```
259pub struct Stash<'a, P: Copy, T: ?Sized + ToGlibPtr<'a, P>>(
260    pub P,
261    pub <T as ToGlibPtr<'a, P>>::Storage,
262);
263
264pub struct StashMut<'a, P: Copy, T: ?Sized>(pub P, pub <T as ToGlibPtrMut<'a, P>>::Storage)
265where
266    T: ToGlibPtrMut<'a, P>;
267
268// rustdoc-stripper-ignore-next
269/// Wrapper around values representing borrowed C memory.
270///
271/// This is returned by `from_glib_borrow()` and ensures that the wrapped value
272/// is never dropped when going out of scope.
273///
274/// Borrowed values must never be passed by value or mutable reference to safe Rust code and must
275/// not leave the C scope in which they are valid.
276#[derive(Debug)]
277pub struct Borrowed<T>(mem::ManuallyDrop<T>);
278
279impl<T> Borrowed<T> {
280    // rustdoc-stripper-ignore-next
281    /// Creates a new borrowed value.
282    #[inline]
283    pub fn new(val: T) -> Self {
284        Self(mem::ManuallyDrop::new(val))
285    }
286
287    // rustdoc-stripper-ignore-next
288    /// Extracts the contained value.
289    ///
290    /// # Safety
291    ///
292    /// The returned value must never be dropped and instead has to be passed to `mem::forget()` or
293    /// be directly wrapped in `mem::ManuallyDrop` or another `Borrowed` wrapper.
294    #[inline]
295    pub unsafe fn into_inner(self) -> T {
296        mem::ManuallyDrop::into_inner(self.0)
297    }
298}
299
300impl<T> AsRef<T> for Borrowed<T> {
301    #[inline]
302    fn as_ref(&self) -> &T {
303        &self.0
304    }
305}
306
307impl<T> std::ops::Deref for Borrowed<T> {
308    type Target = T;
309
310    #[inline]
311    fn deref(&self) -> &T {
312        &self.0
313    }
314}
315
316// rustdoc-stripper-ignore-next
317/// Unsafe variant of the `From` trait.
318pub trait UnsafeFrom<T> {
319    // rustdoc-stripper-ignore-next
320    /// # Safety
321    ///
322    /// It is the responsibility of the caller to ensure *all* invariants of
323    /// the `T` hold before this is called, and that after conversion
324    /// to assume nothing other than the invariants of the output.  Implementors
325    /// of this must ensure that the invariants of the output type hold.
326    unsafe fn unsafe_from(t: T) -> Self;
327}
328
329// rustdoc-stripper-ignore-next
330/// Translate a simple type.
331pub trait IntoGlib {
332    type GlibType: Copy;
333
334    fn into_glib(self) -> Self::GlibType;
335}
336
337impl IntoGlib for bool {
338    type GlibType = ffi::gboolean;
339
340    #[inline]
341    fn into_glib(self) -> ffi::gboolean {
342        if self { ffi::GTRUE } else { ffi::GFALSE }
343    }
344}
345
346impl IntoGlib for char {
347    type GlibType = u32;
348
349    #[inline]
350    fn into_glib(self) -> u32 {
351        self as u32
352    }
353}
354
355unsafe impl TransparentType for char {
356    type GlibType = u32;
357}
358
359impl IntoGlib for Option<char> {
360    type GlibType = u32;
361
362    #[inline]
363    fn into_glib(self) -> u32 {
364        self.as_ref().map(|&c| c as u32).unwrap_or(0)
365    }
366}
367
368impl IntoGlib for Ordering {
369    type GlibType = i32;
370
371    #[inline]
372    fn into_glib(self) -> i32 {
373        match self {
374            Ordering::Less => -1,
375            Ordering::Equal => 0,
376            Ordering::Greater => 1,
377        }
378    }
379}
380
381impl<O, E, G> IntoGlib for Result<O, E>
382where
383    G: Copy,
384    O: IntoGlib<GlibType = G> + TryFromGlib<G, Error = E>,
385    E: IntoGlib<GlibType = G>,
386{
387    type GlibType = G;
388
389    #[inline]
390    fn into_glib(self) -> Self::GlibType {
391        match self {
392            Ok(ok) => ok.into_glib(),
393            Err(err) => err.into_glib(),
394        }
395    }
396}
397
398// rustdoc-stripper-ignore-next
399/// A Rust type `T` for which `Option<T>` translates to the same glib type as T.
400pub trait OptionIntoGlib: IntoGlib {
401    const GLIB_NONE: Self::GlibType;
402}
403
404impl<T: OptionIntoGlib> IntoGlib for Option<T> {
405    type GlibType = T::GlibType;
406
407    #[inline]
408    fn into_glib(self) -> Self::GlibType {
409        match self {
410            Some(t) => t.into_glib(),
411            None => T::GLIB_NONE,
412        }
413    }
414}
415
416// rustdoc-stripper-ignore-next
417/// Provides the default pointer type to be used in some container conversions.
418///
419/// It's `*mut c_char` for `String`, `*mut GtkButton` for `gtk::Button`, etc.
420pub trait GlibPtrDefault {
421    type GlibType: Ptr;
422}
423
424impl<T: ?Sized + GlibPtrDefault> GlibPtrDefault for &T {
425    type GlibType = <T as GlibPtrDefault>::GlibType;
426}
427
428// rustdoc-stripper-ignore-next
429/// Translate to a pointer.
430pub trait ToGlibPtr<'a, P: Copy> {
431    type Storage;
432
433    // rustdoc-stripper-ignore-next
434    /// Transfer: none.
435    ///
436    /// The pointer in the `Stash` is only valid for the lifetime of the `Stash`.
437    fn to_glib_none(&'a self) -> Stash<'a, P, Self>;
438
439    // rustdoc-stripper-ignore-next
440    /// Transfer: container.
441    ///
442    /// We transfer the container ownership to the foreign library retaining
443    /// the elements ownership.
444    fn to_glib_container(&'a self) -> Stash<'a, P, Self> {
445        unimplemented!();
446    }
447
448    // rustdoc-stripper-ignore-next
449    /// Transfer: full.
450    ///
451    /// We transfer the ownership to the foreign library.
452    fn to_glib_full(&self) -> P {
453        unimplemented!();
454    }
455}
456
457// rustdoc-stripper-ignore-next
458/// Translate to a pointer with a mutable borrow.
459pub trait ToGlibPtrMut<'a, P: Copy> {
460    type Storage;
461
462    // rustdoc-stripper-ignore-next
463    /// Transfer: none.
464    ///
465    /// The pointer in the `Stash` is only valid for the lifetime of the `Stash`.
466    #[allow(clippy::wrong_self_convention)]
467    fn to_glib_none_mut(&'a mut self) -> StashMut<'a, P, Self>;
468}
469
470impl<'a, P: Ptr, T: ToGlibPtr<'a, P>> ToGlibPtr<'a, P> for Option<T> {
471    type Storage = Option<<T as ToGlibPtr<'a, P>>::Storage>;
472
473    #[inline]
474    fn to_glib_none(&'a self) -> Stash<'a, P, Option<T>> {
475        self.as_ref()
476            .map_or(Stash(Ptr::from::<()>(ptr::null_mut()), None), |s| {
477                let s = s.to_glib_none();
478                Stash(s.0, Some(s.1))
479            })
480    }
481
482    #[inline]
483    fn to_glib_full(&self) -> P {
484        self.as_ref()
485            .map_or(Ptr::from::<()>(ptr::null_mut()), ToGlibPtr::to_glib_full)
486    }
487}
488
489impl<'a, 'opt: 'a, P: Ptr, T: ToGlibPtrMut<'a, P>> ToGlibPtrMut<'a, P> for Option<&'opt mut T> {
490    type Storage = Option<<T as ToGlibPtrMut<'a, P>>::Storage>;
491
492    #[inline]
493    fn to_glib_none_mut(&'a mut self) -> StashMut<'a, P, Option<&'opt mut T>> {
494        self.as_mut()
495            .map_or(StashMut(Ptr::from::<()>(ptr::null_mut()), None), |s| {
496                let s = s.to_glib_none_mut();
497                StashMut(s.0, Some(s.1))
498            })
499    }
500}
501
502impl<'a, P: Ptr, T: ?Sized + ToGlibPtr<'a, P>> ToGlibPtr<'a, P> for &'a T {
503    type Storage = <T as ToGlibPtr<'a, P>>::Storage;
504
505    #[inline]
506    fn to_glib_none(&'a self) -> Stash<'a, P, Self> {
507        let s = (*self).to_glib_none();
508        Stash(s.0, s.1)
509    }
510
511    #[inline]
512    fn to_glib_full(&self) -> P {
513        (*self).to_glib_full()
514    }
515}
516
517#[doc(hidden)]
518#[derive(Debug)]
519pub enum CowStash<B, O> {
520    Borrowed(B),
521    Owned(O),
522}
523
524impl<'a, P: Ptr, T> ToGlibPtr<'a, P> for Cow<'a, T>
525where
526    T: ToOwned + ?Sized + ToGlibPtr<'a, P>,
527    T::Owned: ToGlibPtr<'a, P>,
528{
529    type Storage = CowStash<T::Storage, <T::Owned as ToGlibPtr<'a, P>>::Storage>;
530
531    #[inline]
532    fn to_glib_none(&'a self) -> Stash<'a, P, Self> {
533        match self {
534            Cow::Borrowed(v) => {
535                let s = v.to_glib_none();
536                Stash(s.0, CowStash::Borrowed(s.1))
537            }
538            Cow::Owned(v) => {
539                let s = v.to_glib_none();
540                Stash(s.0, CowStash::Owned(s.1))
541            }
542        }
543    }
544
545    #[inline]
546    fn to_glib_full(&self) -> P {
547        match self {
548            Cow::Borrowed(v) => v.to_glib_full(),
549            Cow::Owned(v) => v.to_glib_full(),
550        }
551    }
552}
553
554impl<'a> ToGlibPtr<'a, *const c_char> for str {
555    type Storage = Cow<'static, [u8]>;
556
557    fn to_glib_none(&'a self) -> Stash<'a, *const c_char, Self> {
558        static EMPTY_STRING: &[u8] = &[0];
559
560        let bytes = if self.is_empty() {
561            Cow::Borrowed(EMPTY_STRING)
562        } else {
563            if cfg!(debug_assertions) {
564                crate::GStr::check_interior_nuls(self).unwrap();
565            }
566            let mut bytes = Vec::with_capacity(self.len() + 1);
567            unsafe {
568                ptr::copy_nonoverlapping(self.as_ptr(), bytes.as_mut_ptr(), self.len());
569                bytes.as_mut_ptr().add(self.len()).write(0);
570                bytes.set_len(self.len() + 1);
571            }
572            Cow::Owned(bytes)
573        };
574        Stash(bytes.as_ptr() as *const c_char, bytes)
575    }
576
577    #[inline]
578    fn to_glib_full(&self) -> *const c_char {
579        if cfg!(debug_assertions) {
580            crate::GStr::check_interior_nuls(self).unwrap();
581        }
582        unsafe {
583            ffi::g_strndup(self.as_ptr() as *const c_char, self.len() as size_t) as *const c_char
584        }
585    }
586}
587
588impl<'a> ToGlibPtr<'a, *mut c_char> for str {
589    type Storage = Cow<'static, [u8]>;
590
591    #[inline]
592    fn to_glib_none(&'a self) -> Stash<'a, *mut c_char, Self> {
593        let s = ToGlibPtr::<*const c_char>::to_glib_none(self);
594        Stash(s.0 as *mut _, s.1)
595    }
596
597    #[inline]
598    fn to_glib_full(&self) -> *mut c_char {
599        ToGlibPtr::<*const c_char>::to_glib_full(self) as *mut _
600    }
601}
602
603impl<'a> ToGlibPtr<'a, *const c_char> for String {
604    type Storage = Cow<'static, [u8]>;
605
606    #[inline]
607    fn to_glib_none(&self) -> Stash<'a, *const c_char, String> {
608        let s = ToGlibPtr::to_glib_none(self.as_str());
609        Stash(s.0, s.1)
610    }
611
612    #[inline]
613    fn to_glib_full(&self) -> *const c_char {
614        ToGlibPtr::to_glib_full(self.as_str())
615    }
616}
617
618impl<'a> ToGlibPtr<'a, *mut c_char> for String {
619    type Storage = Cow<'static, [u8]>;
620
621    #[inline]
622    fn to_glib_none(&self) -> Stash<'a, *mut c_char, String> {
623        let s = ToGlibPtr::to_glib_none(self.as_str());
624        Stash(s.0, s.1)
625    }
626
627    #[inline]
628    fn to_glib_full(&self) -> *mut c_char {
629        ToGlibPtr::to_glib_full(self.as_str())
630    }
631}
632
633impl<'a> ToGlibPtr<'a, *const c_char> for CStr {
634    type Storage = PhantomData<&'a Self>;
635
636    #[inline]
637    fn to_glib_none(&'a self) -> Stash<'a, *const c_char, Self> {
638        Stash(self.as_ptr(), PhantomData)
639    }
640
641    #[inline]
642    fn to_glib_full(&self) -> *const c_char {
643        unsafe {
644            ffi::g_strndup(
645                self.as_ptr() as *const c_char,
646                self.to_bytes().len() as size_t,
647            ) as *const c_char
648        }
649    }
650}
651
652impl<'a> ToGlibPtr<'a, *mut c_char> for CStr {
653    type Storage = PhantomData<&'a Self>;
654
655    #[inline]
656    fn to_glib_none(&'a self) -> Stash<'a, *mut c_char, Self> {
657        Stash(self.as_ptr() as *mut c_char, PhantomData)
658    }
659
660    #[inline]
661    fn to_glib_full(&self) -> *mut c_char {
662        unsafe {
663            ffi::g_strndup(
664                self.as_ptr() as *const c_char,
665                self.to_bytes().len() as size_t,
666            ) as *mut c_char
667        }
668    }
669}
670
671impl<'a> ToGlibPtr<'a, *const c_char> for CString {
672    type Storage = PhantomData<&'a Self>;
673
674    #[inline]
675    fn to_glib_none(&'a self) -> Stash<'a, *const c_char, Self> {
676        Stash(self.as_ptr(), PhantomData)
677    }
678
679    #[inline]
680    fn to_glib_full(&self) -> *const c_char {
681        unsafe {
682            ffi::g_strndup(
683                self.as_ptr() as *const c_char,
684                self.as_bytes().len() as size_t,
685            ) as *const c_char
686        }
687    }
688}
689
690impl<'a> ToGlibPtr<'a, *mut c_char> for CString {
691    type Storage = PhantomData<&'a Self>;
692
693    #[inline]
694    fn to_glib_none(&'a self) -> Stash<'a, *mut c_char, Self> {
695        Stash(self.as_ptr() as *mut c_char, PhantomData)
696    }
697
698    #[inline]
699    fn to_glib_full(&self) -> *mut c_char {
700        unsafe {
701            ffi::g_strndup(
702                self.as_ptr() as *const c_char,
703                self.as_bytes().len() as size_t,
704            ) as *mut c_char
705        }
706    }
707}
708
709// rustdoc-stripper-ignore-next
710/// Translate to a pointer.
711pub trait IntoGlibPtr<P: Ptr> {
712    // rustdoc-stripper-ignore-next
713    /// Transfer: full.
714    #[allow(clippy::wrong_self_convention)]
715    fn into_glib_ptr(self) -> P;
716}
717
718impl<P: Ptr, T: IntoGlibPtr<P>> IntoGlibPtr<P> for Option<T> {
719    #[inline]
720    fn into_glib_ptr(self) -> P {
721        self.map_or(Ptr::from::<()>(ptr::null_mut()), |s| {
722            IntoGlibPtr::into_glib_ptr(s)
723        })
724    }
725}
726
727impl GlibPtrDefault for str {
728    type GlibType = *mut c_char;
729}
730
731impl GlibPtrDefault for String {
732    type GlibType = *mut c_char;
733}
734
735#[cfg(not(windows))]
736pub(crate) fn path_to_c(path: &Path) -> CString {
737    // GLib paths on UNIX are always in the local encoding, just like in Rust
738    //
739    // Paths on UNIX must not contain NUL bytes, in which case the conversion
740    // to a CString would fail. The only thing we can do then is to panic, as passing
741    // NULL or the empty string to GLib would cause undefined behaviour.
742    CString::new(path.as_os_str().as_bytes()).expect("Invalid path with NUL bytes")
743}
744
745#[cfg(windows)]
746pub(crate) fn path_to_c(path: &Path) -> CString {
747    // GLib paths are always UTF-8 strings on Windows, while in Rust they are
748    // WTF-8. As such, we need to convert to a UTF-8 string. This conversion can
749    // fail, see https://simonsapin.github.io/wtf-8/#converting-wtf-8-utf-8
750    //
751    // It's not clear what we're supposed to do if it fails: the path is not
752    // representable in UTF-8 and thus can't possibly be passed to GLib.
753    // Passing NULL or the empty string to GLib can lead to undefined behaviour, so
754    // the only safe option seems to be to simply panic here.
755    let path_str = path
756        .to_str()
757        .expect("Path can't be represented as UTF-8")
758        .to_owned();
759
760    // On Windows, paths can have \\?\ prepended for long-path support. See
761    // MSDN documentation about CreateFile
762    //
763    // We have to get rid of this and let GLib take care of all these
764    // weirdnesses later
765    if path_str.starts_with("\\\\?\\") {
766        CString::new(path_str[4..].as_bytes())
767    } else {
768        CString::new(path_str.as_bytes())
769    }
770    .expect("Invalid path with NUL bytes")
771}
772
773#[cfg(not(windows))]
774pub(crate) fn os_str_to_c(s: &OsStr) -> CString {
775    // GLib OS string (environment strings) on UNIX are always in the local encoding,
776    // just like in Rust
777    //
778    // OS string on UNIX must not contain NUL bytes, in which case the conversion
779    // to a CString would fail. The only thing we can do then is to panic, as passing
780    // NULL or the empty string to GLib would cause undefined behaviour.
781    CString::new(s.as_bytes()).expect("Invalid OS String with NUL bytes")
782}
783
784#[cfg(windows)]
785pub(crate) fn os_str_to_c(s: &OsStr) -> CString {
786    // GLib OS string (environment strings) are always UTF-8 strings on Windows,
787    // while in Rust they are WTF-8. As such, we need to convert to a UTF-8 string.
788    // This conversion can fail, see https://simonsapin.github.io/wtf-8/#converting-wtf-8-utf-8
789    //
790    // It's not clear what we're supposed to do if it fails: the OS string is not
791    // representable in UTF-8 and thus can't possibly be passed to GLib.
792    // Passing NULL or the empty string to GLib can lead to undefined behaviour, so
793    // the only safe option seems to be to simply panic here.
794    let os_str = s
795        .to_str()
796        .expect("OS String can't be represented as UTF-8")
797        .to_owned();
798
799    CString::new(os_str.as_bytes()).expect("Invalid OS string with NUL bytes")
800}
801
802impl<'a> ToGlibPtr<'a, *const c_char> for Path {
803    type Storage = CString;
804
805    #[inline]
806    fn to_glib_none(&'a self) -> Stash<'a, *const c_char, Self> {
807        let tmp = path_to_c(self);
808        Stash(tmp.as_ptr(), tmp)
809    }
810}
811
812impl<'a> ToGlibPtr<'a, *mut c_char> for Path {
813    type Storage = CString;
814
815    #[inline]
816    fn to_glib_none(&'a self) -> Stash<'a, *mut c_char, Self> {
817        let tmp = path_to_c(self);
818        Stash(tmp.as_ptr() as *mut c_char, tmp)
819    }
820
821    #[inline]
822    fn to_glib_full(&self) -> *mut c_char {
823        let tmp = path_to_c(self);
824        unsafe { ffi::g_strdup(tmp.as_ptr()) }
825    }
826}
827
828impl<'a> ToGlibPtr<'a, *const c_char> for PathBuf {
829    type Storage = CString;
830
831    #[inline]
832    fn to_glib_none(&'a self) -> Stash<'a, *const c_char, Self> {
833        let tmp = path_to_c(self);
834        Stash(tmp.as_ptr(), tmp)
835    }
836}
837
838impl<'a> ToGlibPtr<'a, *mut c_char> for PathBuf {
839    type Storage = CString;
840
841    #[inline]
842    fn to_glib_none(&'a self) -> Stash<'a, *mut c_char, Self> {
843        let tmp = path_to_c(self);
844        Stash(tmp.as_ptr() as *mut c_char, tmp)
845    }
846
847    #[inline]
848    fn to_glib_full(&self) -> *mut c_char {
849        let tmp = path_to_c(self);
850        unsafe { ffi::g_strdup(tmp.as_ptr()) }
851    }
852}
853
854impl GlibPtrDefault for Path {
855    type GlibType = *mut c_char;
856}
857
858impl GlibPtrDefault for PathBuf {
859    type GlibType = *mut c_char;
860}
861
862impl<'a> ToGlibPtr<'a, *const c_char> for OsStr {
863    type Storage = CString;
864
865    #[inline]
866    fn to_glib_none(&'a self) -> Stash<'a, *const c_char, Self> {
867        let tmp = os_str_to_c(self);
868        Stash(tmp.as_ptr(), tmp)
869    }
870}
871
872impl<'a> ToGlibPtr<'a, *mut c_char> for OsStr {
873    type Storage = CString;
874
875    #[inline]
876    fn to_glib_none(&'a self) -> Stash<'a, *mut c_char, Self> {
877        let tmp = os_str_to_c(self);
878        Stash(tmp.as_ptr() as *mut c_char, tmp)
879    }
880
881    #[inline]
882    fn to_glib_full(&self) -> *mut c_char {
883        let tmp = os_str_to_c(self);
884        unsafe { ffi::g_strdup(tmp.as_ptr()) }
885    }
886}
887
888impl<'a> ToGlibPtr<'a, *const c_char> for OsString {
889    type Storage = CString;
890
891    #[inline]
892    fn to_glib_none(&'a self) -> Stash<'a, *const c_char, Self> {
893        let tmp = os_str_to_c(self);
894        Stash(tmp.as_ptr(), tmp)
895    }
896}
897
898impl<'a> ToGlibPtr<'a, *mut c_char> for OsString {
899    type Storage = CString;
900
901    #[inline]
902    fn to_glib_none(&'a self) -> Stash<'a, *mut c_char, Self> {
903        let tmp = os_str_to_c(self);
904        Stash(tmp.as_ptr() as *mut c_char, tmp)
905    }
906
907    #[inline]
908    fn to_glib_full(&self) -> *mut c_char {
909        let tmp = os_str_to_c(self);
910        unsafe { ffi::g_strdup(tmp.as_ptr()) }
911    }
912}
913
914impl GlibPtrDefault for OsStr {
915    type GlibType = *mut c_char;
916}
917
918impl GlibPtrDefault for OsString {
919    type GlibType = *mut c_char;
920}
921
922pub trait ToGlibContainerFromSlice<'a, P>
923where
924    Self: Sized,
925{
926    type Storage;
927
928    #[allow(clippy::wrong_self_convention)]
929    fn to_glib_none_from_slice(t: &'a [Self]) -> (P, Self::Storage);
930    #[allow(clippy::wrong_self_convention)]
931    fn to_glib_container_from_slice(t: &'a [Self]) -> (P, Self::Storage);
932    #[allow(clippy::wrong_self_convention)]
933    fn to_glib_full_from_slice(t: &[Self]) -> P;
934}
935
936macro_rules! impl_to_glib_container_from_slice_fundamental {
937    ($name:ty) => {
938        impl<'a> ToGlibContainerFromSlice<'a, *mut $name> for $name {
939            type Storage = std::marker::PhantomData<&'a [$name]>;
940
941            #[inline]
942            fn to_glib_none_from_slice(t: &'a [$name]) -> (*mut $name, Self::Storage) {
943                (t.as_ptr() as *mut $name, std::marker::PhantomData)
944            }
945
946            #[inline]
947            fn to_glib_container_from_slice(t: &'a [$name]) -> (*mut $name, Self::Storage) {
948                (
949                    ToGlibContainerFromSlice::to_glib_full_from_slice(t),
950                    std::marker::PhantomData,
951                )
952            }
953
954            #[inline]
955            fn to_glib_full_from_slice(t: &[$name]) -> *mut $name {
956                if t.len() == 0 {
957                    return ptr::null_mut();
958                }
959
960                unsafe {
961                    let res = ffi::g_malloc(mem::size_of_val(t)) as *mut $name;
962                    ptr::copy_nonoverlapping(t.as_ptr(), res, t.len());
963                    res
964                }
965            }
966        }
967    };
968}
969
970impl_to_glib_container_from_slice_fundamental!(u8);
971impl_to_glib_container_from_slice_fundamental!(i8);
972impl_to_glib_container_from_slice_fundamental!(u16);
973impl_to_glib_container_from_slice_fundamental!(i16);
974impl_to_glib_container_from_slice_fundamental!(u32);
975impl_to_glib_container_from_slice_fundamental!(i32);
976impl_to_glib_container_from_slice_fundamental!(u64);
977impl_to_glib_container_from_slice_fundamental!(i64);
978impl_to_glib_container_from_slice_fundamental!(f32);
979impl_to_glib_container_from_slice_fundamental!(f64);
980
981macro_rules! impl_to_glib_container_from_slice_string {
982    ($name:ty, $ffi_name:ty) => {
983        impl<'a> ToGlibContainerFromSlice<'a, *mut $ffi_name> for $name {
984            type Storage = (Vec<Stash<'a, $ffi_name, $name>>, Option<Vec<$ffi_name>>);
985
986            fn to_glib_none_from_slice(t: &'a [$name]) -> (*mut $ffi_name, Self::Storage) {
987                let v: Vec<_> = t.iter().map(ToGlibPtr::to_glib_none).collect();
988                let mut v_ptr: Vec<_> = v.iter().map(|s| s.0).collect();
989                v_ptr.push(ptr::null_mut() as $ffi_name);
990
991                (v_ptr.as_ptr() as *mut $ffi_name, (v, Some(v_ptr)))
992            }
993
994            fn to_glib_container_from_slice(t: &'a [$name]) -> (*mut $ffi_name, Self::Storage) {
995                let v: Vec<_> = t.iter().map(ToGlibPtr::to_glib_none).collect();
996
997                let v_ptr = unsafe {
998                    let v_ptr = ffi::g_malloc(mem::size_of::<$ffi_name>() * (t.len() + 1))
999                        as *mut $ffi_name;
1000
1001                    for (i, s) in v.iter().enumerate() {
1002                        ptr::write(v_ptr.add(i), s.0);
1003                    }
1004                    ptr::write(v_ptr.add(t.len()), ptr::null_mut());
1005
1006                    v_ptr
1007                };
1008
1009                (v_ptr, (v, None))
1010            }
1011
1012            fn to_glib_full_from_slice(t: &[$name]) -> *mut $ffi_name {
1013                unsafe {
1014                    let v_ptr = ffi::g_malloc(mem::size_of::<$ffi_name>() * (t.len() + 1))
1015                        as *mut $ffi_name;
1016
1017                    for (i, s) in t.iter().enumerate() {
1018                        ptr::write(v_ptr.add(i), s.to_glib_full());
1019                    }
1020                    ptr::write(v_ptr.add(t.len()), ptr::null_mut());
1021
1022                    v_ptr
1023                }
1024            }
1025        }
1026        impl<'a> ToGlibContainerFromSlice<'a, *const $ffi_name> for $name {
1027            type Storage = (Vec<Stash<'a, $ffi_name, $name>>, Option<Vec<$ffi_name>>);
1028
1029            fn to_glib_none_from_slice(t: &'a [$name]) -> (*const $ffi_name, Self::Storage) {
1030                let v: Vec<_> = t.iter().map(ToGlibPtr::to_glib_none).collect();
1031                let mut v_ptr: Vec<_> = v.iter().map(|s| s.0).collect();
1032                v_ptr.push(ptr::null_mut() as $ffi_name);
1033
1034                (v_ptr.as_ptr() as *const $ffi_name, (v, Some(v_ptr)))
1035            }
1036
1037            fn to_glib_container_from_slice(t: &'a [$name]) -> (*const $ffi_name, Self::Storage) {
1038                let v: Vec<_> = t.iter().map(ToGlibPtr::to_glib_none).collect();
1039
1040                let v_ptr = unsafe {
1041                    let v_ptr = ffi::g_malloc(mem::size_of::<$ffi_name>() * (t.len() + 1))
1042                        as *mut $ffi_name;
1043
1044                    for (i, s) in v.iter().enumerate() {
1045                        ptr::write(v_ptr.add(i), s.0);
1046                    }
1047                    ptr::write(v_ptr.add(t.len()), ptr::null_mut());
1048
1049                    v_ptr as *const $ffi_name
1050                };
1051
1052                (v_ptr, (v, None))
1053            }
1054
1055            fn to_glib_full_from_slice(t: &[$name]) -> *const $ffi_name {
1056                unsafe {
1057                    let v_ptr = ffi::g_malloc(mem::size_of::<$ffi_name>() * (t.len() + 1))
1058                        as *mut $ffi_name;
1059
1060                    for (i, s) in t.iter().enumerate() {
1061                        ptr::write(v_ptr.add(i), s.to_glib_full());
1062                    }
1063                    ptr::write(v_ptr.add(t.len()), ptr::null_mut());
1064
1065                    v_ptr as *const $ffi_name
1066                }
1067            }
1068        }
1069    };
1070}
1071
1072impl_to_glib_container_from_slice_string!(&'a str, *mut c_char);
1073impl_to_glib_container_from_slice_string!(&'a str, *const c_char);
1074impl_to_glib_container_from_slice_string!(String, *mut c_char);
1075impl_to_glib_container_from_slice_string!(String, *const c_char);
1076impl_to_glib_container_from_slice_string!(&'a Path, *mut c_char);
1077impl_to_glib_container_from_slice_string!(&'a Path, *const c_char);
1078impl_to_glib_container_from_slice_string!(PathBuf, *mut c_char);
1079impl_to_glib_container_from_slice_string!(PathBuf, *const c_char);
1080impl_to_glib_container_from_slice_string!(&'a OsStr, *mut c_char);
1081impl_to_glib_container_from_slice_string!(&'a OsStr, *const c_char);
1082impl_to_glib_container_from_slice_string!(OsString, *mut c_char);
1083impl_to_glib_container_from_slice_string!(OsString, *const c_char);
1084impl_to_glib_container_from_slice_string!(&'a CStr, *mut c_char);
1085impl_to_glib_container_from_slice_string!(&'a CStr, *const c_char);
1086impl_to_glib_container_from_slice_string!(CString, *mut c_char);
1087impl_to_glib_container_from_slice_string!(CString, *const c_char);
1088impl_to_glib_container_from_slice_string!(crate::GString, *mut c_char);
1089impl_to_glib_container_from_slice_string!(crate::GString, *const c_char);
1090
1091impl<'a, T> ToGlibContainerFromSlice<'a, *mut ffi::GList> for T
1092where
1093    T: GlibPtrDefault + ToGlibPtr<'a, <T as GlibPtrDefault>::GlibType>,
1094{
1095    type Storage = (
1096        Option<List>,
1097        Vec<Stash<'a, <T as GlibPtrDefault>::GlibType, T>>,
1098    );
1099
1100    #[inline]
1101    fn to_glib_none_from_slice(t: &'a [T]) -> (*mut ffi::GList, Self::Storage) {
1102        let stash_vec: Vec<_> = t.iter().rev().map(ToGlibPtr::to_glib_none).collect();
1103        let mut list: *mut ffi::GList = ptr::null_mut();
1104        unsafe {
1105            for stash in &stash_vec {
1106                list = ffi::g_list_prepend(list, Ptr::to(stash.0));
1107            }
1108        }
1109        let stash = (ptr::NonNull::new(list).map(List), stash_vec);
1110        (list, stash)
1111    }
1112
1113    #[inline]
1114    fn to_glib_container_from_slice(t: &'a [T]) -> (*mut ffi::GList, Self::Storage) {
1115        let stash_vec: Vec<_> = t.iter().rev().map(ToGlibPtr::to_glib_none).collect();
1116        let mut list: *mut ffi::GList = ptr::null_mut();
1117        unsafe {
1118            for stash in &stash_vec {
1119                list = ffi::g_list_prepend(list, Ptr::to(stash.0));
1120            }
1121        }
1122        (list, (None, stash_vec))
1123    }
1124
1125    #[inline]
1126    fn to_glib_full_from_slice(t: &[T]) -> *mut ffi::GList {
1127        let mut list: *mut ffi::GList = ptr::null_mut();
1128        unsafe {
1129            for ptr in t.iter().rev().map(ToGlibPtr::to_glib_full) {
1130                list = ffi::g_list_prepend(list, Ptr::to(ptr));
1131            }
1132        }
1133        list
1134    }
1135}
1136
1137impl<'a, T> ToGlibContainerFromSlice<'a, *const ffi::GList> for T
1138where
1139    T: GlibPtrDefault + ToGlibPtr<'a, <T as GlibPtrDefault>::GlibType>,
1140{
1141    type Storage = (
1142        Option<List>,
1143        Vec<Stash<'a, <T as GlibPtrDefault>::GlibType, T>>,
1144    );
1145
1146    #[inline]
1147    fn to_glib_none_from_slice(t: &'a [T]) -> (*const ffi::GList, Self::Storage) {
1148        let (list, stash) = ToGlibContainerFromSlice::<*mut ffi::GList>::to_glib_none_from_slice(t);
1149        (list as *const ffi::GList, stash)
1150    }
1151
1152    #[inline]
1153    fn to_glib_container_from_slice(_t: &'a [T]) -> (*const ffi::GList, Self::Storage) {
1154        unimplemented!()
1155    }
1156
1157    #[inline]
1158    fn to_glib_full_from_slice(_t: &[T]) -> *const ffi::GList {
1159        unimplemented!()
1160    }
1161}
1162
1163#[doc(alias = "GList")]
1164pub struct List(ptr::NonNull<ffi::GList>);
1165
1166impl Drop for List {
1167    #[inline]
1168    fn drop(&mut self) {
1169        unsafe { ffi::g_list_free(self.0.as_ptr()) }
1170    }
1171}
1172
1173impl<'a, T> ToGlibContainerFromSlice<'a, *mut ffi::GSList> for &'a T
1174where
1175    T: GlibPtrDefault + ToGlibPtr<'a, <T as GlibPtrDefault>::GlibType>,
1176{
1177    type Storage = (
1178        Option<SList>,
1179        Vec<Stash<'a, <T as GlibPtrDefault>::GlibType, &'a T>>,
1180    );
1181
1182    #[inline]
1183    fn to_glib_none_from_slice(t: &'a [&'a T]) -> (*mut ffi::GSList, Self::Storage) {
1184        let stash_vec: Vec<_> = t.iter().rev().map(ToGlibPtr::to_glib_none).collect();
1185        let mut list: *mut ffi::GSList = ptr::null_mut();
1186        unsafe {
1187            for stash in &stash_vec {
1188                list = ffi::g_slist_prepend(list, Ptr::to(stash.0));
1189            }
1190        }
1191
1192        let stash = (ptr::NonNull::new(list).map(SList), stash_vec);
1193        (list, stash)
1194    }
1195
1196    #[inline]
1197    fn to_glib_container_from_slice(t: &'a [&'a T]) -> (*mut ffi::GSList, Self::Storage) {
1198        let stash_vec: Vec<_> = t.iter().rev().map(ToGlibPtr::to_glib_none).collect();
1199        let mut list: *mut ffi::GSList = ptr::null_mut();
1200        unsafe {
1201            for stash in &stash_vec {
1202                list = ffi::g_slist_prepend(list, Ptr::to(stash.0));
1203            }
1204        }
1205        (list, (None, stash_vec))
1206    }
1207
1208    #[inline]
1209    fn to_glib_full_from_slice(t: &[&'a T]) -> *mut ffi::GSList {
1210        let mut list: *mut ffi::GSList = ptr::null_mut();
1211        unsafe {
1212            for ptr in t.iter().rev().map(ToGlibPtr::to_glib_full) {
1213                list = ffi::g_slist_prepend(list, Ptr::to(ptr));
1214            }
1215        }
1216        list
1217    }
1218}
1219
1220impl<'a, T> ToGlibContainerFromSlice<'a, *const ffi::GSList> for &'a T
1221where
1222    T: GlibPtrDefault + ToGlibPtr<'a, <T as GlibPtrDefault>::GlibType>,
1223{
1224    type Storage = (
1225        Option<SList>,
1226        Vec<Stash<'a, <T as GlibPtrDefault>::GlibType, &'a T>>,
1227    );
1228
1229    #[inline]
1230    fn to_glib_none_from_slice(t: &'a [&'a T]) -> (*const ffi::GSList, Self::Storage) {
1231        let (list, stash) =
1232            ToGlibContainerFromSlice::<*mut ffi::GSList>::to_glib_none_from_slice(t);
1233        (list as *const ffi::GSList, stash)
1234    }
1235
1236    #[inline]
1237    fn to_glib_container_from_slice(_t: &'a [&'a T]) -> (*const ffi::GSList, Self::Storage) {
1238        unimplemented!()
1239    }
1240
1241    #[inline]
1242    fn to_glib_full_from_slice(_t: &[&'a T]) -> *const ffi::GSList {
1243        unimplemented!()
1244    }
1245}
1246
1247#[doc(alias = "GSList")]
1248pub struct SList(ptr::NonNull<ffi::GSList>);
1249
1250impl Drop for SList {
1251    #[inline]
1252    fn drop(&mut self) {
1253        unsafe { ffi::g_slist_free(self.0.as_ptr()) }
1254    }
1255}
1256
1257impl<'a, P: Ptr, T: ToGlibContainerFromSlice<'a, P>> ToGlibPtr<'a, P> for [T] {
1258    type Storage = T::Storage;
1259
1260    #[inline]
1261    fn to_glib_none(&'a self) -> Stash<'a, P, Self> {
1262        let result = ToGlibContainerFromSlice::to_glib_none_from_slice(self);
1263        Stash(result.0, result.1)
1264    }
1265
1266    #[inline]
1267    fn to_glib_container(&'a self) -> Stash<'a, P, Self> {
1268        let result = ToGlibContainerFromSlice::to_glib_container_from_slice(self);
1269        Stash(result.0, result.1)
1270    }
1271
1272    #[inline]
1273    fn to_glib_full(&self) -> P {
1274        ToGlibContainerFromSlice::to_glib_full_from_slice(self)
1275    }
1276}
1277
1278#[allow(clippy::implicit_hasher)]
1279impl<'a> ToGlibPtr<'a, *mut ffi::GHashTable> for HashMap<String, String> {
1280    type Storage = HashTable;
1281
1282    #[inline]
1283    fn to_glib_none(&self) -> Stash<'a, *mut ffi::GHashTable, Self> {
1284        let ptr = self.to_glib_full();
1285        Stash(ptr, HashTable(unsafe { ptr::NonNull::new_unchecked(ptr) }))
1286    }
1287
1288    #[inline]
1289    fn to_glib_full(&self) -> *mut ffi::GHashTable {
1290        unsafe {
1291            let ptr = ffi::g_hash_table_new_full(
1292                Some(ffi::g_str_hash),
1293                Some(ffi::g_str_equal),
1294                Some(ffi::g_free),
1295                Some(ffi::g_free),
1296            );
1297            for (k, v) in self {
1298                let k: *mut c_char = k.to_glib_full();
1299                let v: *mut c_char = v.to_glib_full();
1300                ffi::g_hash_table_insert(ptr, k as *mut _, v as *mut _);
1301            }
1302            ptr
1303        }
1304    }
1305}
1306
1307#[doc(alias = "GHashTable")]
1308pub struct HashTable(ptr::NonNull<ffi::GHashTable>);
1309
1310impl Drop for HashTable {
1311    #[inline]
1312    fn drop(&mut self) {
1313        unsafe { ffi::g_hash_table_unref(self.0.as_ptr()) }
1314    }
1315}
1316
1317#[doc(alias = "GPtrArray")]
1318pub struct PtrArray(ptr::NonNull<ffi::GPtrArray>);
1319
1320impl Drop for PtrArray {
1321    #[inline]
1322    fn drop(&mut self) {
1323        unsafe {
1324            ffi::g_ptr_array_unref(self.0.as_ptr());
1325        }
1326    }
1327}
1328
1329impl<'a, T> ToGlibContainerFromSlice<'a, *mut ffi::GPtrArray> for T
1330where
1331    T: GlibPtrDefault + ToGlibPtr<'a, <T as GlibPtrDefault>::GlibType>,
1332{
1333    type Storage = (
1334        Option<PtrArray>,
1335        Vec<Stash<'a, <T as GlibPtrDefault>::GlibType, T>>,
1336    );
1337
1338    #[inline]
1339    fn to_glib_none_from_slice(t: &'a [T]) -> (*mut ffi::GPtrArray, Self::Storage) {
1340        let stash_vec: Vec<_> = t.iter().map(ToGlibPtr::to_glib_none).collect();
1341        let arr = unsafe { ffi::g_ptr_array_sized_new(t.len() as _) };
1342        unsafe {
1343            for stash in &stash_vec {
1344                ffi::g_ptr_array_add(arr, Ptr::to(stash.0));
1345            }
1346        }
1347
1348        (
1349            arr,
1350            (
1351                Some(PtrArray(unsafe { ptr::NonNull::new_unchecked(arr) })),
1352                stash_vec,
1353            ),
1354        )
1355    }
1356
1357    #[inline]
1358    fn to_glib_container_from_slice(t: &'a [T]) -> (*mut ffi::GPtrArray, Self::Storage) {
1359        let stash_vec: Vec<_> = t.iter().map(ToGlibPtr::to_glib_none).collect();
1360        let arr = unsafe { ffi::g_ptr_array_sized_new(t.len() as _) };
1361        unsafe {
1362            for stash in &stash_vec {
1363                ffi::g_ptr_array_add(arr, Ptr::to(stash.0));
1364            }
1365        }
1366        (arr, (None, stash_vec))
1367    }
1368
1369    #[inline]
1370    fn to_glib_full_from_slice(t: &[T]) -> *mut ffi::GPtrArray {
1371        let arr = unsafe { ffi::g_ptr_array_sized_new(t.len() as _) };
1372        unsafe {
1373            for ptr in t.iter().map(ToGlibPtr::to_glib_full) {
1374                ffi::g_ptr_array_add(arr, Ptr::to(ptr));
1375            }
1376        }
1377        arr
1378    }
1379}
1380
1381impl<'a, T> ToGlibContainerFromSlice<'a, *const ffi::GPtrArray> for T
1382where
1383    T: GlibPtrDefault + ToGlibPtr<'a, <T as GlibPtrDefault>::GlibType>,
1384{
1385    type Storage = (
1386        Option<PtrArray>,
1387        Vec<Stash<'a, <T as GlibPtrDefault>::GlibType, T>>,
1388    );
1389
1390    #[inline]
1391    fn to_glib_none_from_slice(t: &'a [T]) -> (*const ffi::GPtrArray, Self::Storage) {
1392        let (arr, stash) =
1393            ToGlibContainerFromSlice::<*mut ffi::GPtrArray>::to_glib_none_from_slice(t);
1394        (arr as *const ffi::GPtrArray, stash)
1395    }
1396
1397    #[inline]
1398    fn to_glib_container_from_slice(_t: &'a [T]) -> (*const ffi::GPtrArray, Self::Storage) {
1399        unimplemented!()
1400    }
1401
1402    #[inline]
1403    fn to_glib_full_from_slice(_t: &[T]) -> *const ffi::GPtrArray {
1404        unimplemented!()
1405    }
1406}
1407
1408// rustdoc-stripper-ignore-next
1409/// Translate a simple type.
1410pub trait FromGlib<G: Copy>: Sized {
1411    unsafe fn from_glib(val: G) -> Self;
1412}
1413
1414// rustdoc-stripper-ignore-next
1415/// Translate a simple type.
1416#[inline]
1417pub unsafe fn from_glib<G: Copy, T: FromGlib<G>>(val: G) -> T {
1418    unsafe { FromGlib::from_glib(val) }
1419}
1420
1421impl FromGlib<ffi::gboolean> for bool {
1422    #[inline]
1423    unsafe fn from_glib(val: ffi::gboolean) -> Self {
1424        val != ffi::GFALSE
1425    }
1426}
1427
1428impl FromGlib<i32> for Ordering {
1429    #[inline]
1430    unsafe fn from_glib(val: i32) -> Self {
1431        val.cmp(&0)
1432    }
1433}
1434
1435// rustdoc-stripper-ignore-next
1436/// Translate from a Glib type which can result in an undefined and/or invalid value.
1437pub trait TryFromGlib<G: Copy>: Sized {
1438    type Error;
1439    unsafe fn try_from_glib(val: G) -> Result<Self, Self::Error>;
1440}
1441
1442// rustdoc-stripper-ignore-next
1443/// Translate from a Glib type which can result in an undefined and/or invalid value.
1444#[inline]
1445pub unsafe fn try_from_glib<G: Copy, T: TryFromGlib<G>>(
1446    val: G,
1447) -> Result<T, <T as TryFromGlib<G>>::Error> {
1448    unsafe { TryFromGlib::try_from_glib(val) }
1449}
1450
1451// rustdoc-stripper-ignore-next
1452/// Error type for [`TryFromGlib`] when the Glib value is None.
1453#[derive(Debug, PartialEq, Eq)]
1454pub struct GlibNoneError;
1455
1456impl fmt::Display for GlibNoneError {
1457    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
1458        write!(fmt, "glib value is None")
1459    }
1460}
1461
1462impl std::error::Error for GlibNoneError {}
1463
1464impl<G: Copy, T: TryFromGlib<G, Error = GlibNoneError>> FromGlib<G> for Option<T> {
1465    #[inline]
1466    unsafe fn from_glib(val: G) -> Self {
1467        unsafe { T::try_from_glib(val).ok() }
1468    }
1469}
1470
1471// rustdoc-stripper-ignore-next
1472/// Error type for [`TryFromGlib`] when the Glib value can be None or invalid.
1473#[derive(Debug, Eq, PartialEq)]
1474pub enum GlibNoneOrInvalidError<I: Error> {
1475    Invalid(I),
1476    None,
1477}
1478
1479impl<I: Error> GlibNoneOrInvalidError<I> {
1480    // rustdoc-stripper-ignore-next
1481    /// Builds the `None` variant.
1482    #[inline]
1483    pub fn none() -> Self {
1484        Self::None
1485    }
1486
1487    // rustdoc-stripper-ignore-next
1488    /// Returns `true` if `self` is the `None` variant.
1489    #[inline]
1490    pub fn is_none(&self) -> bool {
1491        matches!(self, Self::None)
1492    }
1493
1494    // rustdoc-stripper-ignore-next
1495    /// Returns `true` if `self` is the `Invalid` variant.
1496    #[inline]
1497    pub fn is_invalid(&self) -> bool {
1498        matches!(self, Self::Invalid(_))
1499    }
1500}
1501
1502impl<I: Error> From<I> for GlibNoneOrInvalidError<I> {
1503    #[inline]
1504    fn from(invalid: I) -> Self {
1505        Self::Invalid(invalid)
1506    }
1507}
1508
1509impl<I: Error> fmt::Display for GlibNoneOrInvalidError<I> {
1510    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
1511        match self {
1512            Self::Invalid(err) => {
1513                write!(fmt, "glib value is invalid: ")?;
1514                fmt::Display::fmt(err, fmt)
1515            }
1516            Self::None => write!(fmt, "glib value is None"),
1517        }
1518    }
1519}
1520
1521impl<I: Error> Error for GlibNoneOrInvalidError<I> {}
1522
1523impl<G: Copy, I: Error, T: TryFromGlib<G, Error = GlibNoneOrInvalidError<I>>> FromGlib<G>
1524    for Result<Option<T>, I>
1525{
1526    #[inline]
1527    unsafe fn from_glib(val: G) -> Self {
1528        unsafe {
1529            match T::try_from_glib(val) {
1530                Ok(value) => Ok(Some(value)),
1531                Err(GlibNoneOrInvalidError::None) => Ok(None),
1532                Err(GlibNoneOrInvalidError::Invalid(err)) => Err(err),
1533            }
1534        }
1535    }
1536}
1537
1538// rustdoc-stripper-ignore-next
1539/// Translate from a pointer type which is annotated with `transfer none`.
1540/// The resulting value is referenced at least once, by the bindings.
1541///
1542/// This is suitable for floating references, which become strong references.
1543/// It is also suitable for acquiring non-gobject values, like `gchar*`.
1544///
1545/// <a name="safety_points"></a>
1546/// # Safety
1547///
1548/// The implementation of this trait should acquire a reference to the value
1549/// in a way appropriate to the type,
1550/// e.g. by increasing the reference count or copying.
1551/// Values obtained using this trait must be properly released on `drop()`
1552/// by the implementing type.
1553///
1554/// For more information, refer to module level documentation.
1555pub trait FromGlibPtrNone<P: Ptr>: Sized {
1556    // rustdoc-stripper-ignore-next
1557    /// # Safety
1558    ///
1559    /// See trait level [notes on safety](#safety_points)
1560    unsafe fn from_glib_none(ptr: P) -> Self;
1561}
1562
1563// rustdoc-stripper-ignore-next
1564/// Translate from a pointer type which is annotated with `transfer full`.
1565/// This transfers the ownership of the value to the Rust side.
1566///
1567/// Because ownership can only be transferred if something is already referenced,
1568/// this is unsuitable for floating references.
1569///
1570/// <a name="safety_points"></a>
1571/// # Safety
1572///
1573/// The implementation of this trait should not alter the reference count
1574/// or make copies of the underlying value.
1575/// Values obtained using this trait must be properly released on `drop()`
1576/// by the implementing type.
1577///
1578/// For more information, refer to module level documentation.
1579pub trait FromGlibPtrFull<P: Ptr>: Sized {
1580    // rustdoc-stripper-ignore-next
1581    /// # Safety
1582    ///
1583    /// See trait level [notes on safety](#safety_points)
1584    unsafe fn from_glib_full(ptr: P) -> Self;
1585}
1586
1587// rustdoc-stripper-ignore-next
1588/// Translate from a pointer type by borrowing, without affecting the refcount.
1589///
1590/// The purpose of this trait is to access values inside callbacks
1591/// without changing their reference status.
1592/// The obtained borrow must not be accessed outside of the scope of the callback,
1593/// and called procedures must not store any references to the underlying data.
1594/// Safe Rust code must never obtain a mutable Rust reference.
1595///
1596/// <a name="safety_points"></a>
1597/// # Safety
1598///
1599/// The implementation of this trait as well as the returned type
1600/// must satisfy the same constraints together.
1601/// They must not take ownership of the underlying value, copy it,
1602/// and should not change its reference count.
1603/// If it does, it must properly release obtained references.
1604///
1605/// The returned value, when dropped,
1606/// must leave the underlying value in the same state
1607/// as before from_glib_borrow was called:
1608/// - it must not be dropped,
1609/// - it must be the same type of reference, e.g. still floating.
1610///
1611/// For more information, refer to module level documentation.
1612pub trait FromGlibPtrBorrow<P: Ptr>: Sized {
1613    // rustdoc-stripper-ignore-next
1614    /// # Safety
1615    ///
1616    /// See trait level [notes on safety](#safety_points)
1617    unsafe fn from_glib_borrow(_ptr: P) -> Borrowed<Self> {
1618        unimplemented!();
1619    }
1620}
1621
1622// rustdoc-stripper-ignore-next
1623/// Translate from a pointer type, transfer: none.
1624///
1625/// See [`FromGlibPtrNone`](trait.FromGlibPtrNone.html).
1626#[inline]
1627pub unsafe fn from_glib_none<P: Ptr, T: FromGlibPtrNone<P>>(ptr: P) -> T {
1628    unsafe { FromGlibPtrNone::from_glib_none(ptr) }
1629}
1630
1631// rustdoc-stripper-ignore-next
1632/// Translate from a pointer type, transfer: full (assume ownership).
1633///
1634/// See [`FromGlibPtrFull`](trait.FromGlibPtrFull.html).
1635#[inline]
1636pub unsafe fn from_glib_full<P: Ptr, T: FromGlibPtrFull<P>>(ptr: P) -> T {
1637    unsafe { FromGlibPtrFull::from_glib_full(ptr) }
1638}
1639
1640// rustdoc-stripper-ignore-next
1641/// Translate from a pointer type, borrowing the pointer.
1642///
1643/// See [`FromGlibPtrBorrow`](trait.FromGlibPtrBorrow.html).
1644#[inline]
1645pub unsafe fn from_glib_borrow<P: Ptr, T: FromGlibPtrBorrow<P>>(ptr: P) -> Borrowed<T> {
1646    unsafe { FromGlibPtrBorrow::from_glib_borrow(ptr) }
1647}
1648
1649impl<P: Ptr, T: FromGlibPtrNone<P>> FromGlibPtrNone<P> for Option<T> {
1650    #[inline]
1651    unsafe fn from_glib_none(ptr: P) -> Option<T> {
1652        unsafe {
1653            if ptr.is_null() {
1654                None
1655            } else {
1656                Some(from_glib_none(ptr))
1657            }
1658        }
1659    }
1660}
1661
1662impl<P: Ptr, T: FromGlibPtrBorrow<P>> FromGlibPtrBorrow<P> for Option<T> {
1663    #[inline]
1664    unsafe fn from_glib_borrow(ptr: P) -> Borrowed<Option<T>> {
1665        unsafe {
1666            if ptr.is_null() {
1667                Borrowed::new(None)
1668            } else {
1669                let val = T::from_glib_borrow(ptr);
1670                Borrowed::new(Some(val.into_inner()))
1671            }
1672        }
1673    }
1674}
1675
1676impl<P: Ptr, T: FromGlibPtrFull<P>> FromGlibPtrFull<P> for Option<T> {
1677    #[inline]
1678    unsafe fn from_glib_full(ptr: P) -> Option<T> {
1679        unsafe {
1680            if ptr.is_null() {
1681                None
1682            } else {
1683                Some(from_glib_full(ptr))
1684            }
1685        }
1686    }
1687}
1688
1689impl FromGlibPtrNone<*const c_char> for String {
1690    #[inline]
1691    unsafe fn from_glib_none(ptr: *const c_char) -> Self {
1692        unsafe {
1693            debug_assert!(!ptr.is_null());
1694            Self::from_utf8_lossy(CStr::from_ptr(ptr).to_bytes()).into_owned()
1695        }
1696    }
1697}
1698
1699// TODO: Deprecate this
1700impl FromGlibPtrFull<*const c_char> for String {
1701    #[inline]
1702    unsafe fn from_glib_full(ptr: *const c_char) -> Self {
1703        unsafe {
1704            let res = from_glib_none(ptr);
1705            ffi::g_free(ptr as *mut _);
1706            res
1707        }
1708    }
1709}
1710
1711// TODO: Deprecate this
1712impl FromGlibPtrNone<*mut c_char> for String {
1713    #[inline]
1714    unsafe fn from_glib_none(ptr: *mut c_char) -> Self {
1715        unsafe {
1716            debug_assert!(!ptr.is_null());
1717            Self::from_utf8_lossy(CStr::from_ptr(ptr).to_bytes()).into_owned()
1718        }
1719    }
1720}
1721
1722// TODO: Deprecate this
1723impl FromGlibPtrFull<*mut c_char> for String {
1724    #[inline]
1725    unsafe fn from_glib_full(ptr: *mut c_char) -> Self {
1726        unsafe {
1727            let res = from_glib_none(ptr);
1728            ffi::g_free(ptr as *mut _);
1729            res
1730        }
1731    }
1732}
1733
1734#[cfg(not(windows))]
1735pub(crate) unsafe fn c_to_path_buf(ptr: *const c_char) -> PathBuf {
1736    unsafe {
1737        debug_assert!(!ptr.is_null());
1738
1739        // GLib paths on UNIX are always in the local encoding, which can be
1740        // UTF-8 or anything else really, but is always a NUL-terminated string
1741        // and must not contain any other NUL bytes
1742        OsString::from_vec(CStr::from_ptr(ptr).to_bytes().to_vec()).into()
1743    }
1744}
1745
1746#[cfg(not(windows))]
1747pub(crate) unsafe fn c_to_path<'a>(ptr: *const c_char) -> &'a Path {
1748    unsafe {
1749        debug_assert!(!ptr.is_null());
1750
1751        Path::new(OsStr::from_bytes(CStr::from_ptr(ptr).to_bytes()))
1752    }
1753}
1754
1755#[cfg(windows)]
1756pub(crate) unsafe fn c_to_path<'a>(ptr: *const c_char) -> &'a Path {
1757    debug_assert!(!ptr.is_null());
1758
1759    unsafe {
1760        // GLib paths on Windows are always UTF-8, see c_to_path_buf() above
1761        Path::new(crate::GStr::from_ptr(ptr).as_str())
1762    }
1763}
1764
1765#[cfg(windows)]
1766pub(crate) unsafe fn c_to_path_buf(ptr: *const c_char) -> PathBuf {
1767    debug_assert!(!ptr.is_null());
1768
1769    unsafe {
1770        // GLib paths on Windows are always UTF-8, as such we can convert to a String
1771        // first and then go to a PathBuf from there. Unless there is a bug
1772        // in the C library, the conversion from UTF-8 can never fail so we can
1773        // safely panic here if that ever happens
1774        String::from_utf8(CStr::from_ptr(ptr).to_bytes().into())
1775            .expect("Invalid, non-UTF8 path")
1776            .into()
1777    }
1778}
1779
1780#[cfg(not(windows))]
1781pub(crate) unsafe fn c_to_os_string(ptr: *const c_char) -> OsString {
1782    unsafe {
1783        debug_assert!(!ptr.is_null());
1784
1785        // GLib OS string (environment strings) on UNIX are always in the local encoding,
1786        // which can be UTF-8 or anything else really, but is always a NUL-terminated string
1787        // and must not contain any other NUL bytes
1788        OsString::from_vec(CStr::from_ptr(ptr).to_bytes().to_vec())
1789    }
1790}
1791
1792#[cfg(windows)]
1793pub(crate) unsafe fn c_to_os_string(ptr: *const c_char) -> OsString {
1794    debug_assert!(!ptr.is_null());
1795
1796    unsafe {
1797        // GLib OS string (environment strings) on Windows are always UTF-8,
1798        // as such we can convert to a String
1799        // first and then go to a OsString from there. Unless there is a bug
1800        // in the C library, the conversion from UTF-8 can never fail so we can
1801        // safely panic here if that ever happens
1802        String::from_utf8(CStr::from_ptr(ptr).to_bytes().into())
1803            .expect("Invalid, non-UTF8 path")
1804            .into()
1805    }
1806}
1807
1808impl FromGlibPtrNone<*const c_char> for PathBuf {
1809    #[inline]
1810    unsafe fn from_glib_none(ptr: *const c_char) -> Self {
1811        unsafe {
1812            debug_assert!(!ptr.is_null());
1813            c_to_path_buf(ptr)
1814        }
1815    }
1816}
1817
1818impl FromGlibPtrFull<*const c_char> for PathBuf {
1819    #[inline]
1820    unsafe fn from_glib_full(ptr: *const c_char) -> Self {
1821        unsafe {
1822            let res = from_glib_none(ptr);
1823            ffi::g_free(ptr as *mut _);
1824            res
1825        }
1826    }
1827}
1828
1829impl FromGlibPtrNone<*mut c_char> for PathBuf {
1830    #[inline]
1831    unsafe fn from_glib_none(ptr: *mut c_char) -> Self {
1832        unsafe {
1833            debug_assert!(!ptr.is_null());
1834            c_to_path_buf(ptr)
1835        }
1836    }
1837}
1838
1839impl FromGlibPtrFull<*mut c_char> for PathBuf {
1840    #[inline]
1841    unsafe fn from_glib_full(ptr: *mut c_char) -> Self {
1842        unsafe {
1843            let res = from_glib_none(ptr);
1844            ffi::g_free(ptr as *mut _);
1845            res
1846        }
1847    }
1848}
1849
1850#[cfg(not(windows))]
1851pub(crate) unsafe fn c_to_path_buf_num(ptr: *const c_char, num: usize) -> PathBuf {
1852    unsafe {
1853        debug_assert!(!ptr.is_null());
1854        let slice = std::slice::from_raw_parts(ptr as *const u8, num);
1855        OsString::from_vec(slice.to_vec()).into()
1856    }
1857}
1858
1859#[cfg(windows)]
1860pub(crate) unsafe fn c_to_path_buf_num(ptr: *const c_char, num: usize) -> PathBuf {
1861    unsafe {
1862        debug_assert!(!ptr.is_null());
1863        let slice = std::slice::from_raw_parts(ptr as *const u8, num);
1864        String::from_utf8(slice.into())
1865            .expect("Invalid, non-UTF8 path")
1866            .into()
1867    }
1868}
1869
1870#[doc(hidden)]
1871impl FromGlibContainer<*const c_char, *const i8> for PathBuf {
1872    unsafe fn from_glib_none_num(ptr: *const i8, num: usize) -> Self {
1873        unsafe { c_to_path_buf_num(ptr as *const _, num) }
1874    }
1875
1876    unsafe fn from_glib_container_num(ptr: *const i8, num: usize) -> Self {
1877        unsafe { c_to_path_buf_num(ptr as *const _, num) }
1878    }
1879
1880    unsafe fn from_glib_full_num(ptr: *const i8, num: usize) -> Self {
1881        unsafe {
1882            let res = c_to_path_buf_num(ptr as *const _, num);
1883            ffi::g_free(ptr as *mut _);
1884            res
1885        }
1886    }
1887}
1888
1889#[doc(hidden)]
1890impl FromGlibContainer<*const c_char, *mut i8> for PathBuf {
1891    unsafe fn from_glib_none_num(ptr: *mut i8, num: usize) -> Self {
1892        unsafe { FromGlibContainer::from_glib_none_num(ptr as *const i8, num) }
1893    }
1894
1895    unsafe fn from_glib_container_num(ptr: *mut i8, num: usize) -> Self {
1896        unsafe { FromGlibContainer::from_glib_container_num(ptr as *const i8, num) }
1897    }
1898
1899    unsafe fn from_glib_full_num(ptr: *mut i8, num: usize) -> Self {
1900        unsafe { FromGlibContainer::from_glib_full_num(ptr as *const i8, num) }
1901    }
1902}
1903
1904#[doc(hidden)]
1905impl FromGlibContainer<*const c_char, *const u8> for PathBuf {
1906    unsafe fn from_glib_none_num(ptr: *const u8, num: usize) -> Self {
1907        unsafe { FromGlibContainer::from_glib_none_num(ptr as *const i8, num) }
1908    }
1909
1910    unsafe fn from_glib_container_num(ptr: *const u8, num: usize) -> Self {
1911        unsafe { FromGlibContainer::from_glib_container_num(ptr as *const i8, num) }
1912    }
1913
1914    unsafe fn from_glib_full_num(ptr: *const u8, num: usize) -> Self {
1915        unsafe { FromGlibContainer::from_glib_full_num(ptr as *const i8, num) }
1916    }
1917}
1918
1919#[doc(hidden)]
1920impl FromGlibContainer<*const c_char, *mut u8> for PathBuf {
1921    unsafe fn from_glib_none_num(ptr: *mut u8, num: usize) -> Self {
1922        unsafe { FromGlibContainer::from_glib_none_num(ptr as *const i8, num) }
1923    }
1924
1925    unsafe fn from_glib_container_num(ptr: *mut u8, num: usize) -> Self {
1926        unsafe { FromGlibContainer::from_glib_container_num(ptr as *const i8, num) }
1927    }
1928
1929    unsafe fn from_glib_full_num(ptr: *mut u8, num: usize) -> Self {
1930        unsafe { FromGlibContainer::from_glib_full_num(ptr as *const i8, num) }
1931    }
1932}
1933
1934impl FromGlibPtrNone<*const c_char> for OsString {
1935    #[inline]
1936    unsafe fn from_glib_none(ptr: *const c_char) -> Self {
1937        unsafe {
1938            debug_assert!(!ptr.is_null());
1939            c_to_os_string(ptr)
1940        }
1941    }
1942}
1943
1944impl FromGlibPtrFull<*const c_char> for OsString {
1945    #[inline]
1946    unsafe fn from_glib_full(ptr: *const c_char) -> Self {
1947        unsafe {
1948            let res = from_glib_none(ptr);
1949            ffi::g_free(ptr as *mut _);
1950            res
1951        }
1952    }
1953}
1954
1955impl FromGlibPtrNone<*mut c_char> for OsString {
1956    #[inline]
1957    unsafe fn from_glib_none(ptr: *mut c_char) -> Self {
1958        unsafe {
1959            debug_assert!(!ptr.is_null());
1960            c_to_os_string(ptr)
1961        }
1962    }
1963}
1964
1965impl FromGlibPtrFull<*mut c_char> for OsString {
1966    #[inline]
1967    unsafe fn from_glib_full(ptr: *mut c_char) -> Self {
1968        unsafe {
1969            let res = from_glib_none(ptr);
1970            ffi::g_free(ptr as *mut _);
1971            res
1972        }
1973    }
1974}
1975
1976/// Translate from a container.
1977pub trait FromGlibContainer<T, P: Ptr>: Sized {
1978    /// Transfer: none.
1979    ///
1980    /// `num` is the advised number of elements.
1981    unsafe fn from_glib_none_num(ptr: P, num: usize) -> Self;
1982
1983    /// Transfer: container.
1984    ///
1985    /// `num` is the advised number of elements.
1986    unsafe fn from_glib_container_num(ptr: P, num: usize) -> Self;
1987
1988    /// Transfer: full.
1989    ///
1990    /// `num` is the advised number of elements.
1991    unsafe fn from_glib_full_num(ptr: P, num: usize) -> Self;
1992}
1993
1994/// Translate from a container of pointers.
1995pub trait FromGlibPtrContainer<P: Ptr, PP: Ptr>: FromGlibContainer<P, PP> + Sized {
1996    /// Transfer: none.
1997    unsafe fn from_glib_none(ptr: PP) -> Self;
1998
1999    /// Transfer: container.
2000    unsafe fn from_glib_container(ptr: PP) -> Self;
2001
2002    /// Transfer: full.
2003    unsafe fn from_glib_full(ptr: PP) -> Self;
2004}
2005
2006pub unsafe fn c_ptr_array_len<P: Ptr>(mut ptr: *const P) -> usize {
2007    unsafe {
2008        let mut len = 0;
2009
2010        if !ptr.is_null() {
2011            while !(*ptr).is_null() {
2012                len += 1;
2013                ptr = ptr.offset(1);
2014            }
2015        }
2016        len
2017    }
2018}
2019
2020pub trait FromGlibContainerAsVec<T, P: Ptr>
2021where
2022    Self: Sized,
2023{
2024    unsafe fn from_glib_none_num_as_vec(ptr: P, num: usize) -> Vec<Self>;
2025    unsafe fn from_glib_container_num_as_vec(ptr: P, num: usize) -> Vec<Self>;
2026    unsafe fn from_glib_full_num_as_vec(ptr: P, num: usize) -> Vec<Self>;
2027}
2028
2029pub trait FromGlibPtrArrayContainerAsVec<P: Ptr, PP: Ptr>: FromGlibContainerAsVec<P, PP>
2030where
2031    Self: Sized,
2032{
2033    unsafe fn from_glib_none_as_vec(ptr: PP) -> Vec<Self>;
2034    unsafe fn from_glib_container_as_vec(ptr: PP) -> Vec<Self>;
2035    unsafe fn from_glib_full_as_vec(ptr: PP) -> Vec<Self>;
2036}
2037
2038impl FromGlibContainerAsVec<bool, *const ffi::gboolean> for bool {
2039    unsafe fn from_glib_none_num_as_vec(ptr: *const ffi::gboolean, num: usize) -> Vec<Self> {
2040        unsafe {
2041            if num == 0 || ptr.is_null() {
2042                return Vec::new();
2043            }
2044
2045            let mut res = Vec::<Self>::with_capacity(num);
2046            let res_ptr = res.as_mut_ptr();
2047            for i in 0..num {
2048                *res_ptr.add(i) = from_glib(ptr::read(ptr.add(i)));
2049            }
2050            res.set_len(num);
2051            res
2052        }
2053    }
2054
2055    unsafe fn from_glib_container_num_as_vec(_: *const ffi::gboolean, _: usize) -> Vec<Self> {
2056        // Can't really free a *const
2057        unimplemented!();
2058    }
2059
2060    unsafe fn from_glib_full_num_as_vec(_: *const ffi::gboolean, _: usize) -> Vec<Self> {
2061        // Can't really free a *const
2062        unimplemented!();
2063    }
2064}
2065
2066impl FromGlibContainerAsVec<bool, *mut ffi::gboolean> for bool {
2067    unsafe fn from_glib_none_num_as_vec(ptr: *mut ffi::gboolean, num: usize) -> Vec<Self> {
2068        unsafe { FromGlibContainerAsVec::from_glib_none_num_as_vec(ptr as *const _, num) }
2069    }
2070
2071    unsafe fn from_glib_container_num_as_vec(ptr: *mut ffi::gboolean, num: usize) -> Vec<Self> {
2072        unsafe {
2073            let res = FromGlibContainerAsVec::from_glib_none_num_as_vec(ptr, num);
2074            ffi::g_free(ptr as *mut _);
2075            res
2076        }
2077    }
2078
2079    unsafe fn from_glib_full_num_as_vec(ptr: *mut ffi::gboolean, num: usize) -> Vec<Self> {
2080        unsafe { FromGlibContainerAsVec::from_glib_container_num_as_vec(ptr, num) }
2081    }
2082}
2083
2084macro_rules! impl_from_glib_container_as_vec_fundamental {
2085    ($name:ty) => {
2086        unsafe impl TransparentType for $name {
2087            type GlibType = $name;
2088        }
2089
2090        impl FromGlibContainerAsVec<$name, *const $name> for $name {
2091            unsafe fn from_glib_none_num_as_vec(ptr: *const $name, num: usize) -> Vec<Self> {
2092                unsafe {
2093                    if num == 0 || ptr.is_null() {
2094                        return Vec::new();
2095                    }
2096
2097                    let mut res = Vec::with_capacity(num);
2098                    let res_ptr = res.as_mut_ptr();
2099                    std::ptr::copy_nonoverlapping(ptr, res_ptr, num);
2100                    res.set_len(num);
2101                    res
2102                }
2103            }
2104
2105            unsafe fn from_glib_container_num_as_vec(_: *const $name, _: usize) -> Vec<Self> {
2106                // Can't really free a *const
2107                unimplemented!();
2108            }
2109
2110            unsafe fn from_glib_full_num_as_vec(_: *const $name, _: usize) -> Vec<Self> {
2111                // Can't really free a *const
2112                unimplemented!();
2113            }
2114        }
2115
2116        impl FromGlibContainerAsVec<$name, *mut $name> for $name {
2117            unsafe fn from_glib_none_num_as_vec(ptr: *mut $name, num: usize) -> Vec<Self> {
2118                unsafe { FromGlibContainerAsVec::from_glib_none_num_as_vec(ptr as *const _, num) }
2119            }
2120
2121            unsafe fn from_glib_container_num_as_vec(ptr: *mut $name, num: usize) -> Vec<Self> {
2122                unsafe {
2123                    let res = FromGlibContainerAsVec::from_glib_none_num_as_vec(ptr, num);
2124                    ffi::g_free(ptr as *mut _);
2125                    res
2126                }
2127            }
2128
2129            unsafe fn from_glib_full_num_as_vec(ptr: *mut $name, num: usize) -> Vec<Self> {
2130                unsafe { FromGlibContainerAsVec::from_glib_container_num_as_vec(ptr, num) }
2131            }
2132        }
2133    };
2134}
2135
2136impl_from_glib_container_as_vec_fundamental!(u8);
2137impl_from_glib_container_as_vec_fundamental!(i8);
2138impl_from_glib_container_as_vec_fundamental!(u16);
2139impl_from_glib_container_as_vec_fundamental!(i16);
2140impl_from_glib_container_as_vec_fundamental!(u32);
2141impl_from_glib_container_as_vec_fundamental!(i32);
2142impl_from_glib_container_as_vec_fundamental!(u64);
2143impl_from_glib_container_as_vec_fundamental!(i64);
2144impl_from_glib_container_as_vec_fundamental!(f32);
2145impl_from_glib_container_as_vec_fundamental!(f64);
2146
2147macro_rules! impl_from_glib_container_as_vec_string {
2148    ($name:ty, $ffi_name:ty) => {
2149        impl FromGlibContainerAsVec<$ffi_name, *const $ffi_name> for $name {
2150            unsafe fn from_glib_none_num_as_vec(ptr: *const $ffi_name, num: usize) -> Vec<Self> {
2151                unsafe {
2152                    if num == 0 || ptr.is_null() {
2153                        return Vec::new();
2154                    }
2155
2156                    let mut res = Vec::<Self>::with_capacity(num);
2157                    let res_ptr = res.as_mut_ptr();
2158                    for i in 0..num {
2159                        std::ptr::write(
2160                            res_ptr.add(i),
2161                            from_glib_none(ptr::read(ptr.add(i)) as $ffi_name),
2162                        );
2163                    }
2164                    res.set_len(num);
2165                    res
2166                }
2167            }
2168
2169            unsafe fn from_glib_container_num_as_vec(_: *const $ffi_name, _: usize) -> Vec<Self> {
2170                // Can't really free a *const
2171                unimplemented!();
2172            }
2173
2174            unsafe fn from_glib_full_num_as_vec(_: *const $ffi_name, _: usize) -> Vec<Self> {
2175                // Can't really free a *const
2176                unimplemented!();
2177            }
2178        }
2179
2180        impl FromGlibContainerAsVec<$ffi_name, *mut $ffi_name> for $name {
2181            unsafe fn from_glib_none_num_as_vec(ptr: *mut $ffi_name, num: usize) -> Vec<Self> {
2182                unsafe { FromGlibContainerAsVec::from_glib_none_num_as_vec(ptr as *const _, num) }
2183            }
2184
2185            unsafe fn from_glib_container_num_as_vec(ptr: *mut $ffi_name, num: usize) -> Vec<Self> {
2186                unsafe {
2187                    let res = FromGlibContainerAsVec::from_glib_none_num_as_vec(ptr, num);
2188                    ffi::g_free(ptr as *mut _);
2189                    res
2190                }
2191            }
2192
2193            unsafe fn from_glib_full_num_as_vec(ptr: *mut $ffi_name, num: usize) -> Vec<Self> {
2194                unsafe {
2195                    if num == 0 || ptr.is_null() {
2196                        ffi::g_free(ptr as *mut _);
2197                        return Vec::new();
2198                    }
2199
2200                    let mut res = Vec::<Self>::with_capacity(num);
2201                    let res_ptr = res.as_mut_ptr();
2202                    for i in 0..num {
2203                        std::ptr::write(
2204                            res_ptr.add(i),
2205                            from_glib_full(ptr::read(ptr.add(i)) as $ffi_name),
2206                        );
2207                    }
2208                    res.set_len(num);
2209                    ffi::g_free(ptr as *mut _);
2210                    res
2211                }
2212            }
2213        }
2214
2215        impl FromGlibPtrArrayContainerAsVec<$ffi_name, *mut $ffi_name> for $name {
2216            unsafe fn from_glib_none_as_vec(ptr: *mut $ffi_name) -> Vec<Self> {
2217                unsafe {
2218                    FromGlibContainerAsVec::from_glib_none_num_as_vec(ptr, c_ptr_array_len(ptr))
2219                }
2220            }
2221
2222            unsafe fn from_glib_container_as_vec(ptr: *mut $ffi_name) -> Vec<Self> {
2223                unsafe {
2224                    FromGlibContainerAsVec::from_glib_container_num_as_vec(
2225                        ptr,
2226                        c_ptr_array_len(ptr),
2227                    )
2228                }
2229            }
2230
2231            unsafe fn from_glib_full_as_vec(ptr: *mut $ffi_name) -> Vec<Self> {
2232                unsafe {
2233                    FromGlibContainerAsVec::from_glib_full_num_as_vec(ptr, c_ptr_array_len(ptr))
2234                }
2235            }
2236        }
2237
2238        impl FromGlibPtrArrayContainerAsVec<$ffi_name, *const $ffi_name> for $name {
2239            unsafe fn from_glib_none_as_vec(ptr: *const $ffi_name) -> Vec<Self> {
2240                unsafe {
2241                    FromGlibContainerAsVec::from_glib_none_num_as_vec(ptr, c_ptr_array_len(ptr))
2242                }
2243            }
2244
2245            unsafe fn from_glib_container_as_vec(ptr: *const $ffi_name) -> Vec<Self> {
2246                unsafe {
2247                    FromGlibContainerAsVec::from_glib_container_num_as_vec(
2248                        ptr,
2249                        c_ptr_array_len(ptr),
2250                    )
2251                }
2252            }
2253
2254            unsafe fn from_glib_full_as_vec(ptr: *const $ffi_name) -> Vec<Self> {
2255                unsafe {
2256                    FromGlibContainerAsVec::from_glib_full_num_as_vec(ptr, c_ptr_array_len(ptr))
2257                }
2258            }
2259        }
2260    };
2261}
2262
2263// TODO: Deprecate this
2264impl_from_glib_container_as_vec_string!(String, *const c_char);
2265impl_from_glib_container_as_vec_string!(String, *mut c_char);
2266
2267impl_from_glib_container_as_vec_string!(PathBuf, *const c_char);
2268impl_from_glib_container_as_vec_string!(PathBuf, *mut c_char);
2269impl_from_glib_container_as_vec_string!(OsString, *const c_char);
2270impl_from_glib_container_as_vec_string!(OsString, *mut c_char);
2271
2272impl<P, PP: Ptr, T: FromGlibContainerAsVec<P, PP>> FromGlibContainer<P, PP> for Vec<T> {
2273    unsafe fn from_glib_none_num(ptr: PP, num: usize) -> Vec<T> {
2274        unsafe { FromGlibContainerAsVec::from_glib_none_num_as_vec(ptr, num) }
2275    }
2276
2277    unsafe fn from_glib_container_num(ptr: PP, num: usize) -> Vec<T> {
2278        unsafe { FromGlibContainerAsVec::from_glib_container_num_as_vec(ptr, num) }
2279    }
2280
2281    unsafe fn from_glib_full_num(ptr: PP, num: usize) -> Vec<T> {
2282        unsafe { FromGlibContainerAsVec::from_glib_full_num_as_vec(ptr, num) }
2283    }
2284}
2285
2286impl<P: Ptr, PP: Ptr, T: FromGlibPtrArrayContainerAsVec<P, PP>> FromGlibPtrContainer<P, PP>
2287    for Vec<T>
2288{
2289    unsafe fn from_glib_none(ptr: PP) -> Vec<T> {
2290        unsafe { FromGlibPtrArrayContainerAsVec::from_glib_none_as_vec(ptr) }
2291    }
2292
2293    unsafe fn from_glib_container(ptr: PP) -> Vec<T> {
2294        unsafe { FromGlibPtrArrayContainerAsVec::from_glib_container_as_vec(ptr) }
2295    }
2296
2297    unsafe fn from_glib_full(ptr: PP) -> Vec<T> {
2298        unsafe { FromGlibPtrArrayContainerAsVec::from_glib_full_as_vec(ptr) }
2299    }
2300}
2301
2302impl<T> FromGlibContainerAsVec<<T as GlibPtrDefault>::GlibType, *mut ffi::GSList> for T
2303where
2304    T: GlibPtrDefault
2305        + FromGlibPtrNone<<T as GlibPtrDefault>::GlibType>
2306        + FromGlibPtrFull<<T as GlibPtrDefault>::GlibType>,
2307{
2308    unsafe fn from_glib_none_num_as_vec(mut ptr: *mut ffi::GSList, num: usize) -> Vec<T> {
2309        unsafe {
2310            if num == 0 || ptr.is_null() {
2311                return Vec::new();
2312            }
2313            let mut res = Vec::with_capacity(num);
2314            for _ in 0..num {
2315                if ptr.is_null() {
2316                    break;
2317                }
2318
2319                let item_ptr: <T as GlibPtrDefault>::GlibType = Ptr::from((*ptr).data);
2320                if !item_ptr.is_null() {
2321                    res.push(from_glib_none(item_ptr));
2322                }
2323                ptr = (*ptr).next;
2324            }
2325            res
2326        }
2327    }
2328
2329    unsafe fn from_glib_container_num_as_vec(ptr: *mut ffi::GSList, num: usize) -> Vec<T> {
2330        unsafe {
2331            let res = FromGlibContainerAsVec::from_glib_none_num_as_vec(ptr, num);
2332            ffi::g_slist_free(ptr);
2333            res
2334        }
2335    }
2336
2337    unsafe fn from_glib_full_num_as_vec(mut ptr: *mut ffi::GSList, num: usize) -> Vec<T> {
2338        unsafe {
2339            if num == 0 || ptr.is_null() {
2340                return Vec::new();
2341            }
2342            let orig_ptr = ptr;
2343            let mut res = Vec::with_capacity(num);
2344            for _ in 0..num {
2345                if ptr.is_null() {
2346                    break;
2347                }
2348
2349                let item_ptr: <T as GlibPtrDefault>::GlibType = Ptr::from((*ptr).data);
2350                if !item_ptr.is_null() {
2351                    res.push(from_glib_full(item_ptr));
2352                }
2353                ptr = (*ptr).next;
2354            }
2355            ffi::g_slist_free(orig_ptr);
2356            res
2357        }
2358    }
2359}
2360
2361impl<T> FromGlibPtrArrayContainerAsVec<<T as GlibPtrDefault>::GlibType, *mut ffi::GSList> for T
2362where
2363    T: GlibPtrDefault
2364        + FromGlibPtrNone<<T as GlibPtrDefault>::GlibType>
2365        + FromGlibPtrFull<<T as GlibPtrDefault>::GlibType>,
2366{
2367    unsafe fn from_glib_none_as_vec(mut ptr: *mut ffi::GSList) -> Vec<T> {
2368        unsafe {
2369            let mut res = Vec::new();
2370            while !ptr.is_null() {
2371                let item_ptr: <T as GlibPtrDefault>::GlibType = Ptr::from((*ptr).data);
2372                if !item_ptr.is_null() {
2373                    res.push(from_glib_none(item_ptr));
2374                }
2375                ptr = (*ptr).next;
2376            }
2377            res
2378        }
2379    }
2380
2381    unsafe fn from_glib_container_as_vec(ptr: *mut ffi::GSList) -> Vec<T> {
2382        unsafe {
2383            let res = FromGlibPtrArrayContainerAsVec::from_glib_none_as_vec(ptr);
2384            ffi::g_slist_free(ptr);
2385            res
2386        }
2387    }
2388
2389    unsafe fn from_glib_full_as_vec(mut ptr: *mut ffi::GSList) -> Vec<T> {
2390        unsafe {
2391            let orig_ptr = ptr;
2392            let mut res = Vec::new();
2393            while !ptr.is_null() {
2394                let item_ptr: <T as GlibPtrDefault>::GlibType = Ptr::from((*ptr).data);
2395                if !item_ptr.is_null() {
2396                    res.push(from_glib_full(item_ptr));
2397                }
2398                ptr = (*ptr).next;
2399            }
2400            ffi::g_slist_free(orig_ptr);
2401            res
2402        }
2403    }
2404}
2405
2406impl<T> FromGlibContainerAsVec<<T as GlibPtrDefault>::GlibType, *mut ffi::GList> for T
2407where
2408    T: GlibPtrDefault
2409        + FromGlibPtrNone<<T as GlibPtrDefault>::GlibType>
2410        + FromGlibPtrFull<<T as GlibPtrDefault>::GlibType>,
2411{
2412    unsafe fn from_glib_none_num_as_vec(mut ptr: *mut ffi::GList, num: usize) -> Vec<T> {
2413        unsafe {
2414            if num == 0 || ptr.is_null() {
2415                return Vec::new();
2416            }
2417            let mut res = Vec::with_capacity(num);
2418            for _ in 0..num {
2419                if ptr.is_null() {
2420                    break;
2421                }
2422
2423                let item_ptr: <T as GlibPtrDefault>::GlibType = Ptr::from((*ptr).data);
2424                if !item_ptr.is_null() {
2425                    res.push(from_glib_none(item_ptr));
2426                }
2427                ptr = (*ptr).next;
2428            }
2429            res
2430        }
2431    }
2432
2433    unsafe fn from_glib_container_num_as_vec(ptr: *mut ffi::GList, num: usize) -> Vec<T> {
2434        unsafe {
2435            let res = FromGlibContainerAsVec::from_glib_none_num_as_vec(ptr, num);
2436            ffi::g_list_free(ptr);
2437            res
2438        }
2439    }
2440
2441    unsafe fn from_glib_full_num_as_vec(mut ptr: *mut ffi::GList, num: usize) -> Vec<T> {
2442        unsafe {
2443            if num == 0 || ptr.is_null() {
2444                return Vec::new();
2445            }
2446            let orig_ptr = ptr;
2447            let mut res = Vec::with_capacity(num);
2448            for _ in 0..num {
2449                if ptr.is_null() {
2450                    break;
2451                }
2452
2453                let item_ptr: <T as GlibPtrDefault>::GlibType = Ptr::from((*ptr).data);
2454                if !item_ptr.is_null() {
2455                    res.push(from_glib_full(item_ptr));
2456                }
2457                ptr = (*ptr).next;
2458            }
2459            ffi::g_list_free(orig_ptr);
2460            res
2461        }
2462    }
2463}
2464
2465impl<T> FromGlibPtrArrayContainerAsVec<<T as GlibPtrDefault>::GlibType, *mut ffi::GList> for T
2466where
2467    T: GlibPtrDefault
2468        + FromGlibPtrNone<<T as GlibPtrDefault>::GlibType>
2469        + FromGlibPtrFull<<T as GlibPtrDefault>::GlibType>,
2470{
2471    unsafe fn from_glib_none_as_vec(mut ptr: *mut ffi::GList) -> Vec<T> {
2472        unsafe {
2473            let mut res = Vec::new();
2474            while !ptr.is_null() {
2475                let item_ptr: <T as GlibPtrDefault>::GlibType = Ptr::from((*ptr).data);
2476                if !item_ptr.is_null() {
2477                    res.push(from_glib_none(item_ptr));
2478                }
2479                ptr = (*ptr).next;
2480            }
2481            res
2482        }
2483    }
2484
2485    unsafe fn from_glib_container_as_vec(ptr: *mut ffi::GList) -> Vec<T> {
2486        unsafe {
2487            let res = FromGlibPtrArrayContainerAsVec::from_glib_none_as_vec(ptr);
2488            ffi::g_list_free(ptr);
2489            res
2490        }
2491    }
2492
2493    unsafe fn from_glib_full_as_vec(mut ptr: *mut ffi::GList) -> Vec<T> {
2494        unsafe {
2495            let orig_ptr = ptr;
2496            let mut res = Vec::new();
2497            while !ptr.is_null() {
2498                let item_ptr: <T as GlibPtrDefault>::GlibType = Ptr::from((*ptr).data);
2499                if !item_ptr.is_null() {
2500                    res.push(from_glib_full(item_ptr));
2501                }
2502                ptr = (*ptr).next;
2503            }
2504            ffi::g_list_free(orig_ptr);
2505            res
2506        }
2507    }
2508}
2509
2510impl<T> FromGlibContainerAsVec<<T as GlibPtrDefault>::GlibType, *const ffi::GList> for T
2511where
2512    T: GlibPtrDefault
2513        + FromGlibPtrNone<<T as GlibPtrDefault>::GlibType>
2514        + FromGlibPtrFull<<T as GlibPtrDefault>::GlibType>,
2515{
2516    unsafe fn from_glib_none_num_as_vec(ptr: *const ffi::GList, num: usize) -> Vec<T> {
2517        unsafe { FromGlibContainerAsVec::from_glib_none_num_as_vec(mut_override(ptr), num) }
2518    }
2519
2520    unsafe fn from_glib_container_num_as_vec(_: *const ffi::GList, _: usize) -> Vec<T> {
2521        // Can't really free a *const
2522        unimplemented!()
2523    }
2524
2525    unsafe fn from_glib_full_num_as_vec(_: *const ffi::GList, _: usize) -> Vec<T> {
2526        // Can't really free a *const
2527        unimplemented!()
2528    }
2529}
2530
2531impl<T> FromGlibPtrArrayContainerAsVec<<T as GlibPtrDefault>::GlibType, *const ffi::GList> for T
2532where
2533    T: GlibPtrDefault
2534        + FromGlibPtrNone<<T as GlibPtrDefault>::GlibType>
2535        + FromGlibPtrFull<<T as GlibPtrDefault>::GlibType>,
2536{
2537    unsafe fn from_glib_none_as_vec(ptr: *const ffi::GList) -> Vec<T> {
2538        unsafe { FromGlibPtrArrayContainerAsVec::from_glib_none_as_vec(mut_override(ptr)) }
2539    }
2540
2541    unsafe fn from_glib_container_as_vec(_: *const ffi::GList) -> Vec<T> {
2542        // Can't really free a *const
2543        unimplemented!()
2544    }
2545
2546    unsafe fn from_glib_full_as_vec(_: *const ffi::GList) -> Vec<T> {
2547        // Can't really free a *const
2548        unimplemented!()
2549    }
2550}
2551
2552impl<T> FromGlibContainerAsVec<<T as GlibPtrDefault>::GlibType, *const ffi::GSList> for T
2553where
2554    T: GlibPtrDefault
2555        + FromGlibPtrNone<<T as GlibPtrDefault>::GlibType>
2556        + FromGlibPtrFull<<T as GlibPtrDefault>::GlibType>,
2557{
2558    unsafe fn from_glib_none_num_as_vec(ptr: *const ffi::GSList, num: usize) -> Vec<T> {
2559        unsafe { FromGlibContainerAsVec::from_glib_none_num_as_vec(mut_override(ptr), num) }
2560    }
2561
2562    unsafe fn from_glib_container_num_as_vec(_: *const ffi::GSList, _: usize) -> Vec<T> {
2563        // Can't really free a *const
2564        unimplemented!()
2565    }
2566
2567    unsafe fn from_glib_full_num_as_vec(_: *const ffi::GSList, _: usize) -> Vec<T> {
2568        // Can't really free a *const
2569        unimplemented!()
2570    }
2571}
2572
2573impl<T> FromGlibPtrArrayContainerAsVec<<T as GlibPtrDefault>::GlibType, *const ffi::GSList> for T
2574where
2575    T: GlibPtrDefault
2576        + FromGlibPtrNone<<T as GlibPtrDefault>::GlibType>
2577        + FromGlibPtrFull<<T as GlibPtrDefault>::GlibType>,
2578{
2579    unsafe fn from_glib_none_as_vec(ptr: *const ffi::GSList) -> Vec<T> {
2580        unsafe { FromGlibPtrArrayContainerAsVec::from_glib_none_as_vec(mut_override(ptr)) }
2581    }
2582
2583    unsafe fn from_glib_container_as_vec(_: *const ffi::GSList) -> Vec<T> {
2584        // Can't really free a *const
2585        unimplemented!()
2586    }
2587
2588    unsafe fn from_glib_full_as_vec(_: *const ffi::GSList) -> Vec<T> {
2589        // Can't really free a *const
2590        unimplemented!()
2591    }
2592}
2593
2594#[allow(clippy::implicit_hasher)]
2595impl FromGlibContainer<*const c_char, *mut ffi::GHashTable> for HashMap<String, String> {
2596    unsafe fn from_glib_none_num(ptr: *mut ffi::GHashTable, _: usize) -> Self {
2597        unsafe { FromGlibPtrContainer::from_glib_none(ptr) }
2598    }
2599
2600    unsafe fn from_glib_container_num(ptr: *mut ffi::GHashTable, _: usize) -> Self {
2601        unsafe { FromGlibPtrContainer::from_glib_full(ptr) }
2602    }
2603
2604    unsafe fn from_glib_full_num(ptr: *mut ffi::GHashTable, _: usize) -> Self {
2605        unsafe { FromGlibPtrContainer::from_glib_full(ptr) }
2606    }
2607}
2608
2609#[allow(clippy::implicit_hasher)]
2610impl FromGlibPtrContainer<*const c_char, *mut ffi::GHashTable> for HashMap<String, String> {
2611    unsafe fn from_glib_none(ptr: *mut ffi::GHashTable) -> Self {
2612        unsafe {
2613            unsafe extern "C" fn read_string_hash_table(
2614                key: ffi::gpointer,
2615                value: ffi::gpointer,
2616                hash_map: ffi::gpointer,
2617            ) {
2618                unsafe {
2619                    let key: String = from_glib_none(key as *const c_char);
2620                    let value: String = from_glib_none(value as *const c_char);
2621                    let hash_map: &mut HashMap<String, String> =
2622                        &mut *(hash_map as *mut HashMap<String, String>);
2623                    hash_map.insert(key, value);
2624                }
2625            }
2626            let mut map = HashMap::with_capacity(ffi::g_hash_table_size(ptr) as usize);
2627            ffi::g_hash_table_foreach(
2628                ptr,
2629                Some(read_string_hash_table),
2630                &mut map as *mut HashMap<String, String> as *mut _,
2631            );
2632            map
2633        }
2634    }
2635
2636    unsafe fn from_glib_container(ptr: *mut ffi::GHashTable) -> Self {
2637        unsafe { FromGlibPtrContainer::from_glib_full(ptr) }
2638    }
2639
2640    unsafe fn from_glib_full(ptr: *mut ffi::GHashTable) -> Self {
2641        unsafe {
2642            let map = FromGlibPtrContainer::from_glib_none(ptr);
2643            ffi::g_hash_table_unref(ptr);
2644            map
2645        }
2646    }
2647}
2648
2649impl<T> FromGlibContainerAsVec<<T as GlibPtrDefault>::GlibType, *mut ffi::GPtrArray> for T
2650where
2651    T: GlibPtrDefault
2652        + FromGlibPtrNone<<T as GlibPtrDefault>::GlibType>
2653        + FromGlibPtrFull<<T as GlibPtrDefault>::GlibType>,
2654{
2655    unsafe fn from_glib_none_num_as_vec(ptr: *mut ffi::GPtrArray, num: usize) -> Vec<T> {
2656        unsafe {
2657            if num == 0 || ptr.is_null() {
2658                return Vec::new();
2659            }
2660            let pdata = (*ptr).pdata;
2661            debug_assert!((*ptr).len as usize >= num);
2662            let mut res = Vec::with_capacity(num);
2663            for i in 0..num {
2664                let item_ptr: <T as GlibPtrDefault>::GlibType = Ptr::from(ptr::read(pdata.add(i)));
2665                if !item_ptr.is_null() {
2666                    res.push(from_glib_none(item_ptr));
2667                }
2668            }
2669            res
2670        }
2671    }
2672
2673    unsafe fn from_glib_container_num_as_vec(ptr: *mut ffi::GPtrArray, num: usize) -> Vec<T> {
2674        unsafe {
2675            let res = FromGlibContainer::from_glib_none_num(ptr, num);
2676            if !ptr.is_null() {
2677                ffi::g_ptr_array_unref(ptr);
2678            }
2679            res
2680        }
2681    }
2682
2683    unsafe fn from_glib_full_num_as_vec(ptr: *mut ffi::GPtrArray, num: usize) -> Vec<T> {
2684        unsafe {
2685            if ptr.is_null() {
2686                return Vec::new();
2687            }
2688            if num == 0 {
2689                ffi::g_ptr_array_unref(ptr);
2690                return Vec::new();
2691            }
2692            let pdata = (*ptr).pdata;
2693            debug_assert!((*ptr).len as usize >= num);
2694            let mut res = Vec::with_capacity(num);
2695            for i in 0..num {
2696                let item_ptr: <T as GlibPtrDefault>::GlibType = Ptr::from(ptr::read(pdata.add(i)));
2697                if !item_ptr.is_null() {
2698                    res.push(from_glib_none(item_ptr));
2699                }
2700            }
2701            ffi::g_ptr_array_unref(ptr);
2702            res
2703        }
2704    }
2705}
2706
2707impl<T> FromGlibPtrArrayContainerAsVec<<T as GlibPtrDefault>::GlibType, *mut ffi::GPtrArray> for T
2708where
2709    T: GlibPtrDefault
2710        + FromGlibPtrNone<<T as GlibPtrDefault>::GlibType>
2711        + FromGlibPtrFull<<T as GlibPtrDefault>::GlibType>,
2712{
2713    unsafe fn from_glib_none_as_vec(ptr: *mut ffi::GPtrArray) -> Vec<T> {
2714        unsafe {
2715            let num = (*ptr).len as usize;
2716            FromGlibContainer::from_glib_none_num(ptr, num)
2717        }
2718    }
2719
2720    unsafe fn from_glib_container_as_vec(ptr: *mut ffi::GPtrArray) -> Vec<T> {
2721        unsafe {
2722            let num = (*ptr).len as usize;
2723            FromGlibContainer::from_glib_container_num(ptr, num)
2724        }
2725    }
2726
2727    unsafe fn from_glib_full_as_vec(ptr: *mut ffi::GPtrArray) -> Vec<T> {
2728        unsafe {
2729            let num = (*ptr).len as usize;
2730            FromGlibContainer::from_glib_full_num(ptr, num)
2731        }
2732    }
2733}
2734
2735impl<T> FromGlibContainerAsVec<<T as GlibPtrDefault>::GlibType, *const ffi::GPtrArray> for T
2736where
2737    T: GlibPtrDefault
2738        + FromGlibPtrNone<<T as GlibPtrDefault>::GlibType>
2739        + FromGlibPtrFull<<T as GlibPtrDefault>::GlibType>,
2740{
2741    unsafe fn from_glib_none_num_as_vec(ptr: *const ffi::GPtrArray, num: usize) -> Vec<T> {
2742        unsafe { FromGlibContainerAsVec::from_glib_none_num_as_vec(mut_override(ptr), num) }
2743    }
2744
2745    unsafe fn from_glib_container_num_as_vec(_: *const ffi::GPtrArray, _: usize) -> Vec<T> {
2746        // Can't really free a *const
2747        unimplemented!()
2748    }
2749
2750    unsafe fn from_glib_full_num_as_vec(_: *const ffi::GPtrArray, _: usize) -> Vec<T> {
2751        // Can't really free a *const
2752        unimplemented!()
2753    }
2754}
2755
2756impl<T> FromGlibPtrArrayContainerAsVec<<T as GlibPtrDefault>::GlibType, *const ffi::GPtrArray> for T
2757where
2758    T: GlibPtrDefault
2759        + FromGlibPtrNone<<T as GlibPtrDefault>::GlibType>
2760        + FromGlibPtrFull<<T as GlibPtrDefault>::GlibType>,
2761{
2762    unsafe fn from_glib_none_as_vec(ptr: *const ffi::GPtrArray) -> Vec<T> {
2763        unsafe { FromGlibPtrArrayContainerAsVec::from_glib_none_as_vec(mut_override(ptr)) }
2764    }
2765
2766    unsafe fn from_glib_container_as_vec(_: *const ffi::GPtrArray) -> Vec<T> {
2767        // Can't really free a *const
2768        unimplemented!()
2769    }
2770
2771    unsafe fn from_glib_full_as_vec(_: *const ffi::GPtrArray) -> Vec<T> {
2772        // Can't really free a *const
2773        unimplemented!()
2774    }
2775}
2776
2777/// Trait for types that have the same memory representation as a pointer to their FFI type.
2778///
2779/// Values of types implementing this trait can be transmuted to pointers of the FFI type,
2780/// references to pointers of pointers to the FFI type.
2781pub unsafe trait TransparentPtrType: Clone + Sized + GlibPtrDefault {}
2782
2783/// Trait for types that have the same memory representation as their FFI type.
2784///
2785/// Values of types implementing this trait can be transmuted directly to the FFI type, references
2786/// to pointers to the FFI type.
2787pub unsafe trait TransparentType: Clone + Sized {
2788    type GlibType;
2789}
2790
2791unsafe impl<T: TransparentPtrType> TransparentType for T {
2792    type GlibType = <T as GlibPtrDefault>::GlibType;
2793}
2794
2795#[cfg(test)]
2796mod tests {
2797    use std::{collections::HashMap, fs};
2798
2799    use tempfile::tempdir;
2800
2801    use super::*;
2802    use crate::{FileTest, GString};
2803
2804    #[test]
2805    fn boolean() {
2806        assert_eq!(true.into_glib(), ffi::GTRUE);
2807        assert_eq!(false.into_glib(), ffi::GFALSE);
2808        assert!(unsafe { bool::from_glib(ffi::GTRUE) });
2809        assert!(!unsafe { bool::from_glib(ffi::GFALSE) });
2810        assert!(unsafe { bool::from_glib(42) });
2811    }
2812
2813    #[test]
2814    fn ordering() {
2815        assert_eq!(Ordering::Less.into_glib(), -1);
2816        assert_eq!(Ordering::Equal.into_glib(), 0);
2817        assert_eq!(Ordering::Greater.into_glib(), 1);
2818        assert_eq!(Ordering::Less, unsafe { Ordering::from_glib(-42) });
2819        assert_eq!(Ordering::Less, unsafe { Ordering::from_glib(-1) });
2820        assert_eq!(Ordering::Equal, unsafe { Ordering::from_glib(0) });
2821        assert_eq!(Ordering::Greater, unsafe { Ordering::from_glib(1) });
2822        assert_eq!(Ordering::Greater, unsafe { Ordering::from_glib(42) });
2823    }
2824
2825    #[test]
2826    fn string() {
2827        let s = "ABC";
2828        let owned = "ABC".to_string();
2829        let cstring = CString::new("ABC").unwrap();
2830
2831        let stash = s.to_glib_none();
2832        assert_eq!(unsafe { CStr::from_ptr(stash.0) }, cstring.as_c_str());
2833
2834        let stash = owned.to_glib_none();
2835        assert_eq!(unsafe { CStr::from_ptr(stash.0) }, cstring.as_c_str());
2836
2837        let ptr: *mut c_char = s.to_glib_full();
2838        assert_eq!(unsafe { CStr::from_ptr(ptr) }, cstring.as_c_str());
2839
2840        unsafe {
2841            ffi::g_free(ptr as *mut _);
2842        }
2843
2844        let ptr: *mut c_char = owned.to_glib_full();
2845        assert_eq!(unsafe { CStr::from_ptr(ptr) }, cstring.as_c_str());
2846
2847        assert_eq!(s, unsafe { String::from_glib_none(ptr) });
2848        assert_eq!(owned, unsafe { String::from_glib_full(ptr) });
2849    }
2850
2851    #[test]
2852    fn string_hash_map() {
2853        let mut map = HashMap::new();
2854        map.insert("A".into(), "1".into());
2855        map.insert("B".into(), "2".into());
2856        map.insert("C".into(), "3".into());
2857        let ptr: *mut ffi::GHashTable = map.to_glib_full();
2858        let map = unsafe { HashMap::from_glib_full(ptr) };
2859        assert_eq!(map.get("A"), Some(&"1".into()));
2860        assert_eq!(map.get("B"), Some(&"2".into()));
2861        assert_eq!(map.get("C"), Some(&"3".into()));
2862    }
2863
2864    #[test]
2865    fn string_array() {
2866        let v = vec!["A".to_string(), "B".to_string(), "C".to_string()];
2867        let stash = v.to_glib_none();
2868        let ptr: *mut *mut c_char = stash.0;
2869        let ptr_copy = unsafe { ffi::g_strdupv(ptr) };
2870
2871        let actual: Vec<String> = unsafe { FromGlibPtrContainer::from_glib_full(ptr_copy) };
2872        assert_eq!(v, actual);
2873    }
2874
2875    #[test]
2876    fn gstring_array() {
2877        let v = vec!["A".to_string(), "B".to_string(), "C".to_string()];
2878        let stash = v.to_glib_none();
2879        let ptr: *mut *mut c_char = stash.0;
2880        let ptr_copy = unsafe { ffi::g_strdupv(ptr) };
2881
2882        let actual: Vec<GString> = unsafe { FromGlibPtrContainer::from_glib_full(ptr_copy) };
2883        assert_eq!(v, actual);
2884    }
2885
2886    #[test]
2887    fn ptr_array() {
2888        let strings = &["A", "B", "C"];
2889        let (ptr, _stash) =
2890            ToGlibContainerFromSlice::<*mut ffi::GPtrArray>::to_glib_none_from_slice(strings);
2891        let v: Vec<GString> = unsafe { FromGlibPtrArrayContainerAsVec::from_glib_none_as_vec(ptr) };
2892        assert_eq!(&v, strings);
2893    }
2894
2895    #[test]
2896    #[cfg(not(target_os = "macos"))]
2897    fn test_paths() {
2898        let tmp_dir = tempdir().unwrap();
2899
2900        // Test if passing paths to GLib and getting them back
2901        // gives us useful results
2902        let dir_1 = tmp_dir.path().join("abcd");
2903        fs::create_dir(&dir_1).unwrap();
2904        assert_eq!(crate::path_get_basename(&dir_1), Path::new("abcd"));
2905        assert_eq!(
2906            crate::path_get_basename(dir_1.canonicalize().unwrap()),
2907            Path::new("abcd")
2908        );
2909        // This currently fails on Windows because C:\\Users\\runneradmin
2910        // gets shortened to C:\\Users\\RUNNER~1
2911        #[cfg(not(windows))]
2912        assert_eq!(
2913            crate::path_get_dirname(dir_1.canonicalize().unwrap()),
2914            tmp_dir.path()
2915        );
2916        assert!(crate::file_test(
2917            &dir_1,
2918            FileTest::EXISTS | FileTest::IS_DIR
2919        ));
2920        assert!(crate::file_test(
2921            dir_1.canonicalize().unwrap(),
2922            FileTest::EXISTS | FileTest::IS_DIR
2923        ));
2924
2925        // And test with some non-ASCII characters
2926        let dir_2 = tmp_dir.as_ref().join("øäöü");
2927        fs::create_dir(&dir_2).unwrap();
2928        assert_eq!(crate::path_get_basename(&dir_2), Path::new("øäöü"));
2929        assert_eq!(
2930            crate::path_get_basename(dir_2.canonicalize().unwrap()),
2931            Path::new("øäöü")
2932        );
2933        // This currently fails on Windows because C:\\Users\\runneradmin
2934        // gets shortened to C:\\Users\\RUNNER~1
2935        #[cfg(not(windows))]
2936        assert_eq!(
2937            crate::path_get_dirname(dir_2.canonicalize().unwrap()),
2938            tmp_dir.path()
2939        );
2940        assert!(crate::file_test(
2941            &dir_2,
2942            FileTest::EXISTS | FileTest::IS_DIR
2943        ));
2944        assert!(crate::file_test(
2945            dir_2.canonicalize().unwrap(),
2946            FileTest::EXISTS | FileTest::IS_DIR
2947        ));
2948    }
2949
2950    #[test]
2951    #[cfg(target_os = "macos")]
2952    fn test_paths() {
2953        let t_dir = tempdir().unwrap();
2954        let tmp_dir = t_dir.path().canonicalize().unwrap();
2955
2956        // Test if passing paths to GLib and getting them back
2957        // gives us useful results
2958        let dir_1 = tmp_dir.join("abcd");
2959        fs::create_dir(&dir_1).unwrap();
2960        assert_eq!(crate::path_get_basename(&dir_1), Path::new("abcd"));
2961        assert_eq!(
2962            crate::path_get_basename(dir_1.canonicalize().unwrap()),
2963            Path::new("abcd")
2964        );
2965        assert_eq!(
2966            crate::path_get_dirname(dir_1.canonicalize().unwrap()),
2967            tmp_dir
2968        );
2969        assert!(crate::file_test(
2970            &dir_1,
2971            FileTest::EXISTS | FileTest::IS_DIR
2972        ));
2973        assert!(crate::file_test(
2974            &dir_1.canonicalize().unwrap(),
2975            FileTest::EXISTS | FileTest::IS_DIR
2976        ));
2977    }
2978
2979    #[test]
2980    fn none_value() {
2981        const CLONG_NONE: libc::c_long = -1;
2982
2983        #[derive(Debug, PartialEq, Eq)]
2984        struct SpecialU32(u32);
2985        impl IntoGlib for SpecialU32 {
2986            type GlibType = libc::c_uint;
2987            fn into_glib(self) -> libc::c_uint {
2988                self.0 as libc::c_uint
2989            }
2990        }
2991        impl OptionIntoGlib for SpecialU32 {
2992            const GLIB_NONE: Self::GlibType = CLONG_NONE as libc::c_uint;
2993        }
2994
2995        assert_eq!(SpecialU32(0).into_glib(), 0);
2996        assert_eq!(SpecialU32(42).into_glib(), 42);
2997        assert_eq!(Some(SpecialU32(0)).into_glib(), 0);
2998        assert_eq!(Some(SpecialU32(42)).into_glib(), 42);
2999        assert_eq!(
3000            Option::None::<SpecialU32>.into_glib(),
3001            SpecialU32::GLIB_NONE
3002        );
3003
3004        impl TryFromGlib<libc::c_uint> for SpecialU32 {
3005            type Error = GlibNoneError;
3006            #[allow(clippy::unnecessary_cast)]
3007            unsafe fn try_from_glib(val: libc::c_uint) -> Result<Self, GlibNoneError> {
3008                if val == SpecialU32::GLIB_NONE {
3009                    return Err(GlibNoneError);
3010                }
3011
3012                Ok(SpecialU32(val as u32))
3013            }
3014        }
3015
3016        assert_eq!(unsafe { SpecialU32::try_from_glib(0) }, Ok(SpecialU32(0)));
3017        assert_eq!(unsafe { SpecialU32::try_from_glib(42) }, Ok(SpecialU32(42)));
3018        assert_eq!(
3019            unsafe { SpecialU32::try_from_glib(SpecialU32::GLIB_NONE) },
3020            Err(GlibNoneError)
3021        );
3022
3023        assert_eq!(
3024            unsafe { Option::<SpecialU32>::from_glib(0) },
3025            Some(SpecialU32(0))
3026        );
3027        assert_eq!(
3028            unsafe { Option::<SpecialU32>::from_glib(42) },
3029            Some(SpecialU32(42))
3030        );
3031        assert!(unsafe { Option::<SpecialU32>::from_glib(SpecialU32::GLIB_NONE) }.is_none());
3032    }
3033
3034    #[test]
3035    fn invalid_value() {
3036        use std::num::TryFromIntError;
3037
3038        #[derive(Debug, PartialEq, Eq)]
3039        struct U32(u32);
3040
3041        impl TryFromGlib<libc::c_long> for U32 {
3042            type Error = TryFromIntError;
3043            unsafe fn try_from_glib(val: libc::c_long) -> Result<Self, TryFromIntError> {
3044                Ok(U32(u32::try_from(val)?))
3045            }
3046        }
3047
3048        assert_eq!(unsafe { U32::try_from_glib(0) }, Ok(U32(0)));
3049        assert_eq!(unsafe { U32::try_from_glib(42) }, Ok(U32(42)));
3050        assert!(unsafe { U32::try_from_glib(-1) }.is_err());
3051        assert!(unsafe { U32::try_from_glib(-42) }.is_err());
3052    }
3053
3054    #[test]
3055    fn none_or_invalid_value() {
3056        use std::num::TryFromIntError;
3057
3058        #[derive(Debug, PartialEq, Eq)]
3059        struct SpecialU32(u32);
3060        impl IntoGlib for SpecialU32 {
3061            type GlibType = libc::c_long;
3062            fn into_glib(self) -> libc::c_long {
3063                self.0 as libc::c_long
3064            }
3065        }
3066        impl OptionIntoGlib for SpecialU32 {
3067            const GLIB_NONE: Self::GlibType = -1;
3068        }
3069
3070        assert_eq!(SpecialU32(0).into_glib(), 0);
3071        assert_eq!(SpecialU32(42).into_glib(), 42);
3072        assert_eq!(Some(SpecialU32(42)).into_glib(), 42);
3073        assert_eq!(
3074            Option::None::<SpecialU32>.into_glib(),
3075            SpecialU32::GLIB_NONE
3076        );
3077
3078        impl TryFromGlib<libc::c_long> for SpecialU32 {
3079            type Error = GlibNoneOrInvalidError<TryFromIntError>;
3080            unsafe fn try_from_glib(
3081                val: libc::c_long,
3082            ) -> Result<Self, GlibNoneOrInvalidError<TryFromIntError>> {
3083                if val == SpecialU32::GLIB_NONE {
3084                    return Err(GlibNoneOrInvalidError::None);
3085                }
3086
3087                Ok(SpecialU32(u32::try_from(val)?))
3088            }
3089        }
3090
3091        assert_eq!(unsafe { SpecialU32::try_from_glib(0) }, Ok(SpecialU32(0)));
3092        assert_eq!(unsafe { SpecialU32::try_from_glib(42) }, Ok(SpecialU32(42)));
3093        assert!(
3094            unsafe { SpecialU32::try_from_glib(SpecialU32::GLIB_NONE) }
3095                .unwrap_err()
3096                .is_none()
3097        );
3098        assert!(
3099            unsafe { SpecialU32::try_from_glib(-42) }
3100                .unwrap_err()
3101                .is_invalid()
3102        );
3103
3104        assert_eq!(
3105            unsafe { Result::<Option<SpecialU32>, _>::from_glib(0) },
3106            Ok(Some(SpecialU32(0)))
3107        );
3108        assert_eq!(
3109            unsafe { Result::<Option<SpecialU32>, _>::from_glib(42) },
3110            Ok(Some(SpecialU32(42)))
3111        );
3112        assert_eq!(
3113            unsafe { Result::<Option<SpecialU32>, _>::from_glib(SpecialU32::GLIB_NONE) },
3114            Ok(None)
3115        );
3116        assert!(unsafe { Result::<Option<SpecialU32>, _>::from_glib(-42) }.is_err());
3117    }
3118}