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    // GLib paths on Windows are always UTF-8, as such we can convert to a String
1751    // first and then go to a PathBuf from there. Unless there is a bug
1752    // in the C library, the conversion from UTF-8 can never fail so we can
1753    // safely panic here if that ever happens
1754    String::from_utf8(CStr::from_ptr(ptr).to_bytes().into())
1755        .expect("Invalid, non-UTF8 path")
1756        .into()
1757}
1758
1759#[cfg(not(windows))]
1760pub(crate) unsafe fn c_to_os_string(ptr: *const c_char) -> OsString {
1761    unsafe {
1762        debug_assert!(!ptr.is_null());
1763
1764        // GLib OS string (environment strings) on UNIX are always in the local encoding,
1765        // which can be UTF-8 or anything else really, but is always a NUL-terminated string
1766        // and must not contain any other NUL bytes
1767        OsString::from_vec(CStr::from_ptr(ptr).to_bytes().to_vec())
1768    }
1769}
1770
1771#[cfg(windows)]
1772pub(crate) unsafe fn c_to_os_string(ptr: *const c_char) -> OsString {
1773    debug_assert!(!ptr.is_null());
1774
1775    // GLib OS string (environment strings) on Windows are always UTF-8,
1776    // as such we can convert to a String
1777    // first and then go to a OsString from there. Unless there is a bug
1778    // in the C library, the conversion from UTF-8 can never fail so we can
1779    // safely panic here if that ever happens
1780    String::from_utf8(CStr::from_ptr(ptr).to_bytes().into())
1781        .expect("Invalid, non-UTF8 path")
1782        .into()
1783}
1784
1785impl FromGlibPtrNone<*const c_char> for PathBuf {
1786    #[inline]
1787    unsafe fn from_glib_none(ptr: *const c_char) -> Self {
1788        unsafe {
1789            debug_assert!(!ptr.is_null());
1790            c_to_path_buf(ptr)
1791        }
1792    }
1793}
1794
1795impl FromGlibPtrFull<*const c_char> for PathBuf {
1796    #[inline]
1797    unsafe fn from_glib_full(ptr: *const c_char) -> Self {
1798        unsafe {
1799            let res = from_glib_none(ptr);
1800            ffi::g_free(ptr as *mut _);
1801            res
1802        }
1803    }
1804}
1805
1806impl FromGlibPtrNone<*mut c_char> for PathBuf {
1807    #[inline]
1808    unsafe fn from_glib_none(ptr: *mut c_char) -> Self {
1809        unsafe {
1810            debug_assert!(!ptr.is_null());
1811            c_to_path_buf(ptr)
1812        }
1813    }
1814}
1815
1816impl FromGlibPtrFull<*mut c_char> for PathBuf {
1817    #[inline]
1818    unsafe fn from_glib_full(ptr: *mut c_char) -> Self {
1819        unsafe {
1820            let res = from_glib_none(ptr);
1821            ffi::g_free(ptr as *mut _);
1822            res
1823        }
1824    }
1825}
1826
1827#[cfg(not(windows))]
1828pub(crate) unsafe fn c_to_path_buf_num(ptr: *const c_char, num: usize) -> PathBuf {
1829    unsafe {
1830        debug_assert!(!ptr.is_null());
1831        let slice = std::slice::from_raw_parts(ptr as *const u8, num);
1832        OsString::from_vec(slice.to_vec()).into()
1833    }
1834}
1835
1836#[cfg(windows)]
1837pub(crate) unsafe fn c_to_path_buf_num(ptr: *const c_char, num: usize) -> PathBuf {
1838    debug_assert!(!ptr.is_null());
1839    let slice = std::slice::from_raw_parts(ptr as *const u8, num);
1840    String::from_utf8(slice.into())
1841        .expect("Invalid, non-UTF8 path")
1842        .into()
1843}
1844
1845#[doc(hidden)]
1846impl FromGlibContainer<*const c_char, *const i8> for PathBuf {
1847    unsafe fn from_glib_none_num(ptr: *const i8, num: usize) -> Self {
1848        unsafe { c_to_path_buf_num(ptr as *const _, num) }
1849    }
1850
1851    unsafe fn from_glib_container_num(ptr: *const i8, num: usize) -> Self {
1852        unsafe { c_to_path_buf_num(ptr as *const _, num) }
1853    }
1854
1855    unsafe fn from_glib_full_num(ptr: *const i8, num: usize) -> Self {
1856        unsafe {
1857            let res = c_to_path_buf_num(ptr as *const _, num);
1858            ffi::g_free(ptr as *mut _);
1859            res
1860        }
1861    }
1862}
1863
1864#[doc(hidden)]
1865impl FromGlibContainer<*const c_char, *mut i8> for PathBuf {
1866    unsafe fn from_glib_none_num(ptr: *mut i8, num: usize) -> Self {
1867        unsafe { FromGlibContainer::from_glib_none_num(ptr as *const i8, num) }
1868    }
1869
1870    unsafe fn from_glib_container_num(ptr: *mut i8, num: usize) -> Self {
1871        unsafe { FromGlibContainer::from_glib_container_num(ptr as *const i8, num) }
1872    }
1873
1874    unsafe fn from_glib_full_num(ptr: *mut i8, num: usize) -> Self {
1875        unsafe { FromGlibContainer::from_glib_full_num(ptr as *const i8, num) }
1876    }
1877}
1878
1879#[doc(hidden)]
1880impl FromGlibContainer<*const c_char, *const u8> for PathBuf {
1881    unsafe fn from_glib_none_num(ptr: *const u8, num: usize) -> Self {
1882        unsafe { FromGlibContainer::from_glib_none_num(ptr as *const i8, num) }
1883    }
1884
1885    unsafe fn from_glib_container_num(ptr: *const u8, num: usize) -> Self {
1886        unsafe { FromGlibContainer::from_glib_container_num(ptr as *const i8, num) }
1887    }
1888
1889    unsafe fn from_glib_full_num(ptr: *const u8, num: usize) -> Self {
1890        unsafe { FromGlibContainer::from_glib_full_num(ptr as *const i8, num) }
1891    }
1892}
1893
1894#[doc(hidden)]
1895impl FromGlibContainer<*const c_char, *mut u8> for PathBuf {
1896    unsafe fn from_glib_none_num(ptr: *mut u8, num: usize) -> Self {
1897        unsafe { FromGlibContainer::from_glib_none_num(ptr as *const i8, num) }
1898    }
1899
1900    unsafe fn from_glib_container_num(ptr: *mut u8, num: usize) -> Self {
1901        unsafe { FromGlibContainer::from_glib_container_num(ptr as *const i8, num) }
1902    }
1903
1904    unsafe fn from_glib_full_num(ptr: *mut u8, num: usize) -> Self {
1905        unsafe { FromGlibContainer::from_glib_full_num(ptr as *const i8, num) }
1906    }
1907}
1908
1909impl FromGlibPtrNone<*const c_char> for OsString {
1910    #[inline]
1911    unsafe fn from_glib_none(ptr: *const c_char) -> Self {
1912        unsafe {
1913            debug_assert!(!ptr.is_null());
1914            c_to_os_string(ptr)
1915        }
1916    }
1917}
1918
1919impl FromGlibPtrFull<*const c_char> for OsString {
1920    #[inline]
1921    unsafe fn from_glib_full(ptr: *const c_char) -> Self {
1922        unsafe {
1923            let res = from_glib_none(ptr);
1924            ffi::g_free(ptr as *mut _);
1925            res
1926        }
1927    }
1928}
1929
1930impl FromGlibPtrNone<*mut c_char> for OsString {
1931    #[inline]
1932    unsafe fn from_glib_none(ptr: *mut c_char) -> Self {
1933        unsafe {
1934            debug_assert!(!ptr.is_null());
1935            c_to_os_string(ptr)
1936        }
1937    }
1938}
1939
1940impl FromGlibPtrFull<*mut c_char> for OsString {
1941    #[inline]
1942    unsafe fn from_glib_full(ptr: *mut c_char) -> Self {
1943        unsafe {
1944            let res = from_glib_none(ptr);
1945            ffi::g_free(ptr as *mut _);
1946            res
1947        }
1948    }
1949}
1950
1951/// Translate from a container.
1952pub trait FromGlibContainer<T, P: Ptr>: Sized {
1953    /// Transfer: none.
1954    ///
1955    /// `num` is the advised number of elements.
1956    unsafe fn from_glib_none_num(ptr: P, num: usize) -> Self;
1957
1958    /// Transfer: container.
1959    ///
1960    /// `num` is the advised number of elements.
1961    unsafe fn from_glib_container_num(ptr: P, num: usize) -> Self;
1962
1963    /// Transfer: full.
1964    ///
1965    /// `num` is the advised number of elements.
1966    unsafe fn from_glib_full_num(ptr: P, num: usize) -> Self;
1967}
1968
1969/// Translate from a container of pointers.
1970pub trait FromGlibPtrContainer<P: Ptr, PP: Ptr>: FromGlibContainer<P, PP> + Sized {
1971    /// Transfer: none.
1972    unsafe fn from_glib_none(ptr: PP) -> Self;
1973
1974    /// Transfer: container.
1975    unsafe fn from_glib_container(ptr: PP) -> Self;
1976
1977    /// Transfer: full.
1978    unsafe fn from_glib_full(ptr: PP) -> Self;
1979}
1980
1981pub unsafe fn c_ptr_array_len<P: Ptr>(mut ptr: *const P) -> usize {
1982    unsafe {
1983        let mut len = 0;
1984
1985        if !ptr.is_null() {
1986            while !(*ptr).is_null() {
1987                len += 1;
1988                ptr = ptr.offset(1);
1989            }
1990        }
1991        len
1992    }
1993}
1994
1995pub trait FromGlibContainerAsVec<T, P: Ptr>
1996where
1997    Self: Sized,
1998{
1999    unsafe fn from_glib_none_num_as_vec(ptr: P, num: usize) -> Vec<Self>;
2000    unsafe fn from_glib_container_num_as_vec(ptr: P, num: usize) -> Vec<Self>;
2001    unsafe fn from_glib_full_num_as_vec(ptr: P, num: usize) -> Vec<Self>;
2002}
2003
2004pub trait FromGlibPtrArrayContainerAsVec<P: Ptr, PP: Ptr>: FromGlibContainerAsVec<P, PP>
2005where
2006    Self: Sized,
2007{
2008    unsafe fn from_glib_none_as_vec(ptr: PP) -> Vec<Self>;
2009    unsafe fn from_glib_container_as_vec(ptr: PP) -> Vec<Self>;
2010    unsafe fn from_glib_full_as_vec(ptr: PP) -> Vec<Self>;
2011}
2012
2013impl FromGlibContainerAsVec<bool, *const ffi::gboolean> for bool {
2014    unsafe fn from_glib_none_num_as_vec(ptr: *const ffi::gboolean, num: usize) -> Vec<Self> {
2015        unsafe {
2016            if num == 0 || ptr.is_null() {
2017                return Vec::new();
2018            }
2019
2020            let mut res = Vec::<Self>::with_capacity(num);
2021            let res_ptr = res.as_mut_ptr();
2022            for i in 0..num {
2023                *res_ptr.add(i) = from_glib(ptr::read(ptr.add(i)));
2024            }
2025            res.set_len(num);
2026            res
2027        }
2028    }
2029
2030    unsafe fn from_glib_container_num_as_vec(_: *const ffi::gboolean, _: usize) -> Vec<Self> {
2031        // Can't really free a *const
2032        unimplemented!();
2033    }
2034
2035    unsafe fn from_glib_full_num_as_vec(_: *const ffi::gboolean, _: usize) -> Vec<Self> {
2036        // Can't really free a *const
2037        unimplemented!();
2038    }
2039}
2040
2041impl FromGlibContainerAsVec<bool, *mut ffi::gboolean> for bool {
2042    unsafe fn from_glib_none_num_as_vec(ptr: *mut ffi::gboolean, num: usize) -> Vec<Self> {
2043        unsafe { FromGlibContainerAsVec::from_glib_none_num_as_vec(ptr as *const _, num) }
2044    }
2045
2046    unsafe fn from_glib_container_num_as_vec(ptr: *mut ffi::gboolean, num: usize) -> Vec<Self> {
2047        unsafe {
2048            let res = FromGlibContainerAsVec::from_glib_none_num_as_vec(ptr, num);
2049            ffi::g_free(ptr as *mut _);
2050            res
2051        }
2052    }
2053
2054    unsafe fn from_glib_full_num_as_vec(ptr: *mut ffi::gboolean, num: usize) -> Vec<Self> {
2055        unsafe { FromGlibContainerAsVec::from_glib_container_num_as_vec(ptr, num) }
2056    }
2057}
2058
2059macro_rules! impl_from_glib_container_as_vec_fundamental {
2060    ($name:ty) => {
2061        unsafe impl TransparentType for $name {
2062            type GlibType = $name;
2063        }
2064
2065        impl FromGlibContainerAsVec<$name, *const $name> for $name {
2066            unsafe fn from_glib_none_num_as_vec(ptr: *const $name, num: usize) -> Vec<Self> {
2067                unsafe {
2068                    if num == 0 || ptr.is_null() {
2069                        return Vec::new();
2070                    }
2071
2072                    let mut res = Vec::with_capacity(num);
2073                    let res_ptr = res.as_mut_ptr();
2074                    std::ptr::copy_nonoverlapping(ptr, res_ptr, num);
2075                    res.set_len(num);
2076                    res
2077                }
2078            }
2079
2080            unsafe fn from_glib_container_num_as_vec(_: *const $name, _: usize) -> Vec<Self> {
2081                // Can't really free a *const
2082                unimplemented!();
2083            }
2084
2085            unsafe fn from_glib_full_num_as_vec(_: *const $name, _: usize) -> Vec<Self> {
2086                // Can't really free a *const
2087                unimplemented!();
2088            }
2089        }
2090
2091        impl FromGlibContainerAsVec<$name, *mut $name> for $name {
2092            unsafe fn from_glib_none_num_as_vec(ptr: *mut $name, num: usize) -> Vec<Self> {
2093                unsafe { FromGlibContainerAsVec::from_glib_none_num_as_vec(ptr as *const _, num) }
2094            }
2095
2096            unsafe fn from_glib_container_num_as_vec(ptr: *mut $name, num: usize) -> Vec<Self> {
2097                unsafe {
2098                    let res = FromGlibContainerAsVec::from_glib_none_num_as_vec(ptr, num);
2099                    ffi::g_free(ptr as *mut _);
2100                    res
2101                }
2102            }
2103
2104            unsafe fn from_glib_full_num_as_vec(ptr: *mut $name, num: usize) -> Vec<Self> {
2105                unsafe { FromGlibContainerAsVec::from_glib_container_num_as_vec(ptr, num) }
2106            }
2107        }
2108    };
2109}
2110
2111impl_from_glib_container_as_vec_fundamental!(u8);
2112impl_from_glib_container_as_vec_fundamental!(i8);
2113impl_from_glib_container_as_vec_fundamental!(u16);
2114impl_from_glib_container_as_vec_fundamental!(i16);
2115impl_from_glib_container_as_vec_fundamental!(u32);
2116impl_from_glib_container_as_vec_fundamental!(i32);
2117impl_from_glib_container_as_vec_fundamental!(u64);
2118impl_from_glib_container_as_vec_fundamental!(i64);
2119impl_from_glib_container_as_vec_fundamental!(f32);
2120impl_from_glib_container_as_vec_fundamental!(f64);
2121
2122macro_rules! impl_from_glib_container_as_vec_string {
2123    ($name:ty, $ffi_name:ty) => {
2124        impl FromGlibContainerAsVec<$ffi_name, *const $ffi_name> for $name {
2125            unsafe fn from_glib_none_num_as_vec(ptr: *const $ffi_name, num: usize) -> Vec<Self> {
2126                unsafe {
2127                    if num == 0 || ptr.is_null() {
2128                        return Vec::new();
2129                    }
2130
2131                    let mut res = Vec::<Self>::with_capacity(num);
2132                    let res_ptr = res.as_mut_ptr();
2133                    for i in 0..num {
2134                        std::ptr::write(
2135                            res_ptr.add(i),
2136                            from_glib_none(ptr::read(ptr.add(i)) as $ffi_name),
2137                        );
2138                    }
2139                    res.set_len(num);
2140                    res
2141                }
2142            }
2143
2144            unsafe fn from_glib_container_num_as_vec(_: *const $ffi_name, _: usize) -> Vec<Self> {
2145                // Can't really free a *const
2146                unimplemented!();
2147            }
2148
2149            unsafe fn from_glib_full_num_as_vec(_: *const $ffi_name, _: usize) -> Vec<Self> {
2150                // Can't really free a *const
2151                unimplemented!();
2152            }
2153        }
2154
2155        impl FromGlibContainerAsVec<$ffi_name, *mut $ffi_name> for $name {
2156            unsafe fn from_glib_none_num_as_vec(ptr: *mut $ffi_name, num: usize) -> Vec<Self> {
2157                unsafe { FromGlibContainerAsVec::from_glib_none_num_as_vec(ptr as *const _, num) }
2158            }
2159
2160            unsafe fn from_glib_container_num_as_vec(ptr: *mut $ffi_name, num: usize) -> Vec<Self> {
2161                unsafe {
2162                    let res = FromGlibContainerAsVec::from_glib_none_num_as_vec(ptr, num);
2163                    ffi::g_free(ptr as *mut _);
2164                    res
2165                }
2166            }
2167
2168            unsafe fn from_glib_full_num_as_vec(ptr: *mut $ffi_name, num: usize) -> Vec<Self> {
2169                unsafe {
2170                    if num == 0 || ptr.is_null() {
2171                        ffi::g_free(ptr as *mut _);
2172                        return Vec::new();
2173                    }
2174
2175                    let mut res = Vec::<Self>::with_capacity(num);
2176                    let res_ptr = res.as_mut_ptr();
2177                    for i in 0..num {
2178                        std::ptr::write(
2179                            res_ptr.add(i),
2180                            from_glib_full(ptr::read(ptr.add(i)) as $ffi_name),
2181                        );
2182                    }
2183                    res.set_len(num);
2184                    ffi::g_free(ptr as *mut _);
2185                    res
2186                }
2187            }
2188        }
2189
2190        impl FromGlibPtrArrayContainerAsVec<$ffi_name, *mut $ffi_name> for $name {
2191            unsafe fn from_glib_none_as_vec(ptr: *mut $ffi_name) -> Vec<Self> {
2192                unsafe {
2193                    FromGlibContainerAsVec::from_glib_none_num_as_vec(ptr, c_ptr_array_len(ptr))
2194                }
2195            }
2196
2197            unsafe fn from_glib_container_as_vec(ptr: *mut $ffi_name) -> Vec<Self> {
2198                unsafe {
2199                    FromGlibContainerAsVec::from_glib_container_num_as_vec(
2200                        ptr,
2201                        c_ptr_array_len(ptr),
2202                    )
2203                }
2204            }
2205
2206            unsafe fn from_glib_full_as_vec(ptr: *mut $ffi_name) -> Vec<Self> {
2207                unsafe {
2208                    FromGlibContainerAsVec::from_glib_full_num_as_vec(ptr, c_ptr_array_len(ptr))
2209                }
2210            }
2211        }
2212
2213        impl FromGlibPtrArrayContainerAsVec<$ffi_name, *const $ffi_name> for $name {
2214            unsafe fn from_glib_none_as_vec(ptr: *const $ffi_name) -> Vec<Self> {
2215                unsafe {
2216                    FromGlibContainerAsVec::from_glib_none_num_as_vec(ptr, c_ptr_array_len(ptr))
2217                }
2218            }
2219
2220            unsafe fn from_glib_container_as_vec(ptr: *const $ffi_name) -> Vec<Self> {
2221                unsafe {
2222                    FromGlibContainerAsVec::from_glib_container_num_as_vec(
2223                        ptr,
2224                        c_ptr_array_len(ptr),
2225                    )
2226                }
2227            }
2228
2229            unsafe fn from_glib_full_as_vec(ptr: *const $ffi_name) -> Vec<Self> {
2230                unsafe {
2231                    FromGlibContainerAsVec::from_glib_full_num_as_vec(ptr, c_ptr_array_len(ptr))
2232                }
2233            }
2234        }
2235    };
2236}
2237
2238// TODO: Deprecate this
2239impl_from_glib_container_as_vec_string!(String, *const c_char);
2240impl_from_glib_container_as_vec_string!(String, *mut c_char);
2241
2242impl_from_glib_container_as_vec_string!(PathBuf, *const c_char);
2243impl_from_glib_container_as_vec_string!(PathBuf, *mut c_char);
2244impl_from_glib_container_as_vec_string!(OsString, *const c_char);
2245impl_from_glib_container_as_vec_string!(OsString, *mut c_char);
2246
2247impl<P, PP: Ptr, T: FromGlibContainerAsVec<P, PP>> FromGlibContainer<P, PP> for Vec<T> {
2248    unsafe fn from_glib_none_num(ptr: PP, num: usize) -> Vec<T> {
2249        unsafe { FromGlibContainerAsVec::from_glib_none_num_as_vec(ptr, num) }
2250    }
2251
2252    unsafe fn from_glib_container_num(ptr: PP, num: usize) -> Vec<T> {
2253        unsafe { FromGlibContainerAsVec::from_glib_container_num_as_vec(ptr, num) }
2254    }
2255
2256    unsafe fn from_glib_full_num(ptr: PP, num: usize) -> Vec<T> {
2257        unsafe { FromGlibContainerAsVec::from_glib_full_num_as_vec(ptr, num) }
2258    }
2259}
2260
2261impl<P: Ptr, PP: Ptr, T: FromGlibPtrArrayContainerAsVec<P, PP>> FromGlibPtrContainer<P, PP>
2262    for Vec<T>
2263{
2264    unsafe fn from_glib_none(ptr: PP) -> Vec<T> {
2265        unsafe { FromGlibPtrArrayContainerAsVec::from_glib_none_as_vec(ptr) }
2266    }
2267
2268    unsafe fn from_glib_container(ptr: PP) -> Vec<T> {
2269        unsafe { FromGlibPtrArrayContainerAsVec::from_glib_container_as_vec(ptr) }
2270    }
2271
2272    unsafe fn from_glib_full(ptr: PP) -> Vec<T> {
2273        unsafe { FromGlibPtrArrayContainerAsVec::from_glib_full_as_vec(ptr) }
2274    }
2275}
2276
2277impl<T> FromGlibContainerAsVec<<T as GlibPtrDefault>::GlibType, *mut ffi::GSList> for T
2278where
2279    T: GlibPtrDefault
2280        + FromGlibPtrNone<<T as GlibPtrDefault>::GlibType>
2281        + FromGlibPtrFull<<T as GlibPtrDefault>::GlibType>,
2282{
2283    unsafe fn from_glib_none_num_as_vec(mut ptr: *mut ffi::GSList, num: usize) -> Vec<T> {
2284        unsafe {
2285            if num == 0 || ptr.is_null() {
2286                return Vec::new();
2287            }
2288            let mut res = Vec::with_capacity(num);
2289            for _ in 0..num {
2290                if ptr.is_null() {
2291                    break;
2292                }
2293
2294                let item_ptr: <T as GlibPtrDefault>::GlibType = Ptr::from((*ptr).data);
2295                if !item_ptr.is_null() {
2296                    res.push(from_glib_none(item_ptr));
2297                }
2298                ptr = (*ptr).next;
2299            }
2300            res
2301        }
2302    }
2303
2304    unsafe fn from_glib_container_num_as_vec(ptr: *mut ffi::GSList, num: usize) -> Vec<T> {
2305        unsafe {
2306            let res = FromGlibContainerAsVec::from_glib_none_num_as_vec(ptr, num);
2307            ffi::g_slist_free(ptr);
2308            res
2309        }
2310    }
2311
2312    unsafe fn from_glib_full_num_as_vec(mut ptr: *mut ffi::GSList, num: usize) -> Vec<T> {
2313        unsafe {
2314            if num == 0 || ptr.is_null() {
2315                return Vec::new();
2316            }
2317            let orig_ptr = ptr;
2318            let mut res = Vec::with_capacity(num);
2319            for _ in 0..num {
2320                if ptr.is_null() {
2321                    break;
2322                }
2323
2324                let item_ptr: <T as GlibPtrDefault>::GlibType = Ptr::from((*ptr).data);
2325                if !item_ptr.is_null() {
2326                    res.push(from_glib_full(item_ptr));
2327                }
2328                ptr = (*ptr).next;
2329            }
2330            ffi::g_slist_free(orig_ptr);
2331            res
2332        }
2333    }
2334}
2335
2336impl<T> FromGlibPtrArrayContainerAsVec<<T as GlibPtrDefault>::GlibType, *mut ffi::GSList> for T
2337where
2338    T: GlibPtrDefault
2339        + FromGlibPtrNone<<T as GlibPtrDefault>::GlibType>
2340        + FromGlibPtrFull<<T as GlibPtrDefault>::GlibType>,
2341{
2342    unsafe fn from_glib_none_as_vec(mut ptr: *mut ffi::GSList) -> Vec<T> {
2343        unsafe {
2344            let mut res = Vec::new();
2345            while !ptr.is_null() {
2346                let item_ptr: <T as GlibPtrDefault>::GlibType = Ptr::from((*ptr).data);
2347                if !item_ptr.is_null() {
2348                    res.push(from_glib_none(item_ptr));
2349                }
2350                ptr = (*ptr).next;
2351            }
2352            res
2353        }
2354    }
2355
2356    unsafe fn from_glib_container_as_vec(ptr: *mut ffi::GSList) -> Vec<T> {
2357        unsafe {
2358            let res = FromGlibPtrArrayContainerAsVec::from_glib_none_as_vec(ptr);
2359            ffi::g_slist_free(ptr);
2360            res
2361        }
2362    }
2363
2364    unsafe fn from_glib_full_as_vec(mut ptr: *mut ffi::GSList) -> Vec<T> {
2365        unsafe {
2366            let orig_ptr = ptr;
2367            let mut res = Vec::new();
2368            while !ptr.is_null() {
2369                let item_ptr: <T as GlibPtrDefault>::GlibType = Ptr::from((*ptr).data);
2370                if !item_ptr.is_null() {
2371                    res.push(from_glib_full(item_ptr));
2372                }
2373                ptr = (*ptr).next;
2374            }
2375            ffi::g_slist_free(orig_ptr);
2376            res
2377        }
2378    }
2379}
2380
2381impl<T> FromGlibContainerAsVec<<T as GlibPtrDefault>::GlibType, *mut ffi::GList> for T
2382where
2383    T: GlibPtrDefault
2384        + FromGlibPtrNone<<T as GlibPtrDefault>::GlibType>
2385        + FromGlibPtrFull<<T as GlibPtrDefault>::GlibType>,
2386{
2387    unsafe fn from_glib_none_num_as_vec(mut ptr: *mut ffi::GList, num: usize) -> Vec<T> {
2388        unsafe {
2389            if num == 0 || ptr.is_null() {
2390                return Vec::new();
2391            }
2392            let mut res = Vec::with_capacity(num);
2393            for _ in 0..num {
2394                if ptr.is_null() {
2395                    break;
2396                }
2397
2398                let item_ptr: <T as GlibPtrDefault>::GlibType = Ptr::from((*ptr).data);
2399                if !item_ptr.is_null() {
2400                    res.push(from_glib_none(item_ptr));
2401                }
2402                ptr = (*ptr).next;
2403            }
2404            res
2405        }
2406    }
2407
2408    unsafe fn from_glib_container_num_as_vec(ptr: *mut ffi::GList, num: usize) -> Vec<T> {
2409        unsafe {
2410            let res = FromGlibContainerAsVec::from_glib_none_num_as_vec(ptr, num);
2411            ffi::g_list_free(ptr);
2412            res
2413        }
2414    }
2415
2416    unsafe fn from_glib_full_num_as_vec(mut ptr: *mut ffi::GList, num: usize) -> Vec<T> {
2417        unsafe {
2418            if num == 0 || ptr.is_null() {
2419                return Vec::new();
2420            }
2421            let orig_ptr = ptr;
2422            let mut res = Vec::with_capacity(num);
2423            for _ in 0..num {
2424                if ptr.is_null() {
2425                    break;
2426                }
2427
2428                let item_ptr: <T as GlibPtrDefault>::GlibType = Ptr::from((*ptr).data);
2429                if !item_ptr.is_null() {
2430                    res.push(from_glib_full(item_ptr));
2431                }
2432                ptr = (*ptr).next;
2433            }
2434            ffi::g_list_free(orig_ptr);
2435            res
2436        }
2437    }
2438}
2439
2440impl<T> FromGlibPtrArrayContainerAsVec<<T as GlibPtrDefault>::GlibType, *mut ffi::GList> for T
2441where
2442    T: GlibPtrDefault
2443        + FromGlibPtrNone<<T as GlibPtrDefault>::GlibType>
2444        + FromGlibPtrFull<<T as GlibPtrDefault>::GlibType>,
2445{
2446    unsafe fn from_glib_none_as_vec(mut ptr: *mut ffi::GList) -> Vec<T> {
2447        unsafe {
2448            let mut res = Vec::new();
2449            while !ptr.is_null() {
2450                let item_ptr: <T as GlibPtrDefault>::GlibType = Ptr::from((*ptr).data);
2451                if !item_ptr.is_null() {
2452                    res.push(from_glib_none(item_ptr));
2453                }
2454                ptr = (*ptr).next;
2455            }
2456            res
2457        }
2458    }
2459
2460    unsafe fn from_glib_container_as_vec(ptr: *mut ffi::GList) -> Vec<T> {
2461        unsafe {
2462            let res = FromGlibPtrArrayContainerAsVec::from_glib_none_as_vec(ptr);
2463            ffi::g_list_free(ptr);
2464            res
2465        }
2466    }
2467
2468    unsafe fn from_glib_full_as_vec(mut ptr: *mut ffi::GList) -> Vec<T> {
2469        unsafe {
2470            let orig_ptr = ptr;
2471            let mut res = Vec::new();
2472            while !ptr.is_null() {
2473                let item_ptr: <T as GlibPtrDefault>::GlibType = Ptr::from((*ptr).data);
2474                if !item_ptr.is_null() {
2475                    res.push(from_glib_full(item_ptr));
2476                }
2477                ptr = (*ptr).next;
2478            }
2479            ffi::g_list_free(orig_ptr);
2480            res
2481        }
2482    }
2483}
2484
2485impl<T> FromGlibContainerAsVec<<T as GlibPtrDefault>::GlibType, *const ffi::GList> for T
2486where
2487    T: GlibPtrDefault
2488        + FromGlibPtrNone<<T as GlibPtrDefault>::GlibType>
2489        + FromGlibPtrFull<<T as GlibPtrDefault>::GlibType>,
2490{
2491    unsafe fn from_glib_none_num_as_vec(ptr: *const ffi::GList, num: usize) -> Vec<T> {
2492        unsafe { FromGlibContainerAsVec::from_glib_none_num_as_vec(mut_override(ptr), num) }
2493    }
2494
2495    unsafe fn from_glib_container_num_as_vec(_: *const ffi::GList, _: usize) -> Vec<T> {
2496        // Can't really free a *const
2497        unimplemented!()
2498    }
2499
2500    unsafe fn from_glib_full_num_as_vec(_: *const ffi::GList, _: usize) -> Vec<T> {
2501        // Can't really free a *const
2502        unimplemented!()
2503    }
2504}
2505
2506impl<T> FromGlibPtrArrayContainerAsVec<<T as GlibPtrDefault>::GlibType, *const ffi::GList> for T
2507where
2508    T: GlibPtrDefault
2509        + FromGlibPtrNone<<T as GlibPtrDefault>::GlibType>
2510        + FromGlibPtrFull<<T as GlibPtrDefault>::GlibType>,
2511{
2512    unsafe fn from_glib_none_as_vec(ptr: *const ffi::GList) -> Vec<T> {
2513        unsafe { FromGlibPtrArrayContainerAsVec::from_glib_none_as_vec(mut_override(ptr)) }
2514    }
2515
2516    unsafe fn from_glib_container_as_vec(_: *const ffi::GList) -> Vec<T> {
2517        // Can't really free a *const
2518        unimplemented!()
2519    }
2520
2521    unsafe fn from_glib_full_as_vec(_: *const ffi::GList) -> Vec<T> {
2522        // Can't really free a *const
2523        unimplemented!()
2524    }
2525}
2526
2527impl<T> FromGlibContainerAsVec<<T as GlibPtrDefault>::GlibType, *const ffi::GSList> for T
2528where
2529    T: GlibPtrDefault
2530        + FromGlibPtrNone<<T as GlibPtrDefault>::GlibType>
2531        + FromGlibPtrFull<<T as GlibPtrDefault>::GlibType>,
2532{
2533    unsafe fn from_glib_none_num_as_vec(ptr: *const ffi::GSList, num: usize) -> Vec<T> {
2534        unsafe { FromGlibContainerAsVec::from_glib_none_num_as_vec(mut_override(ptr), num) }
2535    }
2536
2537    unsafe fn from_glib_container_num_as_vec(_: *const ffi::GSList, _: usize) -> Vec<T> {
2538        // Can't really free a *const
2539        unimplemented!()
2540    }
2541
2542    unsafe fn from_glib_full_num_as_vec(_: *const ffi::GSList, _: usize) -> Vec<T> {
2543        // Can't really free a *const
2544        unimplemented!()
2545    }
2546}
2547
2548impl<T> FromGlibPtrArrayContainerAsVec<<T as GlibPtrDefault>::GlibType, *const ffi::GSList> for T
2549where
2550    T: GlibPtrDefault
2551        + FromGlibPtrNone<<T as GlibPtrDefault>::GlibType>
2552        + FromGlibPtrFull<<T as GlibPtrDefault>::GlibType>,
2553{
2554    unsafe fn from_glib_none_as_vec(ptr: *const ffi::GSList) -> Vec<T> {
2555        unsafe { FromGlibPtrArrayContainerAsVec::from_glib_none_as_vec(mut_override(ptr)) }
2556    }
2557
2558    unsafe fn from_glib_container_as_vec(_: *const ffi::GSList) -> Vec<T> {
2559        // Can't really free a *const
2560        unimplemented!()
2561    }
2562
2563    unsafe fn from_glib_full_as_vec(_: *const ffi::GSList) -> Vec<T> {
2564        // Can't really free a *const
2565        unimplemented!()
2566    }
2567}
2568
2569#[allow(clippy::implicit_hasher)]
2570impl FromGlibContainer<*const c_char, *mut ffi::GHashTable> for HashMap<String, String> {
2571    unsafe fn from_glib_none_num(ptr: *mut ffi::GHashTable, _: usize) -> Self {
2572        unsafe { FromGlibPtrContainer::from_glib_none(ptr) }
2573    }
2574
2575    unsafe fn from_glib_container_num(ptr: *mut ffi::GHashTable, _: usize) -> Self {
2576        unsafe { FromGlibPtrContainer::from_glib_full(ptr) }
2577    }
2578
2579    unsafe fn from_glib_full_num(ptr: *mut ffi::GHashTable, _: usize) -> Self {
2580        unsafe { FromGlibPtrContainer::from_glib_full(ptr) }
2581    }
2582}
2583
2584#[allow(clippy::implicit_hasher)]
2585impl FromGlibPtrContainer<*const c_char, *mut ffi::GHashTable> for HashMap<String, String> {
2586    unsafe fn from_glib_none(ptr: *mut ffi::GHashTable) -> Self {
2587        unsafe {
2588            unsafe extern "C" fn read_string_hash_table(
2589                key: ffi::gpointer,
2590                value: ffi::gpointer,
2591                hash_map: ffi::gpointer,
2592            ) {
2593                unsafe {
2594                    let key: String = from_glib_none(key as *const c_char);
2595                    let value: String = from_glib_none(value as *const c_char);
2596                    let hash_map: &mut HashMap<String, String> =
2597                        &mut *(hash_map as *mut HashMap<String, String>);
2598                    hash_map.insert(key, value);
2599                }
2600            }
2601            let mut map = HashMap::with_capacity(ffi::g_hash_table_size(ptr) as usize);
2602            ffi::g_hash_table_foreach(
2603                ptr,
2604                Some(read_string_hash_table),
2605                &mut map as *mut HashMap<String, String> as *mut _,
2606            );
2607            map
2608        }
2609    }
2610
2611    unsafe fn from_glib_container(ptr: *mut ffi::GHashTable) -> Self {
2612        unsafe { FromGlibPtrContainer::from_glib_full(ptr) }
2613    }
2614
2615    unsafe fn from_glib_full(ptr: *mut ffi::GHashTable) -> Self {
2616        unsafe {
2617            let map = FromGlibPtrContainer::from_glib_none(ptr);
2618            ffi::g_hash_table_unref(ptr);
2619            map
2620        }
2621    }
2622}
2623
2624impl<T> FromGlibContainerAsVec<<T as GlibPtrDefault>::GlibType, *mut ffi::GPtrArray> for T
2625where
2626    T: GlibPtrDefault
2627        + FromGlibPtrNone<<T as GlibPtrDefault>::GlibType>
2628        + FromGlibPtrFull<<T as GlibPtrDefault>::GlibType>,
2629{
2630    unsafe fn from_glib_none_num_as_vec(ptr: *mut ffi::GPtrArray, num: usize) -> Vec<T> {
2631        unsafe {
2632            if num == 0 || ptr.is_null() {
2633                return Vec::new();
2634            }
2635            let pdata = (*ptr).pdata;
2636            debug_assert!((*ptr).len as usize >= num);
2637            let mut res = Vec::with_capacity(num);
2638            for i in 0..num {
2639                let item_ptr: <T as GlibPtrDefault>::GlibType = Ptr::from(ptr::read(pdata.add(i)));
2640                if !item_ptr.is_null() {
2641                    res.push(from_glib_none(item_ptr));
2642                }
2643            }
2644            res
2645        }
2646    }
2647
2648    unsafe fn from_glib_container_num_as_vec(ptr: *mut ffi::GPtrArray, num: usize) -> Vec<T> {
2649        unsafe {
2650            let res = FromGlibContainer::from_glib_none_num(ptr, num);
2651            if !ptr.is_null() {
2652                ffi::g_ptr_array_unref(ptr);
2653            }
2654            res
2655        }
2656    }
2657
2658    unsafe fn from_glib_full_num_as_vec(ptr: *mut ffi::GPtrArray, num: usize) -> Vec<T> {
2659        unsafe {
2660            if ptr.is_null() {
2661                return Vec::new();
2662            }
2663            if num == 0 {
2664                ffi::g_ptr_array_unref(ptr);
2665                return Vec::new();
2666            }
2667            let pdata = (*ptr).pdata;
2668            debug_assert!((*ptr).len as usize >= num);
2669            let mut res = Vec::with_capacity(num);
2670            for i in 0..num {
2671                let item_ptr: <T as GlibPtrDefault>::GlibType = Ptr::from(ptr::read(pdata.add(i)));
2672                if !item_ptr.is_null() {
2673                    res.push(from_glib_none(item_ptr));
2674                }
2675            }
2676            ffi::g_ptr_array_unref(ptr);
2677            res
2678        }
2679    }
2680}
2681
2682impl<T> FromGlibPtrArrayContainerAsVec<<T as GlibPtrDefault>::GlibType, *mut ffi::GPtrArray> for T
2683where
2684    T: GlibPtrDefault
2685        + FromGlibPtrNone<<T as GlibPtrDefault>::GlibType>
2686        + FromGlibPtrFull<<T as GlibPtrDefault>::GlibType>,
2687{
2688    unsafe fn from_glib_none_as_vec(ptr: *mut ffi::GPtrArray) -> Vec<T> {
2689        unsafe {
2690            let num = (*ptr).len as usize;
2691            FromGlibContainer::from_glib_none_num(ptr, num)
2692        }
2693    }
2694
2695    unsafe fn from_glib_container_as_vec(ptr: *mut ffi::GPtrArray) -> Vec<T> {
2696        unsafe {
2697            let num = (*ptr).len as usize;
2698            FromGlibContainer::from_glib_container_num(ptr, num)
2699        }
2700    }
2701
2702    unsafe fn from_glib_full_as_vec(ptr: *mut ffi::GPtrArray) -> Vec<T> {
2703        unsafe {
2704            let num = (*ptr).len as usize;
2705            FromGlibContainer::from_glib_full_num(ptr, num)
2706        }
2707    }
2708}
2709
2710impl<T> FromGlibContainerAsVec<<T as GlibPtrDefault>::GlibType, *const ffi::GPtrArray> for T
2711where
2712    T: GlibPtrDefault
2713        + FromGlibPtrNone<<T as GlibPtrDefault>::GlibType>
2714        + FromGlibPtrFull<<T as GlibPtrDefault>::GlibType>,
2715{
2716    unsafe fn from_glib_none_num_as_vec(ptr: *const ffi::GPtrArray, num: usize) -> Vec<T> {
2717        unsafe { FromGlibContainerAsVec::from_glib_none_num_as_vec(mut_override(ptr), num) }
2718    }
2719
2720    unsafe fn from_glib_container_num_as_vec(_: *const ffi::GPtrArray, _: usize) -> Vec<T> {
2721        // Can't really free a *const
2722        unimplemented!()
2723    }
2724
2725    unsafe fn from_glib_full_num_as_vec(_: *const ffi::GPtrArray, _: usize) -> Vec<T> {
2726        // Can't really free a *const
2727        unimplemented!()
2728    }
2729}
2730
2731impl<T> FromGlibPtrArrayContainerAsVec<<T as GlibPtrDefault>::GlibType, *const ffi::GPtrArray> for T
2732where
2733    T: GlibPtrDefault
2734        + FromGlibPtrNone<<T as GlibPtrDefault>::GlibType>
2735        + FromGlibPtrFull<<T as GlibPtrDefault>::GlibType>,
2736{
2737    unsafe fn from_glib_none_as_vec(ptr: *const ffi::GPtrArray) -> Vec<T> {
2738        unsafe { FromGlibPtrArrayContainerAsVec::from_glib_none_as_vec(mut_override(ptr)) }
2739    }
2740
2741    unsafe fn from_glib_container_as_vec(_: *const ffi::GPtrArray) -> Vec<T> {
2742        // Can't really free a *const
2743        unimplemented!()
2744    }
2745
2746    unsafe fn from_glib_full_as_vec(_: *const ffi::GPtrArray) -> Vec<T> {
2747        // Can't really free a *const
2748        unimplemented!()
2749    }
2750}
2751
2752/// Trait for types that have the same memory representation as a pointer to their FFI type.
2753///
2754/// Values of types implementing this trait can be transmuted to pointers of the FFI type,
2755/// references to pointers of pointers to the FFI type.
2756pub unsafe trait TransparentPtrType: Clone + Sized + GlibPtrDefault {}
2757
2758/// Trait for types that have the same memory representation as their FFI type.
2759///
2760/// Values of types implementing this trait can be transmuted directly to the FFI type, references
2761/// to pointers to the FFI type.
2762pub unsafe trait TransparentType: Clone + Sized {
2763    type GlibType;
2764}
2765
2766unsafe impl<T: TransparentPtrType> TransparentType for T {
2767    type GlibType = <T as GlibPtrDefault>::GlibType;
2768}
2769
2770#[cfg(test)]
2771mod tests {
2772    use std::{collections::HashMap, fs};
2773
2774    use tempfile::tempdir;
2775
2776    use super::*;
2777    use crate::{FileTest, GString};
2778
2779    #[test]
2780    fn boolean() {
2781        assert_eq!(true.into_glib(), ffi::GTRUE);
2782        assert_eq!(false.into_glib(), ffi::GFALSE);
2783        assert!(unsafe { bool::from_glib(ffi::GTRUE) });
2784        assert!(!unsafe { bool::from_glib(ffi::GFALSE) });
2785        assert!(unsafe { bool::from_glib(42) });
2786    }
2787
2788    #[test]
2789    fn ordering() {
2790        assert_eq!(Ordering::Less.into_glib(), -1);
2791        assert_eq!(Ordering::Equal.into_glib(), 0);
2792        assert_eq!(Ordering::Greater.into_glib(), 1);
2793        assert_eq!(Ordering::Less, unsafe { Ordering::from_glib(-42) });
2794        assert_eq!(Ordering::Less, unsafe { Ordering::from_glib(-1) });
2795        assert_eq!(Ordering::Equal, unsafe { Ordering::from_glib(0) });
2796        assert_eq!(Ordering::Greater, unsafe { Ordering::from_glib(1) });
2797        assert_eq!(Ordering::Greater, unsafe { Ordering::from_glib(42) });
2798    }
2799
2800    #[test]
2801    fn string() {
2802        let s = "ABC";
2803        let owned = "ABC".to_string();
2804        let cstring = CString::new("ABC").unwrap();
2805
2806        let stash = s.to_glib_none();
2807        assert_eq!(unsafe { CStr::from_ptr(stash.0) }, cstring.as_c_str());
2808
2809        let stash = owned.to_glib_none();
2810        assert_eq!(unsafe { CStr::from_ptr(stash.0) }, cstring.as_c_str());
2811
2812        let ptr: *mut c_char = s.to_glib_full();
2813        assert_eq!(unsafe { CStr::from_ptr(ptr) }, cstring.as_c_str());
2814
2815        unsafe {
2816            ffi::g_free(ptr as *mut _);
2817        }
2818
2819        let ptr: *mut c_char = owned.to_glib_full();
2820        assert_eq!(unsafe { CStr::from_ptr(ptr) }, cstring.as_c_str());
2821
2822        assert_eq!(s, unsafe { String::from_glib_none(ptr) });
2823        assert_eq!(owned, unsafe { String::from_glib_full(ptr) });
2824    }
2825
2826    #[test]
2827    fn string_hash_map() {
2828        let mut map = HashMap::new();
2829        map.insert("A".into(), "1".into());
2830        map.insert("B".into(), "2".into());
2831        map.insert("C".into(), "3".into());
2832        let ptr: *mut ffi::GHashTable = map.to_glib_full();
2833        let map = unsafe { HashMap::from_glib_full(ptr) };
2834        assert_eq!(map.get("A"), Some(&"1".into()));
2835        assert_eq!(map.get("B"), Some(&"2".into()));
2836        assert_eq!(map.get("C"), Some(&"3".into()));
2837    }
2838
2839    #[test]
2840    fn string_array() {
2841        let v = vec!["A".to_string(), "B".to_string(), "C".to_string()];
2842        let stash = v.to_glib_none();
2843        let ptr: *mut *mut c_char = stash.0;
2844        let ptr_copy = unsafe { ffi::g_strdupv(ptr) };
2845
2846        let actual: Vec<String> = unsafe { FromGlibPtrContainer::from_glib_full(ptr_copy) };
2847        assert_eq!(v, actual);
2848    }
2849
2850    #[test]
2851    fn gstring_array() {
2852        let v = vec!["A".to_string(), "B".to_string(), "C".to_string()];
2853        let stash = v.to_glib_none();
2854        let ptr: *mut *mut c_char = stash.0;
2855        let ptr_copy = unsafe { ffi::g_strdupv(ptr) };
2856
2857        let actual: Vec<GString> = unsafe { FromGlibPtrContainer::from_glib_full(ptr_copy) };
2858        assert_eq!(v, actual);
2859    }
2860
2861    #[test]
2862    fn ptr_array() {
2863        let strings = &["A", "B", "C"];
2864        let (ptr, _stash) =
2865            ToGlibContainerFromSlice::<*mut ffi::GPtrArray>::to_glib_none_from_slice(strings);
2866        let v: Vec<GString> = unsafe { FromGlibPtrArrayContainerAsVec::from_glib_none_as_vec(ptr) };
2867        assert_eq!(&v, strings);
2868    }
2869
2870    #[test]
2871    #[cfg(not(target_os = "macos"))]
2872    fn test_paths() {
2873        let tmp_dir = tempdir().unwrap();
2874
2875        // Test if passing paths to GLib and getting them back
2876        // gives us useful results
2877        let dir_1 = tmp_dir.path().join("abcd");
2878        fs::create_dir(&dir_1).unwrap();
2879        assert_eq!(crate::path_get_basename(&dir_1), Path::new("abcd"));
2880        assert_eq!(
2881            crate::path_get_basename(dir_1.canonicalize().unwrap()),
2882            Path::new("abcd")
2883        );
2884        // This currently fails on Windows because C:\\Users\\runneradmin
2885        // gets shortened to C:\\Users\\RUNNER~1
2886        #[cfg(not(windows))]
2887        assert_eq!(
2888            crate::path_get_dirname(dir_1.canonicalize().unwrap()),
2889            tmp_dir.path()
2890        );
2891        assert!(crate::file_test(
2892            &dir_1,
2893            FileTest::EXISTS | FileTest::IS_DIR
2894        ));
2895        assert!(crate::file_test(
2896            dir_1.canonicalize().unwrap(),
2897            FileTest::EXISTS | FileTest::IS_DIR
2898        ));
2899
2900        // And test with some non-ASCII characters
2901        let dir_2 = tmp_dir.as_ref().join("øäöü");
2902        fs::create_dir(&dir_2).unwrap();
2903        assert_eq!(crate::path_get_basename(&dir_2), Path::new("øäöü"));
2904        assert_eq!(
2905            crate::path_get_basename(dir_2.canonicalize().unwrap()),
2906            Path::new("øäöü")
2907        );
2908        // This currently fails on Windows because C:\\Users\\runneradmin
2909        // gets shortened to C:\\Users\\RUNNER~1
2910        #[cfg(not(windows))]
2911        assert_eq!(
2912            crate::path_get_dirname(dir_2.canonicalize().unwrap()),
2913            tmp_dir.path()
2914        );
2915        assert!(crate::file_test(
2916            &dir_2,
2917            FileTest::EXISTS | FileTest::IS_DIR
2918        ));
2919        assert!(crate::file_test(
2920            dir_2.canonicalize().unwrap(),
2921            FileTest::EXISTS | FileTest::IS_DIR
2922        ));
2923    }
2924
2925    #[test]
2926    #[cfg(target_os = "macos")]
2927    fn test_paths() {
2928        let t_dir = tempdir().unwrap();
2929        let tmp_dir = t_dir.path().canonicalize().unwrap();
2930
2931        // Test if passing paths to GLib and getting them back
2932        // gives us useful results
2933        let dir_1 = tmp_dir.join("abcd");
2934        fs::create_dir(&dir_1).unwrap();
2935        assert_eq!(crate::path_get_basename(&dir_1), Path::new("abcd"));
2936        assert_eq!(
2937            crate::path_get_basename(dir_1.canonicalize().unwrap()),
2938            Path::new("abcd")
2939        );
2940        assert_eq!(
2941            crate::path_get_dirname(dir_1.canonicalize().unwrap()),
2942            tmp_dir
2943        );
2944        assert!(crate::file_test(
2945            &dir_1,
2946            FileTest::EXISTS | FileTest::IS_DIR
2947        ));
2948        assert!(crate::file_test(
2949            &dir_1.canonicalize().unwrap(),
2950            FileTest::EXISTS | FileTest::IS_DIR
2951        ));
2952    }
2953
2954    #[test]
2955    fn none_value() {
2956        const CLONG_NONE: libc::c_long = -1;
2957
2958        #[derive(Debug, PartialEq, Eq)]
2959        struct SpecialU32(u32);
2960        impl IntoGlib for SpecialU32 {
2961            type GlibType = libc::c_uint;
2962            fn into_glib(self) -> libc::c_uint {
2963                self.0 as libc::c_uint
2964            }
2965        }
2966        impl OptionIntoGlib for SpecialU32 {
2967            const GLIB_NONE: Self::GlibType = CLONG_NONE as libc::c_uint;
2968        }
2969
2970        assert_eq!(SpecialU32(0).into_glib(), 0);
2971        assert_eq!(SpecialU32(42).into_glib(), 42);
2972        assert_eq!(Some(SpecialU32(0)).into_glib(), 0);
2973        assert_eq!(Some(SpecialU32(42)).into_glib(), 42);
2974        assert_eq!(
2975            Option::None::<SpecialU32>.into_glib(),
2976            SpecialU32::GLIB_NONE
2977        );
2978
2979        impl TryFromGlib<libc::c_uint> for SpecialU32 {
2980            type Error = GlibNoneError;
2981            #[allow(clippy::unnecessary_cast)]
2982            unsafe fn try_from_glib(val: libc::c_uint) -> Result<Self, GlibNoneError> {
2983                if val == SpecialU32::GLIB_NONE {
2984                    return Err(GlibNoneError);
2985                }
2986
2987                Ok(SpecialU32(val as u32))
2988            }
2989        }
2990
2991        assert_eq!(unsafe { SpecialU32::try_from_glib(0) }, Ok(SpecialU32(0)));
2992        assert_eq!(unsafe { SpecialU32::try_from_glib(42) }, Ok(SpecialU32(42)));
2993        assert_eq!(
2994            unsafe { SpecialU32::try_from_glib(SpecialU32::GLIB_NONE) },
2995            Err(GlibNoneError)
2996        );
2997
2998        assert_eq!(
2999            unsafe { Option::<SpecialU32>::from_glib(0) },
3000            Some(SpecialU32(0))
3001        );
3002        assert_eq!(
3003            unsafe { Option::<SpecialU32>::from_glib(42) },
3004            Some(SpecialU32(42))
3005        );
3006        assert!(unsafe { Option::<SpecialU32>::from_glib(SpecialU32::GLIB_NONE) }.is_none());
3007    }
3008
3009    #[test]
3010    fn invalid_value() {
3011        use std::num::TryFromIntError;
3012
3013        #[derive(Debug, PartialEq, Eq)]
3014        struct U32(u32);
3015
3016        impl TryFromGlib<libc::c_long> for U32 {
3017            type Error = TryFromIntError;
3018            unsafe fn try_from_glib(val: libc::c_long) -> Result<Self, TryFromIntError> {
3019                Ok(U32(u32::try_from(val)?))
3020            }
3021        }
3022
3023        assert_eq!(unsafe { U32::try_from_glib(0) }, Ok(U32(0)));
3024        assert_eq!(unsafe { U32::try_from_glib(42) }, Ok(U32(42)));
3025        assert!(unsafe { U32::try_from_glib(-1) }.is_err());
3026        assert!(unsafe { U32::try_from_glib(-42) }.is_err());
3027    }
3028
3029    #[test]
3030    fn none_or_invalid_value() {
3031        use std::num::TryFromIntError;
3032
3033        #[derive(Debug, PartialEq, Eq)]
3034        struct SpecialU32(u32);
3035        impl IntoGlib for SpecialU32 {
3036            type GlibType = libc::c_long;
3037            fn into_glib(self) -> libc::c_long {
3038                self.0 as libc::c_long
3039            }
3040        }
3041        impl OptionIntoGlib for SpecialU32 {
3042            const GLIB_NONE: Self::GlibType = -1;
3043        }
3044
3045        assert_eq!(SpecialU32(0).into_glib(), 0);
3046        assert_eq!(SpecialU32(42).into_glib(), 42);
3047        assert_eq!(Some(SpecialU32(42)).into_glib(), 42);
3048        assert_eq!(
3049            Option::None::<SpecialU32>.into_glib(),
3050            SpecialU32::GLIB_NONE
3051        );
3052
3053        impl TryFromGlib<libc::c_long> for SpecialU32 {
3054            type Error = GlibNoneOrInvalidError<TryFromIntError>;
3055            unsafe fn try_from_glib(
3056                val: libc::c_long,
3057            ) -> Result<Self, GlibNoneOrInvalidError<TryFromIntError>> {
3058                if val == SpecialU32::GLIB_NONE {
3059                    return Err(GlibNoneOrInvalidError::None);
3060                }
3061
3062                Ok(SpecialU32(u32::try_from(val)?))
3063            }
3064        }
3065
3066        assert_eq!(unsafe { SpecialU32::try_from_glib(0) }, Ok(SpecialU32(0)));
3067        assert_eq!(unsafe { SpecialU32::try_from_glib(42) }, Ok(SpecialU32(42)));
3068        assert!(
3069            unsafe { SpecialU32::try_from_glib(SpecialU32::GLIB_NONE) }
3070                .unwrap_err()
3071                .is_none()
3072        );
3073        assert!(
3074            unsafe { SpecialU32::try_from_glib(-42) }
3075                .unwrap_err()
3076                .is_invalid()
3077        );
3078
3079        assert_eq!(
3080            unsafe { Result::<Option<SpecialU32>, _>::from_glib(0) },
3081            Ok(Some(SpecialU32(0)))
3082        );
3083        assert_eq!(
3084            unsafe { Result::<Option<SpecialU32>, _>::from_glib(42) },
3085            Ok(Some(SpecialU32(42)))
3086        );
3087        assert_eq!(
3088            unsafe { Result::<Option<SpecialU32>, _>::from_glib(SpecialU32::GLIB_NONE) },
3089            Ok(None)
3090        );
3091        assert!(unsafe { Result::<Option<SpecialU32>, _>::from_glib(-42) }.is_err());
3092    }
3093}