glib/
translate.rs

1// Copyright 2015, The Gtk-rs Project Developers.
2// See the COPYRIGHT file at the top-level directory of this distribution.
3// Licensed under the MIT license, see the LICENSE file or <http://opensource.org/licenses/MIT>
4
5//! Translation between GLib/GLib-based FFI types and their Rust counterparts.
6//!
7//! This module allows library bindings authors to decouple type translation
8//! logic and use unified idioms at FFI boundaries. It also implements
9//! translation of GLib core data types.
10//!
11//! `FromGlib`, `from_glib` and `ToGlib` translate simple types like `bool`.
12//!
13//! ```ignore
14//!     pub fn set_accept_focus(&self, accept_focus: bool) {
15//!         unsafe { gdk_sys::gdk_window_set_accept_focus(self.pointer, accept_focus.to_glib()) }
16//!     }
17//!
18//!     pub fn get_accept_focus(&self) -> bool {
19//!         unsafe { from_glib(gdk_sys::gdk_window_get_accept_focus(self.pointer)) }
20//!     }
21//! ```
22//!
23//! `ToGlibPtr`, `FromGlibPtrNone`, `FromGlibPtrFull` and `FromGlibPtrBorrow` work on `gpointer`s
24//! and support different modes of ownership transfer.
25//!
26//! ```ignore
27//!     fn get_title(&self) -> Option<String> {
28//!         unsafe {
29//!             let title = gtk_sys::gtk_window_get_title(self.pointer);
30//!             from_glib_none(title)
31//!         }
32//!     }
33//! ```
34//!
35//! Letting the foreign library borrow pointers from the Rust side often
36//! requires having a temporary variable of an intermediate type (e.g. `CString`).
37//! A `Stash` contains the temporary storage and a pointer into it that
38//! is valid for the lifetime of the `Stash`. As the lifetime of the `Stash` returned
39//! from `to_glib_none` is at least the enclosing statement, you can avoid explicitly
40//! binding the stash in most cases and just take the pointer out of it:
41//!
42//! ```ignore
43//!     pub fn set_icon_name(&self, name: &str) {
44//!         unsafe {
45//!             gdk_sys::gdk_window_set_icon_name(self.pointer, name.to_glib_none().0)
46//!         }
47//!     }
48//! ```
49
50use glib_sys;
51use libc::{c_char, size_t};
52use std::char;
53use std::cmp::Ordering;
54use std::collections::HashMap;
55use std::ffi::{CStr, CString};
56use std::ffi::{OsStr, OsString};
57use std::mem;
58#[cfg(not(windows))]
59use std::os::unix::prelude::*;
60use std::path::{Path, PathBuf};
61use std::ptr;
62
63/// A pointer
64pub trait Ptr: Copy + 'static {
65    fn is_null(&self) -> bool;
66    fn from<X>(ptr: *mut X) -> Self;
67    fn to<X>(self) -> *mut X;
68}
69
70impl<T: 'static> Ptr for *const T {
71    #[inline]
72    fn is_null(&self) -> bool {
73        (*self).is_null()
74    }
75
76    #[inline]
77    fn from<X>(ptr: *mut X) -> *const T {
78        ptr as *const T
79    }
80
81    #[inline]
82    fn to<X>(self) -> *mut X {
83        self as *mut X
84    }
85}
86
87impl<T: 'static> Ptr for *mut T {
88    #[inline]
89    fn is_null(&self) -> bool {
90        (*self).is_null()
91    }
92
93    #[inline]
94    fn from<X>(ptr: *mut X) -> *mut T {
95        ptr as *mut T
96    }
97
98    #[inline]
99    fn to<X>(self) -> *mut X {
100        self as *mut X
101    }
102}
103
104/// Overrides pointer mutability.
105///
106/// Use when the C API should be specifying a const pointer but doesn't.
107pub fn mut_override<T>(ptr: *const T) -> *mut T {
108    ptr as *mut T
109}
110
111/// Overrides pointer constness.
112///
113/// Use when the C API need const pointer, but function with `IsA<T>` constraint,
114/// that usaly don't have const pointer conversion.
115pub fn const_override<T>(ptr: *mut T) -> *const T {
116    ptr as *const T
117}
118
119/// A trait for creating an uninitialized value. Handy for receiving outparams.
120pub trait Uninitialized {
121    /// Returns an uninitialized value.
122    unsafe fn uninitialized() -> Self;
123}
124
125/// Returns an uninitialized value.
126#[inline]
127pub unsafe fn uninitialized<T: Uninitialized>() -> T {
128    T::uninitialized()
129}
130
131pub trait ToBool: Copy {
132    fn to_bool(self) -> bool;
133}
134
135impl ToBool for bool {
136    #[inline]
137    fn to_bool(self) -> bool {
138        self
139    }
140}
141
142impl ToBool for glib_sys::gboolean {
143    #[inline]
144    fn to_bool(self) -> bool {
145        self != glib_sys::GFALSE
146    }
147}
148
149/// Returns `Some(val)` if the condition is true and `None` otherwise.
150#[inline]
151pub fn some_if<B: ToBool, T, F: FnOnce() -> T>(cond: B, f: F) -> Option<T> {
152    if cond.to_bool() {
153        Some(f())
154    } else {
155        None
156    }
157}
158
159/// Helper type that stores temporary values used for translation.
160///
161/// `P` is the foreign type pointer and the first element of the tuple.
162///
163/// `T` is the Rust type that is translated.
164///
165/// The second element of the tuple is the temporary storage defined
166/// by the implementation of `ToGlibPtr<P> for T`
167///
168/// Say you want to pass a `*mut GdkWindowAttr` to a foreign function. The `Stash`
169/// will own a `GdkWindowAttr` and a `CString` that `GdkWindowAttr::title` points into.
170///
171/// ```ignore
172/// impl <'a> ToGlibPtr<'a, *mut glib_sys::GdkWindowAttr> for WindowAttr {
173///     type Storage = (Box<glib_sys::GdkWindowAttr>, Stash<'a, *const c_char, Option<String>>);
174///
175///     fn to_glib_none(&'a self) -> Stash<*mut glib_sys::GdkWindowAttr, WindowAttr> {
176///         let title = self.title.to_glib_none();
177///
178///         let mut attrs = Box::new(glib_sys::GdkWindowAttr {
179///             title: title.0,
180///             // ....
181///         });
182///
183///         Stash(&mut *attrs, (attrs, title))
184///     }
185/// }
186/// ```
187pub struct Stash<'a, P: Copy, T: ?Sized + ToGlibPtr<'a, P>>(
188    pub P,
189    pub <T as ToGlibPtr<'a, P>>::Storage,
190);
191
192pub struct StashMut<'a, P: Copy, T: ?Sized>(pub P, pub <T as ToGlibPtrMut<'a, P>>::Storage)
193where
194    T: ToGlibPtrMut<'a, P>;
195
196/// Translate a simple type.
197pub trait ToGlib {
198    type GlibType;
199
200    fn to_glib(&self) -> Self::GlibType;
201}
202
203impl ToGlib for bool {
204    type GlibType = glib_sys::gboolean;
205
206    #[inline]
207    fn to_glib(&self) -> glib_sys::gboolean {
208        if *self {
209            glib_sys::GTRUE
210        } else {
211            glib_sys::GFALSE
212        }
213    }
214}
215
216impl ToGlib for char {
217    type GlibType = u32;
218
219    #[inline]
220    fn to_glib(&self) -> u32 {
221        *self as u32
222    }
223}
224
225impl ToGlib for Option<char> {
226    type GlibType = u32;
227
228    #[inline]
229    fn to_glib(&self) -> u32 {
230        self.as_ref().map(|&c| c as u32).unwrap_or(0)
231    }
232}
233
234impl ToGlib for Ordering {
235    type GlibType = i32;
236
237    #[inline]
238    fn to_glib(&self) -> i32 {
239        match *self {
240            Ordering::Less => -1,
241            Ordering::Equal => 0,
242            Ordering::Greater => 1,
243        }
244    }
245}
246
247/// Provides the default pointer type to be used in some container conversions.
248///
249/// It's `*mut c_char` for `String`, `*mut GtkButton` for `gtk::Button`, etc.
250pub trait GlibPtrDefault {
251    type GlibType: Ptr;
252}
253
254impl<'a, T: ?Sized + GlibPtrDefault> GlibPtrDefault for &'a T {
255    type GlibType = <T as GlibPtrDefault>::GlibType;
256}
257
258/// Translate to a pointer.
259pub trait ToGlibPtr<'a, P: Copy> {
260    type Storage;
261
262    /// Transfer: none.
263    ///
264    /// The pointer in the `Stash` is only valid for the lifetime of the `Stash`.
265    fn to_glib_none(&'a self) -> Stash<'a, P, Self>;
266
267    /// Transfer: container.
268    ///
269    /// We transfer the container ownership to the foreign library retaining
270    /// the elements ownership.
271    fn to_glib_container(&'a self) -> Stash<'a, P, Self> {
272        unimplemented!();
273    }
274
275    /// Transfer: full.
276    ///
277    /// We transfer the ownership to the foreign library.
278    fn to_glib_full(&self) -> P {
279        unimplemented!();
280    }
281}
282///
283/// Translate to a pointer with a mutable borrow.
284pub trait ToGlibPtrMut<'a, P: Copy> {
285    type Storage;
286
287    /// Transfer: none.
288    ///
289    /// The pointer in the `Stash` is only valid for the lifetime of the `Stash`.
290    fn to_glib_none_mut(&'a mut self) -> StashMut<P, Self>;
291}
292
293impl<'a, P: Ptr, T: ToGlibPtr<'a, P>> ToGlibPtr<'a, P> for Option<T> {
294    type Storage = Option<<T as ToGlibPtr<'a, P>>::Storage>;
295
296    #[inline]
297    fn to_glib_none(&'a self) -> Stash<'a, P, Option<T>> {
298        self.as_ref()
299            .map_or(Stash(Ptr::from::<()>(ptr::null_mut()), None), |s| {
300                let s = s.to_glib_none();
301                Stash(s.0, Some(s.1))
302            })
303    }
304
305    #[inline]
306    fn to_glib_full(&self) -> P {
307        self.as_ref()
308            .map_or(Ptr::from::<()>(ptr::null_mut()), ToGlibPtr::to_glib_full)
309    }
310}
311
312impl<'a, 'opt: 'a, P: Ptr, T: ToGlibPtrMut<'a, P>> ToGlibPtrMut<'a, P> for Option<&'opt mut T> {
313    type Storage = Option<<T as ToGlibPtrMut<'a, P>>::Storage>;
314
315    #[inline]
316    fn to_glib_none_mut(&'a mut self) -> StashMut<'a, P, Option<&'opt mut T>> {
317        self.as_mut()
318            .map_or(StashMut(Ptr::from::<()>(ptr::null_mut()), None), |s| {
319                let s = s.to_glib_none_mut();
320                StashMut(s.0, Some(s.1))
321            })
322    }
323}
324
325impl<'a, P: Ptr, T: ?Sized + ToGlibPtr<'a, P>> ToGlibPtr<'a, P> for &'a T {
326    type Storage = <T as ToGlibPtr<'a, P>>::Storage;
327
328    #[inline]
329    fn to_glib_none(&'a self) -> Stash<'a, P, Self> {
330        let s = (*self).to_glib_none();
331        Stash(s.0, s.1)
332    }
333
334    #[inline]
335    fn to_glib_full(&self) -> P {
336        (*self).to_glib_full()
337    }
338}
339
340impl<'a> ToGlibPtr<'a, *const c_char> for str {
341    type Storage = CString;
342
343    #[inline]
344    fn to_glib_none(&'a self) -> Stash<'a, *const c_char, Self> {
345        let tmp =
346            CString::new(self).expect("str::ToGlibPtr<*const c_char>: unexpected '\0' character");
347        Stash(tmp.as_ptr(), tmp)
348    }
349
350    #[inline]
351    fn to_glib_full(&self) -> *const c_char {
352        unsafe {
353            glib_sys::g_strndup(self.as_ptr() as *const c_char, self.len() as size_t)
354                as *const c_char
355        }
356    }
357}
358
359impl<'a> ToGlibPtr<'a, *mut c_char> for str {
360    type Storage = CString;
361
362    #[inline]
363    fn to_glib_none(&'a self) -> Stash<'a, *mut c_char, Self> {
364        let tmp =
365            CString::new(self).expect("str::ToGlibPtr<*mut c_char>: unexpected '\0' character");
366        Stash(tmp.as_ptr() as *mut c_char, tmp)
367    }
368
369    #[inline]
370    fn to_glib_full(&self) -> *mut c_char {
371        unsafe { glib_sys::g_strndup(self.as_ptr() as *mut c_char, self.len() as size_t) }
372    }
373}
374
375impl<'a> ToGlibPtr<'a, *const c_char> for String {
376    type Storage = CString;
377
378    #[inline]
379    fn to_glib_none(&self) -> Stash<'a, *const c_char, String> {
380        let tmp = CString::new(&self[..])
381            .expect("String::ToGlibPtr<*const c_char>: unexpected '\0' character");
382        Stash(tmp.as_ptr(), tmp)
383    }
384
385    #[inline]
386    fn to_glib_full(&self) -> *const c_char {
387        unsafe {
388            glib_sys::g_strndup(self.as_ptr() as *const c_char, self.len() as size_t)
389                as *const c_char
390        }
391    }
392}
393
394impl<'a> ToGlibPtr<'a, *mut c_char> for String {
395    type Storage = CString;
396
397    #[inline]
398    fn to_glib_none(&self) -> Stash<'a, *mut c_char, String> {
399        let tmp = CString::new(&self[..])
400            .expect("String::ToGlibPtr<*mut c_char>: unexpected '\0' character");
401        Stash(tmp.as_ptr() as *mut c_char, tmp)
402    }
403
404    #[inline]
405    fn to_glib_full(&self) -> *mut c_char {
406        unsafe {
407            glib_sys::g_strndup(self.as_ptr() as *const c_char, self.len() as size_t) as *mut c_char
408        }
409    }
410}
411
412impl GlibPtrDefault for str {
413    type GlibType = *mut c_char;
414}
415
416impl GlibPtrDefault for String {
417    type GlibType = *mut c_char;
418}
419
420#[cfg(not(windows))]
421fn path_to_c(path: &Path) -> CString {
422    // GLib paths on UNIX are always in the local encoding, just like in Rust
423    //
424    // Paths on UNIX must not contain NUL bytes, in which case the conversion
425    // to a CString would fail. The only thing we can do then is to panic, as passing
426    // NULL or the empty string to GLib would cause undefined behaviour.
427    CString::new(path.as_os_str().as_bytes()).expect("Invalid path with NUL bytes")
428}
429
430#[cfg(windows)]
431fn path_to_c(path: &Path) -> CString {
432    // GLib paths are always UTF-8 strings on Windows, while in Rust they are
433    // WTF-8. As such, we need to convert to a UTF-8 string. This conversion can
434    // fail, see https://simonsapin.github.io/wtf-8/#converting-wtf-8-utf-8
435    //
436    // It's not clear what we're supposed to do if it fails: the path is not
437    // representable in UTF-8 and thus can't possibly be passed to GLib.
438    // Passing NULL or the empty string to GLib can lead to undefined behaviour, so
439    // the only safe option seems to be to simply panic here.
440    let path_str = path
441        .to_str()
442        .expect("Path can't be represented as UTF-8")
443        .to_owned();
444
445    // On Windows, paths can have \\?\ prepended for long-path support. See
446    // MSDN documentation about CreateFile
447    //
448    // We have to get rid of this and let GLib take care of all these
449    // weirdnesses later
450    if path_str.starts_with("\\\\?\\") {
451        CString::new(path_str[4..].as_bytes())
452    } else {
453        CString::new(path_str.as_bytes())
454    }
455    .expect("Invalid path with NUL bytes")
456}
457
458#[cfg(not(windows))]
459fn os_str_to_c(s: &OsStr) -> CString {
460    // GLib OS string (environment strings) on UNIX are always in the local encoding,
461    // just like in Rust
462    //
463    // OS string on UNIX must not contain NUL bytes, in which case the conversion
464    // to a CString would fail. The only thing we can do then is to panic, as passing
465    // NULL or the empty string to GLib would cause undefined behaviour.
466    CString::new(s.as_bytes()).expect("Invalid OS String with NUL bytes")
467}
468
469#[cfg(windows)]
470fn os_str_to_c(s: &OsStr) -> CString {
471    // GLib OS string (environment strings) are always UTF-8 strings on Windows,
472    // while in Rust they are WTF-8. As such, we need to convert to a UTF-8 string.
473    // This conversion can fail, see https://simonsapin.github.io/wtf-8/#converting-wtf-8-utf-8
474    //
475    // It's not clear what we're supposed to do if it fails: the OS string is not
476    // representable in UTF-8 and thus can't possibly be passed to GLib.
477    // Passing NULL or the empty string to GLib can lead to undefined behaviour, so
478    // the only safe option seems to be to simply panic here.
479    let os_str = s
480        .to_str()
481        .expect("OS String can't be represented as UTF-8")
482        .to_owned();
483
484    CString::new(os_str.as_bytes()).expect("Invalid OS string with NUL bytes")
485}
486
487impl<'a> ToGlibPtr<'a, *const c_char> for Path {
488    type Storage = CString;
489
490    #[inline]
491    fn to_glib_none(&'a self) -> Stash<'a, *const c_char, Self> {
492        let tmp = path_to_c(self);
493        Stash(tmp.as_ptr(), tmp)
494    }
495}
496
497impl<'a> ToGlibPtr<'a, *mut c_char> for Path {
498    type Storage = CString;
499
500    #[inline]
501    fn to_glib_none(&'a self) -> Stash<'a, *mut c_char, Self> {
502        let tmp = path_to_c(self);
503        Stash(tmp.as_ptr() as *mut c_char, tmp)
504    }
505}
506
507impl<'a> ToGlibPtr<'a, *const c_char> for PathBuf {
508    type Storage = CString;
509
510    #[inline]
511    fn to_glib_none(&'a self) -> Stash<'a, *const c_char, Self> {
512        let tmp = path_to_c(self);
513        Stash(tmp.as_ptr(), tmp)
514    }
515}
516
517impl<'a> ToGlibPtr<'a, *mut c_char> for PathBuf {
518    type Storage = CString;
519
520    #[inline]
521    fn to_glib_none(&'a self) -> Stash<'a, *mut c_char, Self> {
522        let tmp = path_to_c(self);
523        Stash(tmp.as_ptr() as *mut c_char, tmp)
524    }
525}
526
527impl GlibPtrDefault for Path {
528    type GlibType = *mut c_char;
529}
530
531impl GlibPtrDefault for PathBuf {
532    type GlibType = *mut c_char;
533}
534
535impl<'a> ToGlibPtr<'a, *const c_char> for OsStr {
536    type Storage = CString;
537
538    #[inline]
539    fn to_glib_none(&'a self) -> Stash<'a, *const c_char, Self> {
540        let tmp = os_str_to_c(self);
541        Stash(tmp.as_ptr(), tmp)
542    }
543}
544
545impl<'a> ToGlibPtr<'a, *mut c_char> for OsStr {
546    type Storage = CString;
547
548    #[inline]
549    fn to_glib_none(&'a self) -> Stash<'a, *mut c_char, Self> {
550        let tmp = os_str_to_c(self);
551        Stash(tmp.as_ptr() as *mut c_char, tmp)
552    }
553}
554
555impl<'a> ToGlibPtr<'a, *const c_char> for OsString {
556    type Storage = CString;
557
558    #[inline]
559    fn to_glib_none(&'a self) -> Stash<'a, *const c_char, Self> {
560        let tmp = os_str_to_c(self);
561        Stash(tmp.as_ptr(), tmp)
562    }
563}
564
565impl<'a> ToGlibPtr<'a, *mut c_char> for OsString {
566    type Storage = CString;
567
568    #[inline]
569    fn to_glib_none(&'a self) -> Stash<'a, *mut c_char, Self> {
570        let tmp = os_str_to_c(self);
571        Stash(tmp.as_ptr() as *mut c_char, tmp)
572    }
573}
574
575impl GlibPtrDefault for OsStr {
576    type GlibType = *mut c_char;
577}
578
579impl GlibPtrDefault for OsString {
580    type GlibType = *mut c_char;
581}
582
583pub trait ToGlibContainerFromSlice<'a, P>
584where
585    Self: Sized,
586{
587    type Storage;
588
589    fn to_glib_none_from_slice(t: &'a [Self]) -> (P, Self::Storage);
590    fn to_glib_container_from_slice(t: &'a [Self]) -> (P, Self::Storage);
591    fn to_glib_full_from_slice(t: &[Self]) -> P;
592}
593
594macro_rules! impl_to_glib_container_from_slice_fundamental {
595    ($name:ty) => {
596        impl<'a> ToGlibContainerFromSlice<'a, *mut $name> for $name {
597            type Storage = &'a [$name];
598
599            fn to_glib_none_from_slice(t: &'a [$name]) -> (*mut $name, &'a [$name]) {
600                (t.as_ptr() as *mut $name, t)
601            }
602
603            fn to_glib_container_from_slice(t: &'a [$name]) -> (*mut $name, &'a [$name]) {
604                (ToGlibContainerFromSlice::to_glib_full_from_slice(t), t)
605            }
606
607            fn to_glib_full_from_slice(t: &[$name]) -> *mut $name {
608                if t.len() == 0 {
609                    return ptr::null_mut();
610                }
611
612                unsafe {
613                    let res = glib_sys::g_malloc(mem::size_of::<$name>() * t.len()) as *mut $name;
614                    ptr::copy_nonoverlapping(t.as_ptr(), res, t.len());
615                    res
616                }
617            }
618        }
619    };
620}
621
622impl_to_glib_container_from_slice_fundamental!(u8);
623impl_to_glib_container_from_slice_fundamental!(i8);
624impl_to_glib_container_from_slice_fundamental!(u16);
625impl_to_glib_container_from_slice_fundamental!(i16);
626impl_to_glib_container_from_slice_fundamental!(u32);
627impl_to_glib_container_from_slice_fundamental!(i32);
628impl_to_glib_container_from_slice_fundamental!(u64);
629impl_to_glib_container_from_slice_fundamental!(i64);
630impl_to_glib_container_from_slice_fundamental!(f32);
631impl_to_glib_container_from_slice_fundamental!(f64);
632
633macro_rules! impl_to_glib_container_from_slice_string {
634    ($name:ty, $ffi_name:ty) => {
635        impl<'a> ToGlibContainerFromSlice<'a, *mut $ffi_name> for $name {
636            type Storage = (Vec<Stash<'a, $ffi_name, $name>>, Option<Vec<$ffi_name>>);
637
638            fn to_glib_none_from_slice(t: &'a [$name]) -> (*mut $ffi_name, Self::Storage) {
639                let v: Vec<_> = t.iter().map(ToGlibPtr::to_glib_none).collect();
640                let mut v_ptr: Vec<_> = v.iter().map(|s| s.0).collect();
641                v_ptr.push(ptr::null_mut() as $ffi_name);
642
643                (v_ptr.as_ptr() as *mut $ffi_name, (v, Some(v_ptr)))
644            }
645
646            fn to_glib_container_from_slice(t: &'a [$name]) -> (*mut $ffi_name, Self::Storage) {
647                let v: Vec<_> = t.iter().map(ToGlibPtr::to_glib_none).collect();
648
649                let v_ptr = unsafe {
650                    let v_ptr = glib_sys::g_malloc0(mem::size_of::<$ffi_name>() * (t.len() + 1))
651                        as *mut $ffi_name;
652
653                    for (i, s) in v.iter().enumerate() {
654                        ptr::write(v_ptr.add(i), s.0);
655                    }
656
657                    v_ptr
658                };
659
660                (v_ptr, (v, None))
661            }
662
663            fn to_glib_full_from_slice(t: &[$name]) -> *mut $ffi_name {
664                unsafe {
665                    let v_ptr = glib_sys::g_malloc0(mem::size_of::<$ffi_name>() * (t.len() + 1))
666                        as *mut $ffi_name;
667
668                    for (i, s) in t.iter().enumerate() {
669                        ptr::write(v_ptr.add(i), s.to_glib_full());
670                    }
671
672                    v_ptr
673                }
674            }
675        }
676        impl<'a> ToGlibContainerFromSlice<'a, *const $ffi_name> for $name {
677            type Storage = (Vec<Stash<'a, $ffi_name, $name>>, Option<Vec<$ffi_name>>);
678
679            fn to_glib_none_from_slice(t: &'a [$name]) -> (*const $ffi_name, Self::Storage) {
680                let v: Vec<_> = t.iter().map(ToGlibPtr::to_glib_none).collect();
681                let mut v_ptr: Vec<_> = v.iter().map(|s| s.0).collect();
682                v_ptr.push(ptr::null_mut() as $ffi_name);
683
684                (v_ptr.as_ptr() as *const $ffi_name, (v, Some(v_ptr)))
685            }
686
687            fn to_glib_container_from_slice(t: &'a [$name]) -> (*const $ffi_name, Self::Storage) {
688                let v: Vec<_> = t.iter().map(ToGlibPtr::to_glib_none).collect();
689
690                let v_ptr = unsafe {
691                    let v_ptr = glib_sys::g_malloc0(mem::size_of::<$ffi_name>() * (t.len() + 1))
692                        as *mut $ffi_name;
693
694                    for (i, s) in v.iter().enumerate() {
695                        ptr::write(v_ptr.add(i), s.0);
696                    }
697
698                    v_ptr as *const $ffi_name
699                };
700
701                (v_ptr, (v, None))
702            }
703
704            fn to_glib_full_from_slice(t: &[$name]) -> *const $ffi_name {
705                unsafe {
706                    let v_ptr = glib_sys::g_malloc0(mem::size_of::<$ffi_name>() * (t.len() + 1))
707                        as *mut $ffi_name;
708
709                    for (i, s) in t.iter().enumerate() {
710                        ptr::write(v_ptr.add(i), s.to_glib_full());
711                    }
712
713                    v_ptr as *const $ffi_name
714                }
715            }
716        }
717    };
718}
719
720impl_to_glib_container_from_slice_string!(&'a str, *mut c_char);
721impl_to_glib_container_from_slice_string!(&'a str, *const c_char);
722impl_to_glib_container_from_slice_string!(String, *mut c_char);
723impl_to_glib_container_from_slice_string!(String, *const c_char);
724impl_to_glib_container_from_slice_string!(&'a Path, *mut c_char);
725impl_to_glib_container_from_slice_string!(&'a Path, *const c_char);
726impl_to_glib_container_from_slice_string!(PathBuf, *mut c_char);
727impl_to_glib_container_from_slice_string!(PathBuf, *const c_char);
728impl_to_glib_container_from_slice_string!(&'a OsStr, *mut c_char);
729impl_to_glib_container_from_slice_string!(&'a OsStr, *const c_char);
730impl_to_glib_container_from_slice_string!(OsString, *mut c_char);
731impl_to_glib_container_from_slice_string!(OsString, *const c_char);
732
733impl<'a, T> ToGlibContainerFromSlice<'a, *mut glib_sys::GList> for T
734where
735    T: GlibPtrDefault + ToGlibPtr<'a, <T as GlibPtrDefault>::GlibType>,
736{
737    type Storage = (
738        Option<List>,
739        Vec<Stash<'a, <T as GlibPtrDefault>::GlibType, T>>,
740    );
741
742    #[inline]
743    fn to_glib_none_from_slice(t: &'a [T]) -> (*mut glib_sys::GList, Self::Storage) {
744        let stash_vec: Vec<_> = t.iter().rev().map(ToGlibPtr::to_glib_none).collect();
745        let mut list: *mut glib_sys::GList = ptr::null_mut();
746        unsafe {
747            for stash in &stash_vec {
748                list = glib_sys::g_list_prepend(list, Ptr::to(stash.0));
749            }
750        }
751        (list, (Some(List(list)), stash_vec))
752    }
753
754    #[inline]
755    fn to_glib_container_from_slice(t: &'a [T]) -> (*mut glib_sys::GList, Self::Storage) {
756        let stash_vec: Vec<_> = t.iter().rev().map(ToGlibPtr::to_glib_none).collect();
757        let mut list: *mut glib_sys::GList = ptr::null_mut();
758        unsafe {
759            for stash in &stash_vec {
760                list = glib_sys::g_list_prepend(list, Ptr::to(stash.0));
761            }
762        }
763        (list, (None, stash_vec))
764    }
765
766    #[inline]
767    fn to_glib_full_from_slice(t: &[T]) -> *mut glib_sys::GList {
768        let mut list: *mut glib_sys::GList = ptr::null_mut();
769        unsafe {
770            for ptr in t.iter().rev().map(ToGlibPtr::to_glib_full) {
771                list = glib_sys::g_list_prepend(list, Ptr::to(ptr));
772            }
773        }
774        list
775    }
776}
777
778impl<'a, T> ToGlibContainerFromSlice<'a, *const glib_sys::GList> for T
779where
780    T: GlibPtrDefault + ToGlibPtr<'a, <T as GlibPtrDefault>::GlibType>,
781{
782    type Storage = (
783        Option<List>,
784        Vec<Stash<'a, <T as GlibPtrDefault>::GlibType, T>>,
785    );
786
787    #[inline]
788    fn to_glib_none_from_slice(t: &'a [T]) -> (*const glib_sys::GList, Self::Storage) {
789        let (list, stash) =
790            ToGlibContainerFromSlice::<*mut glib_sys::GList>::to_glib_none_from_slice(t);
791        (list as *const glib_sys::GList, stash)
792    }
793
794    #[inline]
795    fn to_glib_container_from_slice(_t: &'a [T]) -> (*const glib_sys::GList, Self::Storage) {
796        unimplemented!()
797    }
798
799    #[inline]
800    fn to_glib_full_from_slice(_t: &[T]) -> *const glib_sys::GList {
801        unimplemented!()
802    }
803}
804
805pub struct List(*mut glib_sys::GList);
806
807impl Drop for List {
808    fn drop(&mut self) {
809        unsafe { glib_sys::g_list_free(self.0) }
810    }
811}
812
813impl<'a, T> ToGlibContainerFromSlice<'a, *mut glib_sys::GSList> for &'a T
814where
815    T: GlibPtrDefault + ToGlibPtr<'a, <T as GlibPtrDefault>::GlibType>,
816{
817    type Storage = (
818        Option<SList>,
819        Vec<Stash<'a, <T as GlibPtrDefault>::GlibType, &'a T>>,
820    );
821
822    #[inline]
823    fn to_glib_none_from_slice(t: &'a [&'a T]) -> (*mut glib_sys::GSList, Self::Storage) {
824        let stash_vec: Vec<_> = t.iter().rev().map(ToGlibPtr::to_glib_none).collect();
825        let mut list: *mut glib_sys::GSList = ptr::null_mut();
826        unsafe {
827            for stash in &stash_vec {
828                list = glib_sys::g_slist_prepend(list, Ptr::to(stash.0));
829            }
830        }
831        (list, (Some(SList(list)), stash_vec))
832    }
833
834    #[inline]
835    fn to_glib_container_from_slice(t: &'a [&'a T]) -> (*mut glib_sys::GSList, Self::Storage) {
836        let stash_vec: Vec<_> = t.iter().rev().map(ToGlibPtr::to_glib_none).collect();
837        let mut list: *mut glib_sys::GSList = ptr::null_mut();
838        unsafe {
839            for stash in &stash_vec {
840                list = glib_sys::g_slist_prepend(list, Ptr::to(stash.0));
841            }
842        }
843        (list, (None, stash_vec))
844    }
845
846    #[inline]
847    fn to_glib_full_from_slice(t: &[&'a T]) -> *mut glib_sys::GSList {
848        let mut list: *mut glib_sys::GSList = ptr::null_mut();
849        unsafe {
850            for ptr in t.iter().rev().map(ToGlibPtr::to_glib_full) {
851                list = glib_sys::g_slist_prepend(list, Ptr::to(ptr));
852            }
853        }
854        list
855    }
856}
857
858impl<'a, T> ToGlibContainerFromSlice<'a, *const glib_sys::GSList> for &'a T
859where
860    T: GlibPtrDefault + ToGlibPtr<'a, <T as GlibPtrDefault>::GlibType>,
861{
862    type Storage = (
863        Option<SList>,
864        Vec<Stash<'a, <T as GlibPtrDefault>::GlibType, &'a T>>,
865    );
866
867    #[inline]
868    fn to_glib_none_from_slice(t: &'a [&'a T]) -> (*const glib_sys::GSList, Self::Storage) {
869        let (list, stash) =
870            ToGlibContainerFromSlice::<*mut glib_sys::GSList>::to_glib_none_from_slice(t);
871        (list as *const glib_sys::GSList, stash)
872    }
873
874    #[inline]
875    fn to_glib_container_from_slice(_t: &'a [&'a T]) -> (*const glib_sys::GSList, Self::Storage) {
876        unimplemented!()
877    }
878
879    #[inline]
880    fn to_glib_full_from_slice(_t: &[&'a T]) -> *const glib_sys::GSList {
881        unimplemented!()
882    }
883}
884
885pub struct SList(*mut glib_sys::GSList);
886
887impl Drop for SList {
888    fn drop(&mut self) {
889        unsafe { glib_sys::g_slist_free(self.0) }
890    }
891}
892
893impl<'a, P: Ptr, T: ToGlibContainerFromSlice<'a, P>> ToGlibPtr<'a, P> for [T] {
894    type Storage = T::Storage;
895
896    #[inline]
897    fn to_glib_none(&'a self) -> Stash<'a, P, Self> {
898        let result = ToGlibContainerFromSlice::to_glib_none_from_slice(self);
899        Stash(result.0, result.1)
900    }
901
902    #[inline]
903    fn to_glib_container(&'a self) -> Stash<'a, P, Self> {
904        let result = ToGlibContainerFromSlice::to_glib_container_from_slice(self);
905        Stash(result.0, result.1)
906    }
907
908    #[inline]
909    fn to_glib_full(&self) -> P {
910        ToGlibContainerFromSlice::to_glib_full_from_slice(self)
911    }
912}
913
914#[allow(clippy::implicit_hasher)]
915impl<'a> ToGlibPtr<'a, *mut glib_sys::GHashTable> for HashMap<String, String> {
916    type Storage = (HashTable);
917
918    #[inline]
919    fn to_glib_none(&self) -> Stash<'a, *mut glib_sys::GHashTable, Self> {
920        let ptr = self.to_glib_full();
921        Stash(ptr, HashTable(ptr))
922    }
923
924    #[inline]
925    fn to_glib_full(&self) -> *mut glib_sys::GHashTable {
926        unsafe {
927            let ptr = glib_sys::g_hash_table_new_full(
928                Some(glib_sys::g_str_hash),
929                Some(glib_sys::g_str_equal),
930                Some(glib_sys::g_free),
931                Some(glib_sys::g_free),
932            );
933            for (k, v) in self {
934                let k: *mut c_char = k.to_glib_full();
935                let v: *mut c_char = v.to_glib_full();
936                glib_sys::g_hash_table_insert(ptr, k as *mut _, v as *mut _);
937            }
938            ptr
939        }
940    }
941}
942
943pub struct HashTable(*mut glib_sys::GHashTable);
944
945impl Drop for HashTable {
946    fn drop(&mut self) {
947        unsafe { glib_sys::g_hash_table_unref(self.0) }
948    }
949}
950
951impl<'a, T> ToGlibContainerFromSlice<'a, *const glib_sys::GArray> for &'a T
952where
953    T: GlibPtrDefault + ToGlibPtr<'a, <T as GlibPtrDefault>::GlibType>,
954{
955    type Storage = (
956        Option<Array>,
957        Vec<Stash<'a, <T as GlibPtrDefault>::GlibType, &'a T>>,
958    );
959
960    #[inline]
961    fn to_glib_none_from_slice(t: &'a [&'a T]) -> (*const glib_sys::GArray, Self::Storage) {
962        let (list, stash) =
963            ToGlibContainerFromSlice::<*mut glib_sys::GArray>::to_glib_none_from_slice(t);
964        (list as *const glib_sys::GArray, stash)
965    }
966
967    #[inline]
968    fn to_glib_container_from_slice(_t: &'a [&'a T]) -> (*const glib_sys::GArray, Self::Storage) {
969        unimplemented!()
970    }
971
972    #[inline]
973    fn to_glib_full_from_slice(_t: &[&'a T]) -> *const glib_sys::GArray {
974        unimplemented!()
975    }
976}
977
978pub struct Array(*mut glib_sys::GArray);
979
980impl Drop for Array {
981    fn drop(&mut self) {
982        unsafe {
983            glib_sys::g_array_free(self.0, false.to_glib());
984        }
985    }
986}
987
988impl<'a, T> ToGlibContainerFromSlice<'a, *mut glib_sys::GArray> for T
989where
990    T: GlibPtrDefault + ToGlibPtr<'a, <T as GlibPtrDefault>::GlibType>,
991{
992    type Storage = (
993        Option<Array>,
994        Vec<Stash<'a, <T as GlibPtrDefault>::GlibType, T>>,
995    );
996
997    #[inline]
998    fn to_glib_none_from_slice(t: &'a [T]) -> (*mut glib_sys::GArray, Self::Storage) {
999        let stash_vec: Vec<_> = t.iter().map(ToGlibPtr::to_glib_none).collect();
1000        let mut arr: *mut glib_sys::GArray = ptr::null_mut();
1001        unsafe {
1002            for stash in &stash_vec {
1003                arr = glib_sys::g_array_append_vals(arr, Ptr::to(stash.0), 1);
1004            }
1005        }
1006        (arr, (Some(Array(arr)), stash_vec))
1007    }
1008
1009    #[inline]
1010    fn to_glib_container_from_slice(t: &'a [T]) -> (*mut glib_sys::GArray, Self::Storage) {
1011        let stash_vec: Vec<_> = t.iter().rev().map(ToGlibPtr::to_glib_none).collect();
1012        let mut arr: *mut glib_sys::GArray = ptr::null_mut();
1013        unsafe {
1014            for stash in &stash_vec {
1015                arr = glib_sys::g_array_append_vals(arr, Ptr::to(stash.0), 1);
1016            }
1017        }
1018        (arr, (None, stash_vec))
1019    }
1020
1021    #[inline]
1022    fn to_glib_full_from_slice(t: &[T]) -> *mut glib_sys::GArray {
1023        let mut arr: *mut glib_sys::GArray = ptr::null_mut();
1024        unsafe {
1025            for ptr in t.iter().map(ToGlibPtr::to_glib_full) {
1026                arr = glib_sys::g_array_append_vals(arr, Ptr::to(ptr), 1);
1027            }
1028        }
1029        arr
1030    }
1031}
1032
1033/// Translate a simple type.
1034pub trait FromGlib<T>: Sized {
1035    fn from_glib(val: T) -> Self;
1036}
1037
1038/// Translate a simple type.
1039#[inline]
1040pub fn from_glib<G, T: FromGlib<G>>(val: G) -> T {
1041    FromGlib::from_glib(val)
1042}
1043
1044impl FromGlib<glib_sys::gboolean> for bool {
1045    #[inline]
1046    fn from_glib(val: glib_sys::gboolean) -> bool {
1047        val != glib_sys::GFALSE
1048    }
1049}
1050
1051impl FromGlib<u32> for char {
1052    #[inline]
1053    fn from_glib(val: u32) -> char {
1054        char::from_u32(val).expect("Valid Unicode character expected")
1055    }
1056}
1057
1058impl FromGlib<i32> for Ordering {
1059    #[inline]
1060    fn from_glib(val: i32) -> Ordering {
1061        if val < 0 {
1062            Ordering::Less
1063        } else if val > 0 {
1064            Ordering::Greater
1065        } else {
1066            Ordering::Equal
1067        }
1068    }
1069}
1070
1071impl FromGlib<u32> for Option<char> {
1072    #[inline]
1073    fn from_glib(val: u32) -> Option<char> {
1074        match val {
1075            0 => None,
1076            _ => char::from_u32(val),
1077        }
1078    }
1079}
1080
1081impl FromGlib<i32> for Option<u32> {
1082    #[inline]
1083    fn from_glib(val: i32) -> Option<u32> {
1084        if val >= 0 {
1085            Some(val as u32)
1086        } else {
1087            None
1088        }
1089    }
1090}
1091
1092impl FromGlib<i64> for Option<u64> {
1093    #[inline]
1094    fn from_glib(val: i64) -> Option<u64> {
1095        if val >= 0 {
1096            Some(val as u64)
1097        } else {
1098            None
1099        }
1100    }
1101}
1102
1103impl FromGlib<i32> for Option<u64> {
1104    #[inline]
1105    fn from_glib(val: i32) -> Option<u64> {
1106        FromGlib::from_glib(i64::from(val))
1107    }
1108}
1109
1110/// Translate from a pointer type without taking ownership, transfer: none.
1111pub trait FromGlibPtrNone<P: Ptr>: Sized {
1112    unsafe fn from_glib_none(ptr: P) -> Self;
1113}
1114
1115/// Translate from a pointer type taking ownership, transfer: full.
1116pub trait FromGlibPtrFull<P: Ptr>: Sized {
1117    unsafe fn from_glib_full(ptr: P) -> Self;
1118}
1119
1120/// Translate from a pointer type by borrowing. Don't increase the refcount
1121pub trait FromGlibPtrBorrow<P: Ptr>: Sized {
1122    unsafe fn from_glib_borrow(_ptr: P) -> Self {
1123        unimplemented!();
1124    }
1125}
1126
1127/// Translate from a pointer type, transfer: none.
1128#[inline]
1129pub unsafe fn from_glib_none<P: Ptr, T: FromGlibPtrNone<P>>(ptr: P) -> T {
1130    FromGlibPtrNone::from_glib_none(ptr)
1131}
1132
1133/// Translate from a pointer type, transfer: full (assume ownership).
1134#[inline]
1135pub unsafe fn from_glib_full<P: Ptr, T: FromGlibPtrFull<P>>(ptr: P) -> T {
1136    FromGlibPtrFull::from_glib_full(ptr)
1137}
1138
1139/// Translate from a pointer type, borrowing the pointer.
1140#[inline]
1141pub unsafe fn from_glib_borrow<P: Ptr, T: FromGlibPtrBorrow<P>>(ptr: P) -> T {
1142    FromGlibPtrBorrow::from_glib_borrow(ptr)
1143}
1144
1145impl<P: Ptr, T: FromGlibPtrNone<P>> FromGlibPtrNone<P> for Option<T> {
1146    #[inline]
1147    unsafe fn from_glib_none(ptr: P) -> Option<T> {
1148        if ptr.is_null() {
1149            None
1150        } else {
1151            Some(from_glib_none(ptr))
1152        }
1153    }
1154}
1155
1156impl<P: Ptr, T: FromGlibPtrBorrow<P>> FromGlibPtrBorrow<P> for Option<T> {
1157    #[inline]
1158    unsafe fn from_glib_borrow(ptr: P) -> Option<T> {
1159        if ptr.is_null() {
1160            None
1161        } else {
1162            Some(from_glib_borrow(ptr))
1163        }
1164    }
1165}
1166
1167impl<P: Ptr, T: FromGlibPtrFull<P>> FromGlibPtrFull<P> for Option<T> {
1168    #[inline]
1169    unsafe fn from_glib_full(ptr: P) -> Option<T> {
1170        if ptr.is_null() {
1171            None
1172        } else {
1173            Some(from_glib_full(ptr))
1174        }
1175    }
1176}
1177
1178impl FromGlibPtrNone<*const c_char> for String {
1179    #[inline]
1180    unsafe fn from_glib_none(ptr: *const c_char) -> Self {
1181        assert!(!ptr.is_null());
1182        String::from_utf8_lossy(CStr::from_ptr(ptr).to_bytes()).into_owned()
1183    }
1184}
1185
1186// TODO: Deprecate this
1187impl FromGlibPtrFull<*const c_char> for String {
1188    #[inline]
1189    unsafe fn from_glib_full(ptr: *const c_char) -> Self {
1190        let res = from_glib_none(ptr);
1191        glib_sys::g_free(ptr as *mut _);
1192        res
1193    }
1194}
1195
1196// TODO: Deprecate this
1197impl FromGlibPtrNone<*mut c_char> for String {
1198    #[inline]
1199    unsafe fn from_glib_none(ptr: *mut c_char) -> Self {
1200        assert!(!ptr.is_null());
1201        String::from_utf8_lossy(CStr::from_ptr(ptr).to_bytes()).into_owned()
1202    }
1203}
1204
1205// TODO: Deprecate this
1206impl FromGlibPtrFull<*mut c_char> for String {
1207    #[inline]
1208    unsafe fn from_glib_full(ptr: *mut c_char) -> Self {
1209        let res = from_glib_none(ptr);
1210        glib_sys::g_free(ptr as *mut _);
1211        res
1212    }
1213}
1214
1215#[cfg(not(windows))]
1216unsafe fn c_to_path_buf(ptr: *const c_char) -> PathBuf {
1217    assert!(!ptr.is_null());
1218
1219    // GLib paths on UNIX are always in the local encoding, which can be
1220    // UTF-8 or anything else really, but is always a NUL-terminated string
1221    // and must not contain any other NUL bytes
1222    OsString::from_vec(CStr::from_ptr(ptr).to_bytes().to_vec()).into()
1223}
1224
1225#[cfg(windows)]
1226unsafe fn c_to_path_buf(ptr: *const c_char) -> PathBuf {
1227    assert!(!ptr.is_null());
1228
1229    // GLib paths on Windows are always UTF-8, as such we can convert to a String
1230    // first and then go to a PathBuf from there. Unless there is a bug
1231    // in the C library, the conversion from UTF-8 can never fail so we can
1232    // safely panic here if that ever happens
1233    String::from_utf8(CStr::from_ptr(ptr).to_bytes().into())
1234        .expect("Invalid, non-UTF8 path")
1235        .into()
1236}
1237
1238#[cfg(not(windows))]
1239unsafe fn c_to_os_string(ptr: *const c_char) -> OsString {
1240    assert!(!ptr.is_null());
1241
1242    // GLib OS string (environment strings) on UNIX are always in the local encoding,
1243    // which can be UTF-8 or anything else really, but is always a NUL-terminated string
1244    // and must not contain any other NUL bytes
1245    OsString::from_vec(CStr::from_ptr(ptr).to_bytes().to_vec())
1246}
1247
1248#[cfg(windows)]
1249unsafe fn c_to_os_string(ptr: *const c_char) -> OsString {
1250    assert!(!ptr.is_null());
1251
1252    // GLib OS string (environment strings) on Windows are always UTF-8,
1253    // as such we can convert to a String
1254    // first and then go to a OsString from there. Unless there is a bug
1255    // in the C library, the conversion from UTF-8 can never fail so we can
1256    // safely panic here if that ever happens
1257    String::from_utf8(CStr::from_ptr(ptr).to_bytes().into())
1258        .expect("Invalid, non-UTF8 path")
1259        .into()
1260}
1261
1262impl FromGlibPtrNone<*const c_char> for PathBuf {
1263    #[inline]
1264    unsafe fn from_glib_none(ptr: *const c_char) -> Self {
1265        assert!(!ptr.is_null());
1266        c_to_path_buf(ptr)
1267    }
1268}
1269
1270impl FromGlibPtrFull<*const c_char> for PathBuf {
1271    #[inline]
1272    unsafe fn from_glib_full(ptr: *const c_char) -> Self {
1273        let res = from_glib_none(ptr);
1274        glib_sys::g_free(ptr as *mut _);
1275        res
1276    }
1277}
1278
1279impl FromGlibPtrNone<*mut c_char> for PathBuf {
1280    #[inline]
1281    unsafe fn from_glib_none(ptr: *mut c_char) -> Self {
1282        assert!(!ptr.is_null());
1283        c_to_path_buf(ptr)
1284    }
1285}
1286
1287impl FromGlibPtrFull<*mut c_char> for PathBuf {
1288    #[inline]
1289    unsafe fn from_glib_full(ptr: *mut c_char) -> Self {
1290        let res = from_glib_none(ptr);
1291        glib_sys::g_free(ptr as *mut _);
1292        res
1293    }
1294}
1295
1296impl FromGlibPtrNone<*const c_char> for OsString {
1297    #[inline]
1298    unsafe fn from_glib_none(ptr: *const c_char) -> Self {
1299        assert!(!ptr.is_null());
1300        c_to_os_string(ptr)
1301    }
1302}
1303
1304impl FromGlibPtrFull<*const c_char> for OsString {
1305    #[inline]
1306    unsafe fn from_glib_full(ptr: *const c_char) -> Self {
1307        let res = from_glib_none(ptr);
1308        glib_sys::g_free(ptr as *mut _);
1309        res
1310    }
1311}
1312
1313impl FromGlibPtrNone<*mut c_char> for OsString {
1314    #[inline]
1315    unsafe fn from_glib_none(ptr: *mut c_char) -> Self {
1316        assert!(!ptr.is_null());
1317        c_to_os_string(ptr)
1318    }
1319}
1320
1321impl FromGlibPtrFull<*mut c_char> for OsString {
1322    #[inline]
1323    unsafe fn from_glib_full(ptr: *mut c_char) -> Self {
1324        let res = from_glib_none(ptr);
1325        glib_sys::g_free(ptr as *mut _);
1326        res
1327    }
1328}
1329
1330/// Translate from a container.
1331pub trait FromGlibContainer<T, P: Ptr>: Sized {
1332    /// Transfer: none.
1333    ///
1334    /// `num` is the advised number of elements.
1335    unsafe fn from_glib_none_num(ptr: P, num: usize) -> Self;
1336
1337    /// Transfer: container.
1338    ///
1339    /// `num` is the advised number of elements.
1340    unsafe fn from_glib_container_num(ptr: P, num: usize) -> Self;
1341
1342    /// Transfer: full.
1343    ///
1344    /// `num` is the advised number of elements.
1345    unsafe fn from_glib_full_num(ptr: P, num: usize) -> Self;
1346}
1347
1348/// Translate from a container of pointers.
1349pub trait FromGlibPtrContainer<P: Ptr, PP: Ptr>: FromGlibContainer<P, PP> + Sized {
1350    /// Transfer: none.
1351    unsafe fn from_glib_none(ptr: PP) -> Self;
1352
1353    /// Transfer: container.
1354    unsafe fn from_glib_container(ptr: PP) -> Self;
1355
1356    /// Transfer: full.
1357    unsafe fn from_glib_full(ptr: PP) -> Self;
1358}
1359
1360pub unsafe fn c_ptr_array_len<P: Ptr>(mut ptr: *const P) -> usize {
1361    let mut len = 0;
1362
1363    if !ptr.is_null() {
1364        while !(*ptr).is_null() {
1365            len += 1;
1366            ptr = ptr.offset(1);
1367        }
1368    }
1369    len
1370}
1371
1372pub trait FromGlibContainerAsVec<T, P: Ptr>
1373where
1374    Self: Sized,
1375{
1376    unsafe fn from_glib_none_num_as_vec(ptr: P, num: usize) -> Vec<Self>;
1377    unsafe fn from_glib_container_num_as_vec(ptr: P, num: usize) -> Vec<Self>;
1378    unsafe fn from_glib_full_num_as_vec(ptr: P, num: usize) -> Vec<Self>;
1379}
1380
1381pub trait FromGlibPtrArrayContainerAsVec<P: Ptr, PP: Ptr>: FromGlibContainerAsVec<P, PP>
1382where
1383    Self: Sized,
1384{
1385    unsafe fn from_glib_none_as_vec(ptr: PP) -> Vec<Self>;
1386    unsafe fn from_glib_container_as_vec(ptr: PP) -> Vec<Self>;
1387    unsafe fn from_glib_full_as_vec(ptr: PP) -> Vec<Self>;
1388}
1389
1390impl FromGlibContainerAsVec<bool, *const glib_sys::gboolean> for bool {
1391    unsafe fn from_glib_none_num_as_vec(ptr: *const glib_sys::gboolean, num: usize) -> Vec<Self> {
1392        if num == 0 || ptr.is_null() {
1393            return Vec::new();
1394        }
1395
1396        let mut res = Vec::with_capacity(num);
1397        for i in 0..num {
1398            res.push(from_glib(ptr::read(ptr.add(i))));
1399        }
1400        res
1401    }
1402
1403    unsafe fn from_glib_container_num_as_vec(_: *const glib_sys::gboolean, _: usize) -> Vec<Self> {
1404        // Can't really free a *const
1405        unimplemented!();
1406    }
1407
1408    unsafe fn from_glib_full_num_as_vec(_: *const glib_sys::gboolean, _: usize) -> Vec<Self> {
1409        // Can't really free a *const
1410        unimplemented!();
1411    }
1412}
1413
1414impl FromGlibContainerAsVec<bool, *mut glib_sys::gboolean> for bool {
1415    unsafe fn from_glib_none_num_as_vec(ptr: *mut glib_sys::gboolean, num: usize) -> Vec<Self> {
1416        FromGlibContainerAsVec::from_glib_none_num_as_vec(ptr as *const _, num)
1417    }
1418
1419    unsafe fn from_glib_container_num_as_vec(
1420        ptr: *mut glib_sys::gboolean,
1421        num: usize,
1422    ) -> Vec<Self> {
1423        let res = FromGlibContainerAsVec::from_glib_none_num_as_vec(ptr, num);
1424        glib_sys::g_free(ptr as *mut _);
1425        res
1426    }
1427
1428    unsafe fn from_glib_full_num_as_vec(ptr: *mut glib_sys::gboolean, num: usize) -> Vec<Self> {
1429        FromGlibContainerAsVec::from_glib_container_num_as_vec(ptr, num)
1430    }
1431}
1432
1433macro_rules! impl_from_glib_container_as_vec_fundamental {
1434    ($name:ty) => {
1435        impl FromGlibContainerAsVec<$name, *const $name> for $name {
1436            unsafe fn from_glib_none_num_as_vec(ptr: *const $name, num: usize) -> Vec<Self> {
1437                if num == 0 || ptr.is_null() {
1438                    return Vec::new();
1439                }
1440
1441                let mut res = Vec::with_capacity(num);
1442                for i in 0..num {
1443                    res.push(ptr::read(ptr.add(i)));
1444                }
1445                res
1446            }
1447
1448            unsafe fn from_glib_container_num_as_vec(_: *const $name, _: usize) -> Vec<Self> {
1449                // Can't really free a *const
1450                unimplemented!();
1451            }
1452
1453            unsafe fn from_glib_full_num_as_vec(_: *const $name, _: usize) -> Vec<Self> {
1454                // Can't really free a *const
1455                unimplemented!();
1456            }
1457        }
1458
1459        impl FromGlibContainerAsVec<$name, *mut $name> for $name {
1460            unsafe fn from_glib_none_num_as_vec(ptr: *mut $name, num: usize) -> Vec<Self> {
1461                FromGlibContainerAsVec::from_glib_none_num_as_vec(ptr as *const _, num)
1462            }
1463
1464            unsafe fn from_glib_container_num_as_vec(ptr: *mut $name, num: usize) -> Vec<Self> {
1465                let res = FromGlibContainerAsVec::from_glib_none_num_as_vec(ptr, num);
1466                glib_sys::g_free(ptr as *mut _);
1467                res
1468            }
1469
1470            unsafe fn from_glib_full_num_as_vec(ptr: *mut $name, num: usize) -> Vec<Self> {
1471                FromGlibContainerAsVec::from_glib_container_num_as_vec(ptr, num)
1472            }
1473        }
1474    };
1475}
1476
1477impl_from_glib_container_as_vec_fundamental!(u8);
1478impl_from_glib_container_as_vec_fundamental!(i8);
1479impl_from_glib_container_as_vec_fundamental!(u16);
1480impl_from_glib_container_as_vec_fundamental!(i16);
1481impl_from_glib_container_as_vec_fundamental!(u32);
1482impl_from_glib_container_as_vec_fundamental!(i32);
1483impl_from_glib_container_as_vec_fundamental!(u64);
1484impl_from_glib_container_as_vec_fundamental!(i64);
1485impl_from_glib_container_as_vec_fundamental!(f32);
1486impl_from_glib_container_as_vec_fundamental!(f64);
1487
1488macro_rules! impl_from_glib_container_as_vec_string {
1489    ($name:ty, $ffi_name:ty) => {
1490        impl FromGlibContainerAsVec<$ffi_name, *const $ffi_name> for $name {
1491            unsafe fn from_glib_none_num_as_vec(ptr: *const $ffi_name, num: usize) -> Vec<Self> {
1492                if num == 0 || ptr.is_null() {
1493                    return Vec::new();
1494                }
1495
1496                let mut res = Vec::with_capacity(num);
1497                for i in 0..num {
1498                    res.push(from_glib_none(ptr::read(ptr.add(i)) as $ffi_name));
1499                }
1500                res
1501            }
1502
1503            unsafe fn from_glib_container_num_as_vec(_: *const $ffi_name, _: usize) -> Vec<Self> {
1504                // Can't really free a *const
1505                unimplemented!();
1506            }
1507
1508            unsafe fn from_glib_full_num_as_vec(_: *const $ffi_name, _: usize) -> Vec<Self> {
1509                // Can't really free a *const
1510                unimplemented!();
1511            }
1512        }
1513
1514        impl FromGlibContainerAsVec<$ffi_name, *mut $ffi_name> for $name {
1515            unsafe fn from_glib_none_num_as_vec(ptr: *mut $ffi_name, num: usize) -> Vec<Self> {
1516                FromGlibContainerAsVec::from_glib_none_num_as_vec(ptr as *const _, num)
1517            }
1518
1519            unsafe fn from_glib_container_num_as_vec(ptr: *mut $ffi_name, num: usize) -> Vec<Self> {
1520                let res = FromGlibContainerAsVec::from_glib_none_num_as_vec(ptr, num);
1521                glib_sys::g_free(ptr as *mut _);
1522                res
1523            }
1524
1525            unsafe fn from_glib_full_num_as_vec(ptr: *mut $ffi_name, num: usize) -> Vec<Self> {
1526                if num == 0 || ptr.is_null() {
1527                    return Vec::new();
1528                }
1529
1530                let mut res = Vec::with_capacity(num);
1531                for i in 0..num {
1532                    res.push(from_glib_full(ptr::read(ptr.add(i))));
1533                }
1534                glib_sys::g_free(ptr as *mut _);
1535                res
1536            }
1537        }
1538
1539        impl FromGlibPtrArrayContainerAsVec<$ffi_name, *mut $ffi_name> for $name {
1540            unsafe fn from_glib_none_as_vec(ptr: *mut $ffi_name) -> Vec<Self> {
1541                FromGlibContainerAsVec::from_glib_none_num_as_vec(ptr, c_ptr_array_len(ptr))
1542            }
1543
1544            unsafe fn from_glib_container_as_vec(ptr: *mut $ffi_name) -> Vec<Self> {
1545                FromGlibContainerAsVec::from_glib_container_num_as_vec(ptr, c_ptr_array_len(ptr))
1546            }
1547
1548            unsafe fn from_glib_full_as_vec(ptr: *mut $ffi_name) -> Vec<Self> {
1549                FromGlibContainerAsVec::from_glib_full_num_as_vec(ptr, c_ptr_array_len(ptr))
1550            }
1551        }
1552
1553        impl FromGlibPtrArrayContainerAsVec<$ffi_name, *const $ffi_name> for $name {
1554            unsafe fn from_glib_none_as_vec(ptr: *const $ffi_name) -> Vec<Self> {
1555                FromGlibContainerAsVec::from_glib_none_num_as_vec(ptr, c_ptr_array_len(ptr))
1556            }
1557
1558            unsafe fn from_glib_container_as_vec(ptr: *const $ffi_name) -> Vec<Self> {
1559                FromGlibContainerAsVec::from_glib_container_num_as_vec(ptr, c_ptr_array_len(ptr))
1560            }
1561
1562            unsafe fn from_glib_full_as_vec(ptr: *const $ffi_name) -> Vec<Self> {
1563                FromGlibContainerAsVec::from_glib_full_num_as_vec(ptr, c_ptr_array_len(ptr))
1564            }
1565        }
1566    };
1567}
1568
1569// TODO: Deprecate this
1570impl_from_glib_container_as_vec_string!(String, *const c_char);
1571impl_from_glib_container_as_vec_string!(String, *mut c_char);
1572
1573impl_from_glib_container_as_vec_string!(PathBuf, *const c_char);
1574impl_from_glib_container_as_vec_string!(PathBuf, *mut c_char);
1575impl_from_glib_container_as_vec_string!(OsString, *const c_char);
1576impl_from_glib_container_as_vec_string!(OsString, *mut c_char);
1577
1578impl<P, PP: Ptr, T: FromGlibContainerAsVec<P, PP>> FromGlibContainer<P, PP> for Vec<T> {
1579    unsafe fn from_glib_none_num(ptr: PP, num: usize) -> Vec<T> {
1580        FromGlibContainerAsVec::from_glib_none_num_as_vec(ptr, num)
1581    }
1582
1583    unsafe fn from_glib_container_num(ptr: PP, num: usize) -> Vec<T> {
1584        FromGlibContainerAsVec::from_glib_container_num_as_vec(ptr, num)
1585    }
1586
1587    unsafe fn from_glib_full_num(ptr: PP, num: usize) -> Vec<T> {
1588        FromGlibContainerAsVec::from_glib_full_num_as_vec(ptr, num)
1589    }
1590}
1591
1592impl<P: Ptr, PP: Ptr, T: FromGlibPtrArrayContainerAsVec<P, PP>> FromGlibPtrContainer<P, PP>
1593    for Vec<T>
1594{
1595    unsafe fn from_glib_none(ptr: PP) -> Vec<T> {
1596        FromGlibPtrArrayContainerAsVec::from_glib_none_as_vec(ptr)
1597    }
1598
1599    unsafe fn from_glib_container(ptr: PP) -> Vec<T> {
1600        FromGlibPtrArrayContainerAsVec::from_glib_container_as_vec(ptr)
1601    }
1602
1603    unsafe fn from_glib_full(ptr: PP) -> Vec<T> {
1604        FromGlibPtrArrayContainerAsVec::from_glib_full_as_vec(ptr)
1605    }
1606}
1607
1608impl<T> FromGlibContainerAsVec<<T as GlibPtrDefault>::GlibType, *mut glib_sys::GSList> for T
1609where
1610    T: GlibPtrDefault
1611        + FromGlibPtrNone<<T as GlibPtrDefault>::GlibType>
1612        + FromGlibPtrFull<<T as GlibPtrDefault>::GlibType>,
1613{
1614    unsafe fn from_glib_none_num_as_vec(mut ptr: *mut glib_sys::GSList, num: usize) -> Vec<T> {
1615        if num == 0 || ptr.is_null() {
1616            return Vec::new();
1617        }
1618        let mut res = Vec::with_capacity(num);
1619        for _ in 0..num {
1620            let item_ptr: <T as GlibPtrDefault>::GlibType = Ptr::from((*ptr).data);
1621            if !item_ptr.is_null() {
1622                res.push(from_glib_none(item_ptr));
1623            }
1624            ptr = (*ptr).next;
1625        }
1626        res
1627    }
1628
1629    unsafe fn from_glib_container_num_as_vec(ptr: *mut glib_sys::GSList, num: usize) -> Vec<T> {
1630        let res = FromGlibContainer::from_glib_none_num(ptr, num);
1631        if !ptr.is_null() {
1632            glib_sys::g_slist_free(ptr as *mut _);
1633        }
1634        res
1635    }
1636
1637    unsafe fn from_glib_full_num_as_vec(mut ptr: *mut glib_sys::GSList, num: usize) -> Vec<T> {
1638        if num == 0 || ptr.is_null() {
1639            return Vec::new();
1640        }
1641        let orig_ptr = ptr;
1642        let mut res = Vec::with_capacity(num);
1643        for _ in 0..num {
1644            let item_ptr: <T as GlibPtrDefault>::GlibType = Ptr::from((*ptr).data);
1645            if !item_ptr.is_null() {
1646                res.push(from_glib_full(item_ptr));
1647            }
1648            ptr = (*ptr).next;
1649        }
1650        glib_sys::g_slist_free(orig_ptr as *mut _);
1651        res
1652    }
1653}
1654
1655impl<T> FromGlibPtrArrayContainerAsVec<<T as GlibPtrDefault>::GlibType, *mut glib_sys::GSList> for T
1656where
1657    T: GlibPtrDefault
1658        + FromGlibPtrNone<<T as GlibPtrDefault>::GlibType>
1659        + FromGlibPtrFull<<T as GlibPtrDefault>::GlibType>,
1660{
1661    unsafe fn from_glib_none_as_vec(ptr: *mut glib_sys::GSList) -> Vec<T> {
1662        let num = glib_sys::g_slist_length(ptr) as usize;
1663        FromGlibContainer::from_glib_none_num(ptr, num)
1664    }
1665
1666    unsafe fn from_glib_container_as_vec(ptr: *mut glib_sys::GSList) -> Vec<T> {
1667        let num = glib_sys::g_slist_length(ptr) as usize;
1668        FromGlibContainer::from_glib_container_num(ptr, num)
1669    }
1670
1671    unsafe fn from_glib_full_as_vec(ptr: *mut glib_sys::GSList) -> Vec<T> {
1672        let num = glib_sys::g_slist_length(ptr) as usize;
1673        FromGlibContainer::from_glib_full_num(ptr, num)
1674    }
1675}
1676
1677impl<T> FromGlibContainerAsVec<<T as GlibPtrDefault>::GlibType, *mut glib_sys::GList> for T
1678where
1679    T: GlibPtrDefault
1680        + FromGlibPtrNone<<T as GlibPtrDefault>::GlibType>
1681        + FromGlibPtrFull<<T as GlibPtrDefault>::GlibType>,
1682{
1683    unsafe fn from_glib_none_num_as_vec(mut ptr: *mut glib_sys::GList, num: usize) -> Vec<T> {
1684        if num == 0 || ptr.is_null() {
1685            return Vec::new();
1686        }
1687        let mut res = Vec::with_capacity(num);
1688        for _ in 0..num {
1689            let item_ptr: <T as GlibPtrDefault>::GlibType = Ptr::from((*ptr).data);
1690            if !item_ptr.is_null() {
1691                res.push(from_glib_none(item_ptr));
1692            }
1693            ptr = (*ptr).next;
1694        }
1695        res
1696    }
1697
1698    unsafe fn from_glib_container_num_as_vec(ptr: *mut glib_sys::GList, num: usize) -> Vec<T> {
1699        let res = FromGlibContainer::from_glib_none_num(ptr, num);
1700        if !ptr.is_null() {
1701            glib_sys::g_list_free(ptr as *mut _);
1702        }
1703        res
1704    }
1705
1706    unsafe fn from_glib_full_num_as_vec(mut ptr: *mut glib_sys::GList, num: usize) -> Vec<T> {
1707        if num == 0 || ptr.is_null() {
1708            return Vec::new();
1709        }
1710        let orig_ptr = ptr;
1711        let mut res = Vec::with_capacity(num);
1712        for _ in 0..num {
1713            let item_ptr: <T as GlibPtrDefault>::GlibType = Ptr::from((*ptr).data);
1714            if !item_ptr.is_null() {
1715                res.push(from_glib_full(item_ptr));
1716            }
1717            ptr = (*ptr).next;
1718        }
1719        glib_sys::g_list_free(orig_ptr as *mut _);
1720        res
1721    }
1722}
1723
1724impl<T> FromGlibPtrArrayContainerAsVec<<T as GlibPtrDefault>::GlibType, *mut glib_sys::GList> for T
1725where
1726    T: GlibPtrDefault
1727        + FromGlibPtrNone<<T as GlibPtrDefault>::GlibType>
1728        + FromGlibPtrFull<<T as GlibPtrDefault>::GlibType>,
1729{
1730    unsafe fn from_glib_none_as_vec(ptr: *mut glib_sys::GList) -> Vec<T> {
1731        let num = glib_sys::g_list_length(ptr) as usize;
1732        FromGlibContainer::from_glib_none_num(ptr, num)
1733    }
1734
1735    unsafe fn from_glib_container_as_vec(ptr: *mut glib_sys::GList) -> Vec<T> {
1736        let num = glib_sys::g_list_length(ptr) as usize;
1737        FromGlibContainer::from_glib_container_num(ptr, num)
1738    }
1739
1740    unsafe fn from_glib_full_as_vec(ptr: *mut glib_sys::GList) -> Vec<T> {
1741        let num = glib_sys::g_list_length(ptr) as usize;
1742        FromGlibContainer::from_glib_full_num(ptr, num)
1743    }
1744}
1745
1746impl<T> FromGlibContainerAsVec<<T as GlibPtrDefault>::GlibType, *const glib_sys::GList> for T
1747where
1748    T: GlibPtrDefault
1749        + FromGlibPtrNone<<T as GlibPtrDefault>::GlibType>
1750        + FromGlibPtrFull<<T as GlibPtrDefault>::GlibType>,
1751{
1752    unsafe fn from_glib_none_num_as_vec(ptr: *const glib_sys::GList, num: usize) -> Vec<T> {
1753        FromGlibContainer::from_glib_none_num(mut_override(ptr), num)
1754    }
1755
1756    unsafe fn from_glib_container_num_as_vec(_: *const glib_sys::GList, _: usize) -> Vec<T> {
1757        // Can't really free a *const
1758        unimplemented!()
1759    }
1760
1761    unsafe fn from_glib_full_num_as_vec(_: *const glib_sys::GList, _: usize) -> Vec<T> {
1762        // Can't really free a *const
1763        unimplemented!()
1764    }
1765}
1766
1767impl<T> FromGlibPtrArrayContainerAsVec<<T as GlibPtrDefault>::GlibType, *const glib_sys::GList>
1768    for T
1769where
1770    T: GlibPtrDefault
1771        + FromGlibPtrNone<<T as GlibPtrDefault>::GlibType>
1772        + FromGlibPtrFull<<T as GlibPtrDefault>::GlibType>,
1773{
1774    unsafe fn from_glib_none_as_vec(ptr: *const glib_sys::GList) -> Vec<T> {
1775        FromGlibPtrContainer::from_glib_none(mut_override(ptr))
1776    }
1777
1778    unsafe fn from_glib_container_as_vec(_: *const glib_sys::GList) -> Vec<T> {
1779        // Can't really free a *const
1780        unimplemented!()
1781    }
1782
1783    unsafe fn from_glib_full_as_vec(_: *const glib_sys::GList) -> Vec<T> {
1784        // Can't really free a *const
1785        unimplemented!()
1786    }
1787}
1788
1789impl<T> FromGlibContainerAsVec<<T as GlibPtrDefault>::GlibType, *const glib_sys::GSList> for T
1790where
1791    T: GlibPtrDefault
1792        + FromGlibPtrNone<<T as GlibPtrDefault>::GlibType>
1793        + FromGlibPtrFull<<T as GlibPtrDefault>::GlibType>,
1794{
1795    unsafe fn from_glib_none_num_as_vec(ptr: *const glib_sys::GSList, num: usize) -> Vec<T> {
1796        FromGlibContainer::from_glib_none_num(mut_override(ptr), num)
1797    }
1798
1799    unsafe fn from_glib_container_num_as_vec(_: *const glib_sys::GSList, _: usize) -> Vec<T> {
1800        // Can't really free a *const
1801        unimplemented!()
1802    }
1803
1804    unsafe fn from_glib_full_num_as_vec(_: *const glib_sys::GSList, _: usize) -> Vec<T> {
1805        // Can't really free a *const
1806        unimplemented!()
1807    }
1808}
1809
1810impl<T> FromGlibPtrArrayContainerAsVec<<T as GlibPtrDefault>::GlibType, *const glib_sys::GSList>
1811    for T
1812where
1813    T: GlibPtrDefault
1814        + FromGlibPtrNone<<T as GlibPtrDefault>::GlibType>
1815        + FromGlibPtrFull<<T as GlibPtrDefault>::GlibType>,
1816{
1817    unsafe fn from_glib_none_as_vec(ptr: *const glib_sys::GSList) -> Vec<T> {
1818        FromGlibPtrContainer::from_glib_none(mut_override(ptr))
1819    }
1820
1821    unsafe fn from_glib_container_as_vec(_: *const glib_sys::GSList) -> Vec<T> {
1822        // Can't really free a *const
1823        unimplemented!()
1824    }
1825
1826    unsafe fn from_glib_full_as_vec(_: *const glib_sys::GSList) -> Vec<T> {
1827        // Can't really free a *const
1828        unimplemented!()
1829    }
1830}
1831
1832#[allow(clippy::implicit_hasher)]
1833impl FromGlibContainer<*const c_char, *mut glib_sys::GHashTable> for HashMap<String, String> {
1834    unsafe fn from_glib_none_num(ptr: *mut glib_sys::GHashTable, _: usize) -> Self {
1835        FromGlibPtrContainer::from_glib_none(ptr)
1836    }
1837
1838    unsafe fn from_glib_container_num(ptr: *mut glib_sys::GHashTable, _: usize) -> Self {
1839        FromGlibPtrContainer::from_glib_full(ptr)
1840    }
1841
1842    unsafe fn from_glib_full_num(ptr: *mut glib_sys::GHashTable, _: usize) -> Self {
1843        FromGlibPtrContainer::from_glib_full(ptr)
1844    }
1845}
1846
1847#[allow(clippy::implicit_hasher)]
1848impl FromGlibPtrContainer<*const c_char, *mut glib_sys::GHashTable> for HashMap<String, String> {
1849    unsafe fn from_glib_none(ptr: *mut glib_sys::GHashTable) -> Self {
1850        unsafe extern "C" fn read_string_hash_table(
1851            key: glib_sys::gpointer,
1852            value: glib_sys::gpointer,
1853            hash_map: glib_sys::gpointer,
1854        ) {
1855            let key: String = from_glib_none(key as *const c_char);
1856            let value: String = from_glib_none(value as *const c_char);
1857            let hash_map: &mut HashMap<String, String> =
1858                &mut *(hash_map as *mut HashMap<String, String>);
1859            hash_map.insert(key, value);
1860        }
1861        let mut map = HashMap::new();
1862        glib_sys::g_hash_table_foreach(
1863            ptr,
1864            Some(read_string_hash_table),
1865            &mut map as *mut HashMap<String, String> as *mut _,
1866        );
1867        map
1868    }
1869
1870    unsafe fn from_glib_container(ptr: *mut glib_sys::GHashTable) -> Self {
1871        FromGlibPtrContainer::from_glib_full(ptr)
1872    }
1873
1874    unsafe fn from_glib_full(ptr: *mut glib_sys::GHashTable) -> Self {
1875        let map = FromGlibPtrContainer::from_glib_none(ptr);
1876        glib_sys::g_hash_table_unref(ptr);
1877        map
1878    }
1879}
1880
1881#[cfg(test)]
1882mod tests {
1883    extern crate tempfile;
1884    use self::tempfile::tempdir;
1885    use std::fs;
1886
1887    use super::*;
1888    use glib_sys;
1889    use gstring::GString;
1890    use std::collections::HashMap;
1891
1892    #[test]
1893    fn string_hash_map() {
1894        let mut map = HashMap::new();
1895        map.insert("A".into(), "1".into());
1896        map.insert("B".into(), "2".into());
1897        map.insert("C".into(), "3".into());
1898        let ptr: *mut glib_sys::GHashTable = map.to_glib_full();
1899        let map = unsafe { HashMap::from_glib_full(ptr) };
1900        assert_eq!(map.get("A"), Some(&"1".into()));
1901        assert_eq!(map.get("B"), Some(&"2".into()));
1902        assert_eq!(map.get("C"), Some(&"3".into()));
1903    }
1904
1905    #[test]
1906    fn string_array() {
1907        let v = vec!["A".to_string(), "B".to_string(), "C".to_string()];
1908        let stash = v.to_glib_none();
1909        let ptr: *mut *mut c_char = stash.0;
1910        let ptr_copy = unsafe { glib_sys::g_strdupv(ptr) };
1911
1912        let actual: Vec<String> = unsafe { FromGlibPtrContainer::from_glib_full(ptr_copy) };
1913        assert_eq!(v, actual);
1914    }
1915
1916    #[test]
1917    fn gstring_array() {
1918        let v = vec!["A".to_string(), "B".to_string(), "C".to_string()];
1919        let stash = v.to_glib_none();
1920        let ptr: *mut *mut c_char = stash.0;
1921        let ptr_copy = unsafe { glib_sys::g_strdupv(ptr) };
1922
1923        let actual: Vec<GString> = unsafe { FromGlibPtrContainer::from_glib_full(ptr_copy) };
1924        assert_eq!(v, actual);
1925    }
1926
1927    #[test]
1928    #[cfg(not(target_os = "macos"))]
1929    fn test_paths() {
1930        let tmp_dir = tempdir().unwrap();
1931
1932        // Test if passing paths to GLib and getting them back
1933        // gives us useful results
1934        let dir_1 = tmp_dir.path().join("abcd");
1935        fs::create_dir(&dir_1).unwrap();
1936        assert_eq!(::functions::path_get_basename(&dir_1), Some("abcd".into()));
1937        assert_eq!(
1938            ::functions::path_get_basename(dir_1.canonicalize().unwrap()),
1939            Some("abcd".into())
1940        );
1941        assert_eq!(
1942            ::functions::path_get_dirname(dir_1.canonicalize().unwrap()),
1943            Some(tmp_dir.path().into())
1944        );
1945        assert!(::functions::file_test(
1946            &dir_1,
1947            ::FileTest::EXISTS | ::FileTest::IS_DIR
1948        ));
1949        assert!(::functions::file_test(
1950            &dir_1.canonicalize().unwrap(),
1951            ::FileTest::EXISTS | ::FileTest::IS_DIR
1952        ));
1953
1954        // And test with some non-ASCII characters
1955        let dir_2 = tmp_dir.as_ref().join("øäöü");
1956        fs::create_dir(&dir_2).unwrap();
1957        assert_eq!(
1958            ::functions::path_get_basename(&dir_2),
1959            Some("øäöü".into())
1960        );
1961        assert_eq!(
1962            ::functions::path_get_basename(dir_2.canonicalize().unwrap()),
1963            Some("øäöü".into())
1964        );
1965        assert_eq!(
1966            ::functions::path_get_dirname(dir_2.canonicalize().unwrap()),
1967            Some(tmp_dir.path().into())
1968        );
1969        assert!(::functions::file_test(
1970            &dir_2,
1971            ::FileTest::EXISTS | ::FileTest::IS_DIR
1972        ));
1973        assert!(::functions::file_test(
1974            &dir_2.canonicalize().unwrap(),
1975            ::FileTest::EXISTS | ::FileTest::IS_DIR
1976        ));
1977    }
1978
1979    #[test]
1980    #[cfg(target_os = "macos")]
1981    fn test_paths() {
1982        let t_dir = tempdir().unwrap();
1983        let tmp_dir = t_dir.path().canonicalize().unwrap();
1984
1985        // Test if passing paths to GLib and getting them back
1986        // gives us useful results
1987        let dir_1 = tmp_dir.join("abcd");
1988        fs::create_dir(&dir_1).unwrap();
1989        assert_eq!(::functions::path_get_basename(&dir_1), Some("abcd".into()));
1990        assert_eq!(
1991            ::functions::path_get_basename(dir_1.canonicalize().unwrap()),
1992            Some("abcd".into())
1993        );
1994        assert_eq!(
1995            ::functions::path_get_dirname(dir_1.canonicalize().unwrap()),
1996            Some(tmp_dir)
1997        );
1998        assert!(::functions::file_test(
1999            &dir_1,
2000            ::FileTest::EXISTS | ::FileTest::IS_DIR
2001        ));
2002        assert!(::functions::file_test(
2003            &dir_1.canonicalize().unwrap(),
2004            ::FileTest::EXISTS | ::FileTest::IS_DIR
2005        ));
2006    }
2007}