Skip to main content

glib/
translate.rs

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