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