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::{Eq, Ordering, PartialEq},
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
149use libc::{c_char, size_t};
150
151// rustdoc-stripper-ignore-next
152/// A pointer
153pub trait Ptr: Copy + 'static {
154 fn is_null(&self) -> bool;
155 fn from<X>(ptr: *mut X) -> Self;
156 fn to<X>(self) -> *mut X;
157}
158
159impl<T: 'static> Ptr for *const T {
160 #[inline]
161 fn is_null(&self) -> bool {
162 (*self).is_null()
163 }
164
165 #[inline]
166 fn from<X>(ptr: *mut X) -> *const T {
167 ptr as *const T
168 }
169
170 #[inline]
171 fn to<X>(self) -> *mut X {
172 self as *mut X
173 }
174}
175
176impl<T: 'static> Ptr for *mut T {
177 #[inline]
178 fn is_null(&self) -> bool {
179 (*self).is_null()
180 }
181
182 #[inline]
183 fn from<X>(ptr: *mut X) -> *mut T {
184 ptr as *mut T
185 }
186
187 #[inline]
188 fn to<X>(self) -> *mut X {
189 self as *mut X
190 }
191}
192
193// rustdoc-stripper-ignore-next
194/// Overrides pointer mutability.
195///
196/// Use when the C API should be specifying a const pointer but doesn't.
197#[inline]
198pub fn mut_override<T>(ptr: *const T) -> *mut T {
199 ptr as *mut T
200}
201
202// rustdoc-stripper-ignore-next
203/// Overrides pointer constness.
204///
205/// Use when the C API need const pointer, but function with `IsA<T>` constraint,
206/// that usually don't have const pointer conversion.
207#[inline]
208pub fn const_override<T>(ptr: *mut T) -> *const T {
209 ptr as *const T
210}
211
212// rustdoc-stripper-ignore-next
213/// A trait for creating an uninitialized value. Handy for receiving outparams.
214pub trait Uninitialized {
215 // Returns an uninitialized value.
216 unsafe fn uninitialized() -> Self;
217}
218
219// rustdoc-stripper-ignore-next
220/// Returns an uninitialized value.
221#[inline]
222pub unsafe fn uninitialized<T: Uninitialized>() -> T {
223 T::uninitialized()
224}
225
226// rustdoc-stripper-ignore-next
227/// Helper type that stores temporary values used for translation.
228///
229/// `P` is the foreign type pointer and the first element of the tuple.
230///
231/// `T` is the Rust type that is translated.
232///
233/// The second element of the tuple is the temporary storage defined
234/// by the implementation of `ToGlibPtr<P> for T`
235///
236/// Say you want to pass a `*mut GdkWindowAttr` to a foreign function. The `Stash`
237/// will own a `GdkWindowAttr` and a `CString` that `GdkWindowAttr::title` points into.
238///
239/// ```ignore
240/// impl <'a> ToGlibPtr<'a, *mut ffi::GdkWindowAttr> for WindowAttr {
241/// type Storage = (Box<ffi::GdkWindowAttr>, Stash<'a, *const c_char, Option<String>>);
242///
243/// fn to_glib_none(&'a self) -> Stash<*mut ffi::GdkWindowAttr, WindowAttr> {
244/// let title = self.title.to_glib_none();
245///
246/// let mut attrs = Box::new(ffi::GdkWindowAttr {
247/// title: title.0,
248/// // ....
249/// });
250///
251/// Stash(&mut *attrs, (attrs, title))
252/// }
253/// }
254/// ```
255pub struct Stash<'a, P: Copy, T: ?Sized + ToGlibPtr<'a, P>>(
256 pub P,
257 pub <T as ToGlibPtr<'a, P>>::Storage,
258);
259
260pub struct StashMut<'a, P: Copy, T: ?Sized>(pub P, pub <T as ToGlibPtrMut<'a, P>>::Storage)
261where
262 T: ToGlibPtrMut<'a, P>;
263
264// rustdoc-stripper-ignore-next
265/// Wrapper around values representing borrowed C memory.
266///
267/// This is returned by `from_glib_borrow()` and ensures that the wrapped value
268/// is never dropped when going out of scope.
269///
270/// Borrowed values must never be passed by value or mutable reference to safe Rust code and must
271/// not leave the C scope in which they are valid.
272#[derive(Debug)]
273pub struct Borrowed<T>(mem::ManuallyDrop<T>);
274
275impl<T> Borrowed<T> {
276 // rustdoc-stripper-ignore-next
277 /// Creates a new borrowed value.
278 #[inline]
279 pub fn new(val: T) -> Self {
280 Self(mem::ManuallyDrop::new(val))
281 }
282
283 // rustdoc-stripper-ignore-next
284 /// Extracts the contained value.
285 ///
286 /// # Safety
287 ///
288 /// The returned value must never be dropped and instead has to be passed to `mem::forget()` or
289 /// be directly wrapped in `mem::ManuallyDrop` or another `Borrowed` wrapper.
290 #[inline]
291 pub unsafe fn into_inner(self) -> T {
292 mem::ManuallyDrop::into_inner(self.0)
293 }
294}
295
296impl<T> AsRef<T> for Borrowed<T> {
297 #[inline]
298 fn as_ref(&self) -> &T {
299 &self.0
300 }
301}
302
303impl<T> std::ops::Deref for Borrowed<T> {
304 type Target = T;
305
306 #[inline]
307 fn deref(&self) -> &T {
308 &self.0
309 }
310}
311
312// rustdoc-stripper-ignore-next
313/// Unsafe variant of the `From` trait.
314pub trait UnsafeFrom<T> {
315 // rustdoc-stripper-ignore-next
316 /// # Safety
317 ///
318 /// It is the responsibility of the caller to ensure *all* invariants of
319 /// the `T` hold before this is called, and that after conversion
320 /// to assume nothing other than the invariants of the output. Implementors
321 /// of this must ensure that the invariants of the output type hold.
322 unsafe fn unsafe_from(t: T) -> Self;
323}
324
325// rustdoc-stripper-ignore-next
326/// Translate a simple type.
327pub trait IntoGlib {
328 type GlibType: Copy;
329
330 fn into_glib(self) -> Self::GlibType;
331}
332
333impl IntoGlib for bool {
334 type GlibType = ffi::gboolean;
335
336 #[inline]
337 fn into_glib(self) -> ffi::gboolean {
338 if self {
339 ffi::GTRUE
340 } else {
341 ffi::GFALSE
342 }
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(default: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: O) => ok.into_glib(),
393 Err(err: E) => 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) => 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<'a, T: ?Sized + GlibPtrDefault> GlibPtrDefault for &'a 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<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(default:Stash(Ptr::from::<()>(ptr::null_mut()), None), |s: &T| {
477 let s: Stash<'_, P, T> = 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(default:Ptr::from::<()>(ptr::null_mut()), f: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(default:StashMut(Ptr::from::<()>(ptr::null_mut()), None), |s: &mut &mut T| {
496 let s: StashMut<'_, P, T> = 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: Stash<'_, P, T> = (*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: Stash<'_, *const i8, str> = 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: Stash<'_, *const i8, str> = 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: Stash<'_, *mut i8, str> = 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 unsafe fn into_glib_ptr(self) -> P;
716}
717
718impl<P: Ptr, T: IntoGlibPtr<P>> IntoGlibPtr<P> for Option<T> {
719 #[inline]
720 unsafe fn into_glib_ptr(self) -> P {
721 self.map_or(default:Ptr::from::<()>(ptr::null_mut()), |s: T| {
722 IntoGlibPtr::into_glib_ptr(self: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(msg:"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(msg:"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: CString = 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: CString = 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: CString = path_to_c(self);
824 unsafe { ffi::g_strdup(str: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: CString = 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: CString = 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: CString = path_to_c(self);
850 unsafe { ffi::g_strdup(str: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: CString = 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: CString = 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: CString = os_str_to_c(self);
884 unsafe { ffi::g_strdup(str: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: CString = 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: CString = 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: CString = os_str_to_c(self);
910 unsafe { ffi::g_strdup(str: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!(crate::GString, *mut c_char);
1085impl_to_glib_container_from_slice_string!(crate::GString, *const c_char);
1086
1087impl<'a, T> ToGlibContainerFromSlice<'a, *mut ffi::GList> for T
1088where
1089 T: GlibPtrDefault + ToGlibPtr<'a, <T as GlibPtrDefault>::GlibType>,
1090{
1091 type Storage = (
1092 Option<List>,
1093 Vec<Stash<'a, <T as GlibPtrDefault>::GlibType, T>>,
1094 );
1095
1096 #[inline]
1097 fn to_glib_none_from_slice(t: &'a [T]) -> (*mut ffi::GList, Self::Storage) {
1098 let stash_vec: Vec<_> = t.iter().rev().map(ToGlibPtr::to_glib_none).collect();
1099 let mut list: *mut ffi::GList = ptr::null_mut();
1100 unsafe {
1101 for stash in &stash_vec {
1102 list = ffi::g_list_prepend(list, Ptr::to(stash.0));
1103 }
1104 }
1105 let stash = (ptr::NonNull::new(list).map(List), stash_vec);
1106 (list, stash)
1107 }
1108
1109 #[inline]
1110 fn to_glib_container_from_slice(t: &'a [T]) -> (*mut ffi::GList, Self::Storage) {
1111 let stash_vec: Vec<_> = t.iter().rev().map(ToGlibPtr::to_glib_none).collect();
1112 let mut list: *mut ffi::GList = ptr::null_mut();
1113 unsafe {
1114 for stash in &stash_vec {
1115 list = ffi::g_list_prepend(list, Ptr::to(stash.0));
1116 }
1117 }
1118 (list, (None, stash_vec))
1119 }
1120
1121 #[inline]
1122 fn to_glib_full_from_slice(t: &[T]) -> *mut ffi::GList {
1123 let mut list: *mut ffi::GList = ptr::null_mut();
1124 unsafe {
1125 for ptr in t.iter().rev().map(ToGlibPtr::to_glib_full) {
1126 list = ffi::g_list_prepend(list, Ptr::to(ptr));
1127 }
1128 }
1129 list
1130 }
1131}
1132
1133impl<'a, T> ToGlibContainerFromSlice<'a, *const ffi::GList> for T
1134where
1135 T: GlibPtrDefault + ToGlibPtr<'a, <T as GlibPtrDefault>::GlibType>,
1136{
1137 type Storage = (
1138 Option<List>,
1139 Vec<Stash<'a, <T as GlibPtrDefault>::GlibType, T>>,
1140 );
1141
1142 #[inline]
1143 fn to_glib_none_from_slice(t: &'a [T]) -> (*const ffi::GList, Self::Storage) {
1144 let (list: *mut GList, stash: (Option, Vec>)) = ToGlibContainerFromSlice::<*mut ffi::GList>::to_glib_none_from_slice(t);
1145 (list as *const ffi::GList, stash)
1146 }
1147
1148 #[inline]
1149 fn to_glib_container_from_slice(_t: &'a [T]) -> (*const ffi::GList, Self::Storage) {
1150 unimplemented!()
1151 }
1152
1153 #[inline]
1154 fn to_glib_full_from_slice(_t: &[T]) -> *const ffi::GList {
1155 unimplemented!()
1156 }
1157}
1158
1159#[doc(alias = "GList")]
1160pub struct List(ptr::NonNull<ffi::GList>);
1161
1162impl Drop for List {
1163 #[inline]
1164 fn drop(&mut self) {
1165 unsafe { ffi::g_list_free(self.0.as_ptr()) }
1166 }
1167}
1168
1169impl<'a, T> ToGlibContainerFromSlice<'a, *mut ffi::GSList> for &'a T
1170where
1171 T: GlibPtrDefault + ToGlibPtr<'a, <T as GlibPtrDefault>::GlibType>,
1172{
1173 type Storage = (
1174 Option<SList>,
1175 Vec<Stash<'a, <T as GlibPtrDefault>::GlibType, &'a T>>,
1176 );
1177
1178 #[inline]
1179 fn to_glib_none_from_slice(t: &'a [&'a T]) -> (*mut ffi::GSList, Self::Storage) {
1180 let stash_vec: Vec<_> = t.iter().rev().map(ToGlibPtr::to_glib_none).collect();
1181 let mut list: *mut ffi::GSList = ptr::null_mut();
1182 unsafe {
1183 for stash in &stash_vec {
1184 list = ffi::g_slist_prepend(list, Ptr::to(stash.0));
1185 }
1186 }
1187
1188 let stash = (ptr::NonNull::new(list).map(SList), stash_vec);
1189 (list, stash)
1190 }
1191
1192 #[inline]
1193 fn to_glib_container_from_slice(t: &'a [&'a T]) -> (*mut ffi::GSList, Self::Storage) {
1194 let stash_vec: Vec<_> = t.iter().rev().map(ToGlibPtr::to_glib_none).collect();
1195 let mut list: *mut ffi::GSList = ptr::null_mut();
1196 unsafe {
1197 for stash in &stash_vec {
1198 list = ffi::g_slist_prepend(list, Ptr::to(stash.0));
1199 }
1200 }
1201 (list, (None, stash_vec))
1202 }
1203
1204 #[inline]
1205 fn to_glib_full_from_slice(t: &[&'a T]) -> *mut ffi::GSList {
1206 let mut list: *mut ffi::GSList = ptr::null_mut();
1207 unsafe {
1208 for ptr in t.iter().rev().map(ToGlibPtr::to_glib_full) {
1209 list = ffi::g_slist_prepend(list, Ptr::to(ptr));
1210 }
1211 }
1212 list
1213 }
1214}
1215
1216impl<'a, T> ToGlibContainerFromSlice<'a, *const ffi::GSList> for &'a T
1217where
1218 T: GlibPtrDefault + ToGlibPtr<'a, <T as GlibPtrDefault>::GlibType>,
1219{
1220 type Storage = (
1221 Option<SList>,
1222 Vec<Stash<'a, <T as GlibPtrDefault>::GlibType, &'a T>>,
1223 );
1224
1225 #[inline]
1226 fn to_glib_none_from_slice(t: &'a [&'a T]) -> (*const ffi::GSList, Self::Storage) {
1227 let (list: *mut GSList, stash: (Option, Vec>)) =
1228 ToGlibContainerFromSlice::<*mut ffi::GSList>::to_glib_none_from_slice(t);
1229 (list as *const ffi::GSList, stash)
1230 }
1231
1232 #[inline]
1233 fn to_glib_container_from_slice(_t: &'a [&'a T]) -> (*const ffi::GSList, Self::Storage) {
1234 unimplemented!()
1235 }
1236
1237 #[inline]
1238 fn to_glib_full_from_slice(_t: &[&'a T]) -> *const ffi::GSList {
1239 unimplemented!()
1240 }
1241}
1242
1243#[doc(alias = "GSList")]
1244pub struct SList(ptr::NonNull<ffi::GSList>);
1245
1246impl Drop for SList {
1247 #[inline]
1248 fn drop(&mut self) {
1249 unsafe { ffi::g_slist_free(self.0.as_ptr()) }
1250 }
1251}
1252
1253impl<'a, P: Ptr, T: ToGlibContainerFromSlice<'a, P>> ToGlibPtr<'a, P> for [T] {
1254 type Storage = T::Storage;
1255
1256 #[inline]
1257 fn to_glib_none(&'a self) -> Stash<'a, P, Self> {
1258 let result: (P, >::Storage) = ToGlibContainerFromSlice::to_glib_none_from_slice(self);
1259 Stash(result.0, result.1)
1260 }
1261
1262 #[inline]
1263 fn to_glib_container(&'a self) -> Stash<'a, P, Self> {
1264 let result: (P, >::Storage) = ToGlibContainerFromSlice::to_glib_container_from_slice(self);
1265 Stash(result.0, result.1)
1266 }
1267
1268 #[inline]
1269 fn to_glib_full(&self) -> P {
1270 ToGlibContainerFromSlice::to_glib_full_from_slice(self)
1271 }
1272}
1273
1274#[allow(clippy::implicit_hasher)]
1275impl<'a> ToGlibPtr<'a, *mut ffi::GHashTable> for HashMap<String, String> {
1276 type Storage = HashTable;
1277
1278 #[inline]
1279 fn to_glib_none(&self) -> Stash<'a, *mut ffi::GHashTable, Self> {
1280 let ptr = self.to_glib_full();
1281 Stash(ptr, HashTable(unsafe { ptr::NonNull::new_unchecked(ptr) }))
1282 }
1283
1284 #[inline]
1285 fn to_glib_full(&self) -> *mut ffi::GHashTable {
1286 unsafe {
1287 let ptr = ffi::g_hash_table_new_full(
1288 Some(ffi::g_str_hash),
1289 Some(ffi::g_str_equal),
1290 Some(ffi::g_free),
1291 Some(ffi::g_free),
1292 );
1293 for (k, v) in self {
1294 let k: *mut c_char = k.to_glib_full();
1295 let v: *mut c_char = v.to_glib_full();
1296 ffi::g_hash_table_insert(ptr, k as *mut _, v as *mut _);
1297 }
1298 ptr
1299 }
1300 }
1301}
1302
1303#[doc(alias = "GHashTable")]
1304pub struct HashTable(ptr::NonNull<ffi::GHashTable>);
1305
1306impl Drop for HashTable {
1307 #[inline]
1308 fn drop(&mut self) {
1309 unsafe { ffi::g_hash_table_unref(self.0.as_ptr()) }
1310 }
1311}
1312
1313#[doc(alias = "GPtrArray")]
1314pub struct PtrArray(ptr::NonNull<ffi::GPtrArray>);
1315
1316impl Drop for PtrArray {
1317 #[inline]
1318 fn drop(&mut self) {
1319 unsafe {
1320 ffi::g_ptr_array_unref(self.0.as_ptr());
1321 }
1322 }
1323}
1324
1325impl<'a, T> ToGlibContainerFromSlice<'a, *mut ffi::GPtrArray> for T
1326where
1327 T: GlibPtrDefault + ToGlibPtr<'a, <T as GlibPtrDefault>::GlibType>,
1328{
1329 type Storage = (
1330 Option<PtrArray>,
1331 Vec<Stash<'a, <T as GlibPtrDefault>::GlibType, T>>,
1332 );
1333
1334 #[inline]
1335 fn to_glib_none_from_slice(t: &'a [T]) -> (*mut ffi::GPtrArray, Self::Storage) {
1336 let stash_vec: Vec<_> = t.iter().map(ToGlibPtr::to_glib_none).collect();
1337 let arr = unsafe { ffi::g_ptr_array_sized_new(t.len() as _) };
1338 unsafe {
1339 for stash in &stash_vec {
1340 ffi::g_ptr_array_add(arr, Ptr::to(stash.0));
1341 }
1342 }
1343
1344 (
1345 arr,
1346 (
1347 Some(PtrArray(unsafe { ptr::NonNull::new_unchecked(arr) })),
1348 stash_vec,
1349 ),
1350 )
1351 }
1352
1353 #[inline]
1354 fn to_glib_container_from_slice(t: &'a [T]) -> (*mut ffi::GPtrArray, Self::Storage) {
1355 let stash_vec: Vec<_> = t.iter().map(ToGlibPtr::to_glib_none).collect();
1356 let arr = unsafe { ffi::g_ptr_array_sized_new(t.len() as _) };
1357 unsafe {
1358 for stash in &stash_vec {
1359 ffi::g_ptr_array_add(arr, Ptr::to(stash.0));
1360 }
1361 }
1362 (arr, (None, stash_vec))
1363 }
1364
1365 #[inline]
1366 fn to_glib_full_from_slice(t: &[T]) -> *mut ffi::GPtrArray {
1367 let arr = unsafe { ffi::g_ptr_array_sized_new(t.len() as _) };
1368 unsafe {
1369 for ptr in t.iter().map(ToGlibPtr::to_glib_full) {
1370 ffi::g_ptr_array_add(arr, Ptr::to(ptr));
1371 }
1372 }
1373 arr
1374 }
1375}
1376
1377impl<'a, T> ToGlibContainerFromSlice<'a, *const ffi::GPtrArray> for T
1378where
1379 T: GlibPtrDefault + ToGlibPtr<'a, <T as GlibPtrDefault>::GlibType>,
1380{
1381 type Storage = (
1382 Option<PtrArray>,
1383 Vec<Stash<'a, <T as GlibPtrDefault>::GlibType, T>>,
1384 );
1385
1386 #[inline]
1387 fn to_glib_none_from_slice(t: &'a [T]) -> (*const ffi::GPtrArray, Self::Storage) {
1388 let (arr: *mut GPtrArray, stash: (Option, Vec>)) =
1389 ToGlibContainerFromSlice::<*mut ffi::GPtrArray>::to_glib_none_from_slice(t);
1390 (arr as *const ffi::GPtrArray, stash)
1391 }
1392
1393 #[inline]
1394 fn to_glib_container_from_slice(_t: &'a [T]) -> (*const ffi::GPtrArray, Self::Storage) {
1395 unimplemented!()
1396 }
1397
1398 #[inline]
1399 fn to_glib_full_from_slice(_t: &[T]) -> *const ffi::GPtrArray {
1400 unimplemented!()
1401 }
1402}
1403
1404// rustdoc-stripper-ignore-next
1405/// Translate a simple type.
1406pub trait FromGlib<G: Copy>: Sized {
1407 unsafe fn from_glib(val: G) -> Self;
1408}
1409
1410// rustdoc-stripper-ignore-next
1411/// Translate a simple type.
1412#[inline]
1413pub unsafe fn from_glib<G: Copy, T: FromGlib<G>>(val: G) -> T {
1414 FromGlib::from_glib(val)
1415}
1416
1417impl FromGlib<ffi::gboolean> for bool {
1418 #[inline]
1419 unsafe fn from_glib(val: ffi::gboolean) -> Self {
1420 val != ffi::GFALSE
1421 }
1422}
1423
1424impl FromGlib<i32> for Ordering {
1425 #[inline]
1426 unsafe fn from_glib(val: i32) -> Self {
1427 val.cmp(&0)
1428 }
1429}
1430
1431// rustdoc-stripper-ignore-next
1432/// Translate from a Glib type which can result in an undefined and/or invalid value.
1433pub trait TryFromGlib<G: Copy>: Sized {
1434 type Error;
1435 unsafe fn try_from_glib(val: G) -> Result<Self, Self::Error>;
1436}
1437
1438// rustdoc-stripper-ignore-next
1439/// Translate from a Glib type which can result in an undefined and/or invalid value.
1440#[inline]
1441pub unsafe fn try_from_glib<G: Copy, T: TryFromGlib<G>>(
1442 val: G,
1443) -> Result<T, <T as TryFromGlib<G>>::Error> {
1444 TryFromGlib::try_from_glib(val)
1445}
1446
1447// rustdoc-stripper-ignore-next
1448/// Error type for [`TryFromGlib`] when the Glib value is None.
1449#[derive(Debug, PartialEq, Eq)]
1450pub struct GlibNoneError;
1451
1452impl fmt::Display for GlibNoneError {
1453 fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
1454 write!(fmt, "glib value is None")
1455 }
1456}
1457
1458impl std::error::Error for GlibNoneError {}
1459
1460impl<G: Copy, T: TryFromGlib<G, Error = GlibNoneError>> FromGlib<G> for Option<T> {
1461 #[inline]
1462 unsafe fn from_glib(val: G) -> Self {
1463 T::try_from_glib(val).ok()
1464 }
1465}
1466
1467// rustdoc-stripper-ignore-next
1468/// Error type for [`TryFromGlib`] when the Glib value can be None or invalid.
1469#[derive(Debug, Eq, PartialEq)]
1470pub enum GlibNoneOrInvalidError<I: Error> {
1471 Invalid(I),
1472 None,
1473}
1474
1475impl<I: Error> GlibNoneOrInvalidError<I> {
1476 // rustdoc-stripper-ignore-next
1477 /// Builds the `None` variant.
1478 #[inline]
1479 pub fn none() -> Self {
1480 Self::None
1481 }
1482
1483 // rustdoc-stripper-ignore-next
1484 /// Returns `true` if `self` is the `None` variant.
1485 #[inline]
1486 pub fn is_none(&self) -> bool {
1487 matches!(self, Self::None)
1488 }
1489
1490 // rustdoc-stripper-ignore-next
1491 /// Returns `true` if `self` is the `Invalid` variant.
1492 #[inline]
1493 pub fn is_invalid(&self) -> bool {
1494 matches!(self, Self::Invalid(_))
1495 }
1496}
1497
1498impl<I: Error> From<I> for GlibNoneOrInvalidError<I> {
1499 #[inline]
1500 fn from(invalid: I) -> Self {
1501 Self::Invalid(invalid)
1502 }
1503}
1504
1505impl<I: Error> fmt::Display for GlibNoneOrInvalidError<I> {
1506 fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
1507 match self {
1508 Self::Invalid(err: &I) => {
1509 write!(fmt, "glib value is invalid: ")?;
1510 fmt::Display::fmt(self:err, f:fmt)
1511 }
1512 Self::None => write!(fmt, "glib value is None"),
1513 }
1514 }
1515}
1516
1517impl<I: Error> Error for GlibNoneOrInvalidError<I> {}
1518
1519impl<G: Copy, I: Error, T: TryFromGlib<G, Error = GlibNoneOrInvalidError<I>>> FromGlib<G>
1520 for Result<Option<T>, I>
1521{
1522 #[inline]
1523 unsafe fn from_glib(val: G) -> Self {
1524 match T::try_from_glib(val) {
1525 Ok(value: T) => Ok(Some(value)),
1526 Err(GlibNoneOrInvalidError::None) => Ok(None),
1527 Err(GlibNoneOrInvalidError::Invalid(err: I)) => Err(err),
1528 }
1529 }
1530}
1531
1532// rustdoc-stripper-ignore-next
1533/// Translate from a pointer type which is annotated with `transfer none`.
1534/// The resulting value is referenced at least once, by the bindings.
1535///
1536/// This is suitable for floating references, which become strong references.
1537/// It is also suitable for acquiring non-gobject values, like `gchar*`.
1538///
1539/// <a name="safety_points"></a>
1540/// # Safety
1541///
1542/// The implementation of this trait should acquire a reference to the value
1543/// in a way appropriate to the type,
1544/// e.g. by increasing the reference count or copying.
1545/// Values obtained using this trait must be properly released on `drop()`
1546/// by the implementing type.
1547///
1548/// For more information, refer to module level documentation.
1549pub trait FromGlibPtrNone<P: Ptr>: Sized {
1550 // rustdoc-stripper-ignore-next
1551 /// # Safety
1552 ///
1553 /// See trait level [notes on safety](#safety_points)
1554 unsafe fn from_glib_none(ptr: P) -> Self;
1555}
1556
1557// rustdoc-stripper-ignore-next
1558/// Translate from a pointer type which is annotated with `transfer full`.
1559/// This transfers the ownership of the value to the Rust side.
1560///
1561/// Because ownership can only be transferred if something is already referenced,
1562/// this is unsuitable for floating references.
1563///
1564/// <a name="safety_points"></a>
1565/// # Safety
1566///
1567/// The implementation of this trait should not alter the reference count
1568/// or make copies of the underlying value.
1569/// Values obtained using this trait must be properly released on `drop()`
1570/// by the implementing type.
1571///
1572/// For more information, refer to module level documentation.
1573pub trait FromGlibPtrFull<P: Ptr>: Sized {
1574 // rustdoc-stripper-ignore-next
1575 /// # Safety
1576 ///
1577 /// See trait level [notes on safety](#safety_points)
1578 unsafe fn from_glib_full(ptr: P) -> Self;
1579}
1580
1581// rustdoc-stripper-ignore-next
1582/// Translate from a pointer type by borrowing, without affecting the refcount.
1583///
1584/// The purpose of this trait is to access values inside callbacks
1585/// without changing their reference status.
1586/// The obtained borrow must not be accessed outside of the scope of the callback,
1587/// and called procedures must not store any references to the underlying data.
1588/// Safe Rust code must never obtain a mutable Rust reference.
1589///
1590/// <a name="safety_points"></a>
1591/// # Safety
1592///
1593/// The implementation of this trait as well as the returned type
1594/// must satisfy the same constraints together.
1595/// They must not take ownership of the underlying value, copy it,
1596/// and should not change its reference count.
1597/// If it does, it must properly release obtained references.
1598///
1599/// The returned value, when dropped,
1600/// must leave the underlying value in the same state
1601/// as before from_glib_borrow was called:
1602/// - it must not be dropped,
1603/// - it must be the same type of reference, e.g. still floating.
1604///
1605/// For more information, refer to module level documentation.
1606pub trait FromGlibPtrBorrow<P: Ptr>: Sized {
1607 // rustdoc-stripper-ignore-next
1608 /// # Safety
1609 ///
1610 /// See trait level [notes on safety](#safety_points)
1611 unsafe fn from_glib_borrow(_ptr: P) -> Borrowed<Self> {
1612 unimplemented!();
1613 }
1614}
1615
1616// rustdoc-stripper-ignore-next
1617/// Translate from a pointer type, transfer: none.
1618///
1619/// See [`FromGlibPtrNone`](trait.FromGlibPtrNone.html).
1620#[inline]
1621pub unsafe fn from_glib_none<P: Ptr, T: FromGlibPtrNone<P>>(ptr: P) -> T {
1622 FromGlibPtrNone::from_glib_none(ptr)
1623}
1624
1625// rustdoc-stripper-ignore-next
1626/// Translate from a pointer type, transfer: full (assume ownership).
1627///
1628/// See [`FromGlibPtrFull`](trait.FromGlibPtrFull.html).
1629#[inline]
1630pub unsafe fn from_glib_full<P: Ptr, T: FromGlibPtrFull<P>>(ptr: P) -> T {
1631 FromGlibPtrFull::from_glib_full(ptr)
1632}
1633
1634// rustdoc-stripper-ignore-next
1635/// Translate from a pointer type, borrowing the pointer.
1636///
1637/// See [`FromGlibPtrBorrow`](trait.FromGlibPtrBorrow.html).
1638#[inline]
1639pub unsafe fn from_glib_borrow<P: Ptr, T: FromGlibPtrBorrow<P>>(ptr: P) -> Borrowed<T> {
1640 FromGlibPtrBorrow::from_glib_borrow(ptr)
1641}
1642
1643impl<P: Ptr, T: FromGlibPtrNone<P>> FromGlibPtrNone<P> for Option<T> {
1644 #[inline]
1645 unsafe fn from_glib_none(ptr: P) -> Option<T> {
1646 if ptr.is_null() {
1647 None
1648 } else {
1649 Some(from_glib_none(ptr))
1650 }
1651 }
1652}
1653
1654impl<P: Ptr, T: FromGlibPtrBorrow<P>> FromGlibPtrBorrow<P> for Option<T> {
1655 #[inline]
1656 unsafe fn from_glib_borrow(ptr: P) -> Borrowed<Option<T>> {
1657 if ptr.is_null() {
1658 Borrowed::new(val:None)
1659 } else {
1660 let val: Borrowed = T::from_glib_borrow(ptr);
1661 Borrowed::new(val:Some(val.into_inner()))
1662 }
1663 }
1664}
1665
1666impl<P: Ptr, T: FromGlibPtrFull<P>> FromGlibPtrFull<P> for Option<T> {
1667 #[inline]
1668 unsafe fn from_glib_full(ptr: P) -> Option<T> {
1669 if ptr.is_null() {
1670 None
1671 } else {
1672 Some(from_glib_full(ptr))
1673 }
1674 }
1675}
1676
1677impl FromGlibPtrNone<*const c_char> for String {
1678 #[inline]
1679 unsafe fn from_glib_none(ptr: *const c_char) -> Self {
1680 debug_assert!(!ptr.is_null());
1681 Self::from_utf8_lossy(CStr::from_ptr(ptr).to_bytes()).into_owned()
1682 }
1683}
1684
1685// TODO: Deprecate this
1686impl FromGlibPtrFull<*const c_char> for String {
1687 #[inline]
1688 unsafe fn from_glib_full(ptr: *const c_char) -> Self {
1689 let res: String = from_glib_none(ptr);
1690 ffi::g_free(mem:ptr as *mut _);
1691 res
1692 }
1693}
1694
1695// TODO: Deprecate this
1696impl FromGlibPtrNone<*mut c_char> for String {
1697 #[inline]
1698 unsafe fn from_glib_none(ptr: *mut c_char) -> Self {
1699 debug_assert!(!ptr.is_null());
1700 Self::from_utf8_lossy(CStr::from_ptr(ptr).to_bytes()).into_owned()
1701 }
1702}
1703
1704// TODO: Deprecate this
1705impl FromGlibPtrFull<*mut c_char> for String {
1706 #[inline]
1707 unsafe fn from_glib_full(ptr: *mut c_char) -> Self {
1708 let res: String = from_glib_none(ptr);
1709 ffi::g_free(mem:ptr as *mut _);
1710 res
1711 }
1712}
1713
1714#[cfg(not(windows))]
1715pub(crate) unsafe fn c_to_path_buf(ptr: *const c_char) -> PathBuf {
1716 debug_assert!(!ptr.is_null());
1717
1718 // GLib paths on UNIX are always in the local encoding, which can be
1719 // UTF-8 or anything else really, but is always a NUL-terminated string
1720 // and must not contain any other NUL bytes
1721 OsString::from_vec(CStr::from_ptr(ptr).to_bytes().to_vec()).into()
1722}
1723
1724#[cfg(windows)]
1725pub(crate) unsafe fn c_to_path_buf(ptr: *const c_char) -> PathBuf {
1726 debug_assert!(!ptr.is_null());
1727
1728 // GLib paths on Windows are always UTF-8, as such we can convert to a String
1729 // first and then go to a PathBuf from there. Unless there is a bug
1730 // in the C library, the conversion from UTF-8 can never fail so we can
1731 // safely panic here if that ever happens
1732 String::from_utf8(CStr::from_ptr(ptr).to_bytes().into())
1733 .expect("Invalid, non-UTF8 path")
1734 .into()
1735}
1736
1737#[cfg(not(windows))]
1738pub(crate) unsafe fn c_to_os_string(ptr: *const c_char) -> OsString {
1739 debug_assert!(!ptr.is_null());
1740
1741 // GLib OS string (environment strings) on UNIX are always in the local encoding,
1742 // which can be UTF-8 or anything else really, but is always a NUL-terminated string
1743 // and must not contain any other NUL bytes
1744 OsString::from_vec(CStr::from_ptr(ptr).to_bytes().to_vec())
1745}
1746
1747#[cfg(windows)]
1748pub(crate) unsafe fn c_to_os_string(ptr: *const c_char) -> OsString {
1749 debug_assert!(!ptr.is_null());
1750
1751 // GLib OS string (environment strings) on Windows are always UTF-8,
1752 // as such we can convert to a String
1753 // first and then go to a OsString from there. Unless there is a bug
1754 // in the C library, the conversion from UTF-8 can never fail so we can
1755 // safely panic here if that ever happens
1756 String::from_utf8(CStr::from_ptr(ptr).to_bytes().into())
1757 .expect("Invalid, non-UTF8 path")
1758 .into()
1759}
1760
1761impl FromGlibPtrNone<*const c_char> for PathBuf {
1762 #[inline]
1763 unsafe fn from_glib_none(ptr: *const c_char) -> Self {
1764 debug_assert!(!ptr.is_null());
1765 c_to_path_buf(ptr)
1766 }
1767}
1768
1769impl FromGlibPtrFull<*const c_char> for PathBuf {
1770 #[inline]
1771 unsafe fn from_glib_full(ptr: *const c_char) -> Self {
1772 let res: PathBuf = from_glib_none(ptr);
1773 ffi::g_free(mem:ptr as *mut _);
1774 res
1775 }
1776}
1777
1778impl FromGlibPtrNone<*mut c_char> for PathBuf {
1779 #[inline]
1780 unsafe fn from_glib_none(ptr: *mut c_char) -> Self {
1781 debug_assert!(!ptr.is_null());
1782 c_to_path_buf(ptr)
1783 }
1784}
1785
1786impl FromGlibPtrFull<*mut c_char> for PathBuf {
1787 #[inline]
1788 unsafe fn from_glib_full(ptr: *mut c_char) -> Self {
1789 let res: PathBuf = from_glib_none(ptr);
1790 ffi::g_free(mem:ptr as *mut _);
1791 res
1792 }
1793}
1794
1795#[cfg(not(windows))]
1796pub(crate) unsafe fn c_to_path_buf_num(ptr: *const c_char, num: usize) -> PathBuf {
1797 debug_assert!(!ptr.is_null());
1798 let slice: &[u8] = std::slice::from_raw_parts(data:ptr as *const u8, len:num);
1799 OsString::from_vec(slice.to_vec()).into()
1800}
1801
1802#[cfg(windows)]
1803pub(crate) unsafe fn c_to_path_buf_num(ptr: *const c_char, num: usize) -> PathBuf {
1804 debug_assert!(!ptr.is_null());
1805 let slice = std::slice::from_raw_parts(ptr as *const u8, num);
1806 String::from_utf8(slice.into())
1807 .expect("Invalid, non-UTF8 path")
1808 .into()
1809}
1810
1811#[doc(hidden)]
1812impl FromGlibContainer<*const c_char, *const i8> for PathBuf {
1813 unsafe fn from_glib_none_num(ptr: *const i8, num: usize) -> Self {
1814 c_to_path_buf_num(ptr as *const _, num)
1815 }
1816
1817 unsafe fn from_glib_container_num(ptr: *const i8, num: usize) -> Self {
1818 c_to_path_buf_num(ptr as *const _, num)
1819 }
1820
1821 unsafe fn from_glib_full_num(ptr: *const i8, num: usize) -> Self {
1822 let res: PathBuf = c_to_path_buf_num(ptr as *const _, num);
1823 ffi::g_free(mem:ptr as *mut _);
1824 res
1825 }
1826}
1827
1828#[doc(hidden)]
1829impl FromGlibContainer<*const c_char, *mut i8> for PathBuf {
1830 unsafe fn from_glib_none_num(ptr: *mut i8, num: usize) -> Self {
1831 FromGlibContainer::from_glib_none_num(ptr as *const i8, num)
1832 }
1833
1834 unsafe fn from_glib_container_num(ptr: *mut i8, num: usize) -> Self {
1835 FromGlibContainer::from_glib_container_num(ptr as *const i8, num)
1836 }
1837
1838 unsafe fn from_glib_full_num(ptr: *mut i8, num: usize) -> Self {
1839 FromGlibContainer::from_glib_full_num(ptr as *const i8, num)
1840 }
1841}
1842
1843#[doc(hidden)]
1844impl FromGlibContainer<*const c_char, *const u8> for PathBuf {
1845 unsafe fn from_glib_none_num(ptr: *const u8, num: usize) -> Self {
1846 FromGlibContainer::from_glib_none_num(ptr as *const i8, num)
1847 }
1848
1849 unsafe fn from_glib_container_num(ptr: *const u8, num: usize) -> Self {
1850 FromGlibContainer::from_glib_container_num(ptr as *const i8, num)
1851 }
1852
1853 unsafe fn from_glib_full_num(ptr: *const u8, num: usize) -> Self {
1854 FromGlibContainer::from_glib_full_num(ptr as *const i8, num)
1855 }
1856}
1857
1858#[doc(hidden)]
1859impl FromGlibContainer<*const c_char, *mut u8> for PathBuf {
1860 unsafe fn from_glib_none_num(ptr: *mut u8, num: usize) -> Self {
1861 FromGlibContainer::from_glib_none_num(ptr as *const i8, num)
1862 }
1863
1864 unsafe fn from_glib_container_num(ptr: *mut u8, num: usize) -> Self {
1865 FromGlibContainer::from_glib_container_num(ptr as *const i8, num)
1866 }
1867
1868 unsafe fn from_glib_full_num(ptr: *mut u8, num: usize) -> Self {
1869 FromGlibContainer::from_glib_full_num(ptr as *const i8, num)
1870 }
1871}
1872
1873impl FromGlibPtrNone<*const c_char> for OsString {
1874 #[inline]
1875 unsafe fn from_glib_none(ptr: *const c_char) -> Self {
1876 debug_assert!(!ptr.is_null());
1877 c_to_os_string(ptr)
1878 }
1879}
1880
1881impl FromGlibPtrFull<*const c_char> for OsString {
1882 #[inline]
1883 unsafe fn from_glib_full(ptr: *const c_char) -> Self {
1884 let res: OsString = from_glib_none(ptr);
1885 ffi::g_free(mem:ptr as *mut _);
1886 res
1887 }
1888}
1889
1890impl FromGlibPtrNone<*mut c_char> for OsString {
1891 #[inline]
1892 unsafe fn from_glib_none(ptr: *mut c_char) -> Self {
1893 debug_assert!(!ptr.is_null());
1894 c_to_os_string(ptr)
1895 }
1896}
1897
1898impl FromGlibPtrFull<*mut c_char> for OsString {
1899 #[inline]
1900 unsafe fn from_glib_full(ptr: *mut c_char) -> Self {
1901 let res: OsString = from_glib_none(ptr);
1902 ffi::g_free(mem:ptr as *mut _);
1903 res
1904 }
1905}
1906
1907/// Translate from a container.
1908pub trait FromGlibContainer<T, P: Ptr>: Sized {
1909 /// Transfer: none.
1910 ///
1911 /// `num` is the advised number of elements.
1912 unsafe fn from_glib_none_num(ptr: P, num: usize) -> Self;
1913
1914 /// Transfer: container.
1915 ///
1916 /// `num` is the advised number of elements.
1917 unsafe fn from_glib_container_num(ptr: P, num: usize) -> Self;
1918
1919 /// Transfer: full.
1920 ///
1921 /// `num` is the advised number of elements.
1922 unsafe fn from_glib_full_num(ptr: P, num: usize) -> Self;
1923}
1924
1925/// Translate from a container of pointers.
1926pub trait FromGlibPtrContainer<P: Ptr, PP: Ptr>: FromGlibContainer<P, PP> + Sized {
1927 /// Transfer: none.
1928 unsafe fn from_glib_none(ptr: PP) -> Self;
1929
1930 /// Transfer: container.
1931 unsafe fn from_glib_container(ptr: PP) -> Self;
1932
1933 /// Transfer: full.
1934 unsafe fn from_glib_full(ptr: PP) -> Self;
1935}
1936
1937pub unsafe fn c_ptr_array_len<P: Ptr>(mut ptr: *const P) -> usize {
1938 let mut len: usize = 0;
1939
1940 if !ptr.is_null() {
1941 while !(*ptr).is_null() {
1942 len += 1;
1943 ptr = ptr.offset(count:1);
1944 }
1945 }
1946 len
1947}
1948
1949pub trait FromGlibContainerAsVec<T, P: Ptr>
1950where
1951 Self: Sized,
1952{
1953 unsafe fn from_glib_none_num_as_vec(ptr: P, num: usize) -> Vec<Self>;
1954 unsafe fn from_glib_container_num_as_vec(ptr: P, num: usize) -> Vec<Self>;
1955 unsafe fn from_glib_full_num_as_vec(ptr: P, num: usize) -> Vec<Self>;
1956}
1957
1958pub trait FromGlibPtrArrayContainerAsVec<P: Ptr, PP: Ptr>: FromGlibContainerAsVec<P, PP>
1959where
1960 Self: Sized,
1961{
1962 unsafe fn from_glib_none_as_vec(ptr: PP) -> Vec<Self>;
1963 unsafe fn from_glib_container_as_vec(ptr: PP) -> Vec<Self>;
1964 unsafe fn from_glib_full_as_vec(ptr: PP) -> Vec<Self>;
1965}
1966
1967impl FromGlibContainerAsVec<bool, *const ffi::gboolean> for bool {
1968 unsafe fn from_glib_none_num_as_vec(ptr: *const ffi::gboolean, num: usize) -> Vec<Self> {
1969 if num == 0 || ptr.is_null() {
1970 return Vec::new();
1971 }
1972
1973 let mut res = Vec::<Self>::with_capacity(num);
1974 let res_ptr = res.as_mut_ptr();
1975 for i in 0..num {
1976 *res_ptr.add(i) = from_glib(ptr::read(ptr.add(i)));
1977 }
1978 res.set_len(num);
1979 res
1980 }
1981
1982 unsafe fn from_glib_container_num_as_vec(_: *const ffi::gboolean, _: usize) -> Vec<Self> {
1983 // Can't really free a *const
1984 unimplemented!();
1985 }
1986
1987 unsafe fn from_glib_full_num_as_vec(_: *const ffi::gboolean, _: usize) -> Vec<Self> {
1988 // Can't really free a *const
1989 unimplemented!();
1990 }
1991}
1992
1993impl FromGlibContainerAsVec<bool, *mut ffi::gboolean> for bool {
1994 unsafe fn from_glib_none_num_as_vec(ptr: *mut ffi::gboolean, num: usize) -> Vec<Self> {
1995 FromGlibContainerAsVec::from_glib_none_num_as_vec(ptr as *const _, num)
1996 }
1997
1998 unsafe fn from_glib_container_num_as_vec(ptr: *mut ffi::gboolean, num: usize) -> Vec<Self> {
1999 let res: Vec = FromGlibContainerAsVec::from_glib_none_num_as_vec(ptr, num);
2000 ffi::g_free(mem:ptr as *mut _);
2001 res
2002 }
2003
2004 unsafe fn from_glib_full_num_as_vec(ptr: *mut ffi::gboolean, num: usize) -> Vec<Self> {
2005 FromGlibContainerAsVec::from_glib_container_num_as_vec(ptr, num)
2006 }
2007}
2008
2009macro_rules! impl_from_glib_container_as_vec_fundamental {
2010 ($name:ty) => {
2011 unsafe impl TransparentType for $name {
2012 type GlibType = $name;
2013 }
2014
2015 impl FromGlibContainerAsVec<$name, *const $name> for $name {
2016 unsafe fn from_glib_none_num_as_vec(ptr: *const $name, num: usize) -> Vec<Self> {
2017 if num == 0 || ptr.is_null() {
2018 return Vec::new();
2019 }
2020
2021 let mut res = Vec::with_capacity(num);
2022 let res_ptr = res.as_mut_ptr();
2023 std::ptr::copy_nonoverlapping(ptr, res_ptr, num);
2024 res.set_len(num);
2025 res
2026 }
2027
2028 unsafe fn from_glib_container_num_as_vec(_: *const $name, _: usize) -> Vec<Self> {
2029 // Can't really free a *const
2030 unimplemented!();
2031 }
2032
2033 unsafe fn from_glib_full_num_as_vec(_: *const $name, _: usize) -> Vec<Self> {
2034 // Can't really free a *const
2035 unimplemented!();
2036 }
2037 }
2038
2039 impl FromGlibContainerAsVec<$name, *mut $name> for $name {
2040 unsafe fn from_glib_none_num_as_vec(ptr: *mut $name, num: usize) -> Vec<Self> {
2041 FromGlibContainerAsVec::from_glib_none_num_as_vec(ptr as *const _, num)
2042 }
2043
2044 unsafe fn from_glib_container_num_as_vec(ptr: *mut $name, num: usize) -> Vec<Self> {
2045 let res = FromGlibContainerAsVec::from_glib_none_num_as_vec(ptr, num);
2046 ffi::g_free(ptr as *mut _);
2047 res
2048 }
2049
2050 unsafe fn from_glib_full_num_as_vec(ptr: *mut $name, num: usize) -> Vec<Self> {
2051 FromGlibContainerAsVec::from_glib_container_num_as_vec(ptr, num)
2052 }
2053 }
2054 };
2055}
2056
2057impl_from_glib_container_as_vec_fundamental!(u8);
2058impl_from_glib_container_as_vec_fundamental!(i8);
2059impl_from_glib_container_as_vec_fundamental!(u16);
2060impl_from_glib_container_as_vec_fundamental!(i16);
2061impl_from_glib_container_as_vec_fundamental!(u32);
2062impl_from_glib_container_as_vec_fundamental!(i32);
2063impl_from_glib_container_as_vec_fundamental!(u64);
2064impl_from_glib_container_as_vec_fundamental!(i64);
2065impl_from_glib_container_as_vec_fundamental!(f32);
2066impl_from_glib_container_as_vec_fundamental!(f64);
2067
2068macro_rules! impl_from_glib_container_as_vec_string {
2069 ($name:ty, $ffi_name:ty) => {
2070 impl FromGlibContainerAsVec<$ffi_name, *const $ffi_name> for $name {
2071 unsafe fn from_glib_none_num_as_vec(ptr: *const $ffi_name, num: usize) -> Vec<Self> {
2072 if num == 0 || ptr.is_null() {
2073 return Vec::new();
2074 }
2075
2076 let mut res = Vec::<Self>::with_capacity(num);
2077 let res_ptr = res.as_mut_ptr();
2078 for i in 0..num {
2079 std::ptr::write(
2080 res_ptr.add(i),
2081 from_glib_none(ptr::read(ptr.add(i)) as $ffi_name),
2082 );
2083 }
2084 res.set_len(num);
2085 res
2086 }
2087
2088 unsafe fn from_glib_container_num_as_vec(_: *const $ffi_name, _: usize) -> Vec<Self> {
2089 // Can't really free a *const
2090 unimplemented!();
2091 }
2092
2093 unsafe fn from_glib_full_num_as_vec(_: *const $ffi_name, _: usize) -> Vec<Self> {
2094 // Can't really free a *const
2095 unimplemented!();
2096 }
2097 }
2098
2099 impl FromGlibContainerAsVec<$ffi_name, *mut $ffi_name> for $name {
2100 unsafe fn from_glib_none_num_as_vec(ptr: *mut $ffi_name, num: usize) -> Vec<Self> {
2101 FromGlibContainerAsVec::from_glib_none_num_as_vec(ptr as *const _, num)
2102 }
2103
2104 unsafe fn from_glib_container_num_as_vec(ptr: *mut $ffi_name, num: usize) -> Vec<Self> {
2105 let res = FromGlibContainerAsVec::from_glib_none_num_as_vec(ptr, num);
2106 ffi::g_free(ptr as *mut _);
2107 res
2108 }
2109
2110 unsafe fn from_glib_full_num_as_vec(ptr: *mut $ffi_name, num: usize) -> Vec<Self> {
2111 if num == 0 || ptr.is_null() {
2112 ffi::g_free(ptr as *mut _);
2113 return Vec::new();
2114 }
2115
2116 let mut res = Vec::<Self>::with_capacity(num);
2117 let res_ptr = res.as_mut_ptr();
2118 for i in 0..num {
2119 std::ptr::write(
2120 res_ptr.add(i),
2121 from_glib_full(ptr::read(ptr.add(i)) as $ffi_name),
2122 );
2123 }
2124 res.set_len(num);
2125 ffi::g_free(ptr as *mut _);
2126 res
2127 }
2128 }
2129
2130 impl FromGlibPtrArrayContainerAsVec<$ffi_name, *mut $ffi_name> for $name {
2131 unsafe fn from_glib_none_as_vec(ptr: *mut $ffi_name) -> Vec<Self> {
2132 FromGlibContainerAsVec::from_glib_none_num_as_vec(ptr, c_ptr_array_len(ptr))
2133 }
2134
2135 unsafe fn from_glib_container_as_vec(ptr: *mut $ffi_name) -> Vec<Self> {
2136 FromGlibContainerAsVec::from_glib_container_num_as_vec(ptr, c_ptr_array_len(ptr))
2137 }
2138
2139 unsafe fn from_glib_full_as_vec(ptr: *mut $ffi_name) -> Vec<Self> {
2140 FromGlibContainerAsVec::from_glib_full_num_as_vec(ptr, c_ptr_array_len(ptr))
2141 }
2142 }
2143
2144 impl FromGlibPtrArrayContainerAsVec<$ffi_name, *const $ffi_name> for $name {
2145 unsafe fn from_glib_none_as_vec(ptr: *const $ffi_name) -> Vec<Self> {
2146 FromGlibContainerAsVec::from_glib_none_num_as_vec(ptr, c_ptr_array_len(ptr))
2147 }
2148
2149 unsafe fn from_glib_container_as_vec(ptr: *const $ffi_name) -> Vec<Self> {
2150 FromGlibContainerAsVec::from_glib_container_num_as_vec(ptr, c_ptr_array_len(ptr))
2151 }
2152
2153 unsafe fn from_glib_full_as_vec(ptr: *const $ffi_name) -> Vec<Self> {
2154 FromGlibContainerAsVec::from_glib_full_num_as_vec(ptr, c_ptr_array_len(ptr))
2155 }
2156 }
2157 };
2158}
2159
2160// TODO: Deprecate this
2161impl_from_glib_container_as_vec_string!(String, *const c_char);
2162impl_from_glib_container_as_vec_string!(String, *mut c_char);
2163
2164impl_from_glib_container_as_vec_string!(PathBuf, *const c_char);
2165impl_from_glib_container_as_vec_string!(PathBuf, *mut c_char);
2166impl_from_glib_container_as_vec_string!(OsString, *const c_char);
2167impl_from_glib_container_as_vec_string!(OsString, *mut c_char);
2168
2169impl<P, PP: Ptr, T: FromGlibContainerAsVec<P, PP>> FromGlibContainer<P, PP> for Vec<T> {
2170 unsafe fn from_glib_none_num(ptr: PP, num: usize) -> Vec<T> {
2171 FromGlibContainerAsVec::from_glib_none_num_as_vec(ptr, num)
2172 }
2173
2174 unsafe fn from_glib_container_num(ptr: PP, num: usize) -> Vec<T> {
2175 FromGlibContainerAsVec::from_glib_container_num_as_vec(ptr, num)
2176 }
2177
2178 unsafe fn from_glib_full_num(ptr: PP, num: usize) -> Vec<T> {
2179 FromGlibContainerAsVec::from_glib_full_num_as_vec(ptr, num)
2180 }
2181}
2182
2183impl<P: Ptr, PP: Ptr, T: FromGlibPtrArrayContainerAsVec<P, PP>> FromGlibPtrContainer<P, PP>
2184 for Vec<T>
2185{
2186 unsafe fn from_glib_none(ptr: PP) -> Vec<T> {
2187 FromGlibPtrArrayContainerAsVec::from_glib_none_as_vec(ptr)
2188 }
2189
2190 unsafe fn from_glib_container(ptr: PP) -> Vec<T> {
2191 FromGlibPtrArrayContainerAsVec::from_glib_container_as_vec(ptr)
2192 }
2193
2194 unsafe fn from_glib_full(ptr: PP) -> Vec<T> {
2195 FromGlibPtrArrayContainerAsVec::from_glib_full_as_vec(ptr)
2196 }
2197}
2198
2199impl<T> FromGlibContainerAsVec<<T as GlibPtrDefault>::GlibType, *mut ffi::GSList> for T
2200where
2201 T: GlibPtrDefault
2202 + FromGlibPtrNone<<T as GlibPtrDefault>::GlibType>
2203 + FromGlibPtrFull<<T as GlibPtrDefault>::GlibType>,
2204{
2205 unsafe fn from_glib_none_num_as_vec(mut ptr: *mut ffi::GSList, num: usize) -> Vec<T> {
2206 if num == 0 || ptr.is_null() {
2207 return Vec::new();
2208 }
2209 let mut res = Vec::with_capacity(num);
2210 for _ in 0..num {
2211 if ptr.is_null() {
2212 break;
2213 }
2214
2215 let item_ptr: <T as GlibPtrDefault>::GlibType = Ptr::from((*ptr).data);
2216 if !item_ptr.is_null() {
2217 res.push(from_glib_none(item_ptr));
2218 }
2219 ptr = (*ptr).next;
2220 }
2221 res
2222 }
2223
2224 unsafe fn from_glib_container_num_as_vec(ptr: *mut ffi::GSList, num: usize) -> Vec<T> {
2225 let res = FromGlibContainerAsVec::from_glib_none_num_as_vec(ptr, num);
2226 ffi::g_slist_free(ptr);
2227 res
2228 }
2229
2230 unsafe fn from_glib_full_num_as_vec(mut ptr: *mut ffi::GSList, num: usize) -> Vec<T> {
2231 if num == 0 || ptr.is_null() {
2232 return Vec::new();
2233 }
2234 let orig_ptr = ptr;
2235 let mut res = Vec::with_capacity(num);
2236 for _ in 0..num {
2237 if ptr.is_null() {
2238 break;
2239 }
2240
2241 let item_ptr: <T as GlibPtrDefault>::GlibType = Ptr::from((*ptr).data);
2242 if !item_ptr.is_null() {
2243 res.push(from_glib_full(item_ptr));
2244 }
2245 ptr = (*ptr).next;
2246 }
2247 ffi::g_slist_free(orig_ptr);
2248 res
2249 }
2250}
2251
2252impl<T> FromGlibPtrArrayContainerAsVec<<T as GlibPtrDefault>::GlibType, *mut ffi::GSList> for T
2253where
2254 T: GlibPtrDefault
2255 + FromGlibPtrNone<<T as GlibPtrDefault>::GlibType>
2256 + FromGlibPtrFull<<T as GlibPtrDefault>::GlibType>,
2257{
2258 unsafe fn from_glib_none_as_vec(mut ptr: *mut ffi::GSList) -> Vec<T> {
2259 let mut res = Vec::new();
2260 while !ptr.is_null() {
2261 let item_ptr: <T as GlibPtrDefault>::GlibType = Ptr::from((*ptr).data);
2262 if !item_ptr.is_null() {
2263 res.push(from_glib_none(item_ptr));
2264 }
2265 ptr = (*ptr).next;
2266 }
2267 res
2268 }
2269
2270 unsafe fn from_glib_container_as_vec(ptr: *mut ffi::GSList) -> Vec<T> {
2271 let res = FromGlibPtrArrayContainerAsVec::from_glib_none_as_vec(ptr);
2272 ffi::g_slist_free(ptr);
2273 res
2274 }
2275
2276 unsafe fn from_glib_full_as_vec(mut ptr: *mut ffi::GSList) -> Vec<T> {
2277 let orig_ptr = ptr;
2278 let mut res = Vec::new();
2279 while !ptr.is_null() {
2280 let item_ptr: <T as GlibPtrDefault>::GlibType = Ptr::from((*ptr).data);
2281 if !item_ptr.is_null() {
2282 res.push(from_glib_full(item_ptr));
2283 }
2284 ptr = (*ptr).next;
2285 }
2286 ffi::g_slist_free(orig_ptr);
2287 res
2288 }
2289}
2290
2291impl<T> FromGlibContainerAsVec<<T as GlibPtrDefault>::GlibType, *mut ffi::GList> for T
2292where
2293 T: GlibPtrDefault
2294 + FromGlibPtrNone<<T as GlibPtrDefault>::GlibType>
2295 + FromGlibPtrFull<<T as GlibPtrDefault>::GlibType>,
2296{
2297 unsafe fn from_glib_none_num_as_vec(mut ptr: *mut ffi::GList, num: usize) -> Vec<T> {
2298 if num == 0 || ptr.is_null() {
2299 return Vec::new();
2300 }
2301 let mut res = Vec::with_capacity(num);
2302 for _ in 0..num {
2303 if ptr.is_null() {
2304 break;
2305 }
2306
2307 let item_ptr: <T as GlibPtrDefault>::GlibType = Ptr::from((*ptr).data);
2308 if !item_ptr.is_null() {
2309 res.push(from_glib_none(item_ptr));
2310 }
2311 ptr = (*ptr).next;
2312 }
2313 res
2314 }
2315
2316 unsafe fn from_glib_container_num_as_vec(ptr: *mut ffi::GList, num: usize) -> Vec<T> {
2317 let res = FromGlibContainerAsVec::from_glib_none_num_as_vec(ptr, num);
2318 ffi::g_list_free(ptr);
2319 res
2320 }
2321
2322 unsafe fn from_glib_full_num_as_vec(mut ptr: *mut ffi::GList, num: usize) -> Vec<T> {
2323 if num == 0 || ptr.is_null() {
2324 return Vec::new();
2325 }
2326 let orig_ptr = ptr;
2327 let mut res = Vec::with_capacity(num);
2328 for _ in 0..num {
2329 if ptr.is_null() {
2330 break;
2331 }
2332
2333 let item_ptr: <T as GlibPtrDefault>::GlibType = Ptr::from((*ptr).data);
2334 if !item_ptr.is_null() {
2335 res.push(from_glib_full(item_ptr));
2336 }
2337 ptr = (*ptr).next;
2338 }
2339 ffi::g_list_free(orig_ptr);
2340 res
2341 }
2342}
2343
2344impl<T> FromGlibPtrArrayContainerAsVec<<T as GlibPtrDefault>::GlibType, *mut ffi::GList> for T
2345where
2346 T: GlibPtrDefault
2347 + FromGlibPtrNone<<T as GlibPtrDefault>::GlibType>
2348 + FromGlibPtrFull<<T as GlibPtrDefault>::GlibType>,
2349{
2350 unsafe fn from_glib_none_as_vec(mut ptr: *mut ffi::GList) -> Vec<T> {
2351 let mut res = Vec::new();
2352 while !ptr.is_null() {
2353 let item_ptr: <T as GlibPtrDefault>::GlibType = Ptr::from((*ptr).data);
2354 if !item_ptr.is_null() {
2355 res.push(from_glib_none(item_ptr));
2356 }
2357 ptr = (*ptr).next;
2358 }
2359 res
2360 }
2361
2362 unsafe fn from_glib_container_as_vec(ptr: *mut ffi::GList) -> Vec<T> {
2363 let res = FromGlibPtrArrayContainerAsVec::from_glib_none_as_vec(ptr);
2364 ffi::g_list_free(ptr);
2365 res
2366 }
2367
2368 unsafe fn from_glib_full_as_vec(mut ptr: *mut ffi::GList) -> Vec<T> {
2369 let orig_ptr = ptr;
2370 let mut res = Vec::new();
2371 while !ptr.is_null() {
2372 let item_ptr: <T as GlibPtrDefault>::GlibType = Ptr::from((*ptr).data);
2373 if !item_ptr.is_null() {
2374 res.push(from_glib_full(item_ptr));
2375 }
2376 ptr = (*ptr).next;
2377 }
2378 ffi::g_list_free(orig_ptr);
2379 res
2380 }
2381}
2382
2383impl<T> FromGlibContainerAsVec<<T as GlibPtrDefault>::GlibType, *const ffi::GList> for T
2384where
2385 T: GlibPtrDefault
2386 + FromGlibPtrNone<<T as GlibPtrDefault>::GlibType>
2387 + FromGlibPtrFull<<T as GlibPtrDefault>::GlibType>,
2388{
2389 unsafe fn from_glib_none_num_as_vec(ptr: *const ffi::GList, num: usize) -> Vec<T> {
2390 FromGlibContainerAsVec::from_glib_none_num_as_vec(ptr:mut_override(ptr), num)
2391 }
2392
2393 unsafe fn from_glib_container_num_as_vec(_: *const ffi::GList, _: usize) -> Vec<T> {
2394 // Can't really free a *const
2395 unimplemented!()
2396 }
2397
2398 unsafe fn from_glib_full_num_as_vec(_: *const ffi::GList, _: usize) -> Vec<T> {
2399 // Can't really free a *const
2400 unimplemented!()
2401 }
2402}
2403
2404impl<T> FromGlibPtrArrayContainerAsVec<<T as GlibPtrDefault>::GlibType, *const ffi::GList> for T
2405where
2406 T: GlibPtrDefault
2407 + FromGlibPtrNone<<T as GlibPtrDefault>::GlibType>
2408 + FromGlibPtrFull<<T as GlibPtrDefault>::GlibType>,
2409{
2410 unsafe fn from_glib_none_as_vec(ptr: *const ffi::GList) -> Vec<T> {
2411 FromGlibPtrArrayContainerAsVec::from_glib_none_as_vec(ptr:mut_override(ptr))
2412 }
2413
2414 unsafe fn from_glib_container_as_vec(_: *const ffi::GList) -> Vec<T> {
2415 // Can't really free a *const
2416 unimplemented!()
2417 }
2418
2419 unsafe fn from_glib_full_as_vec(_: *const ffi::GList) -> Vec<T> {
2420 // Can't really free a *const
2421 unimplemented!()
2422 }
2423}
2424
2425impl<T> FromGlibContainerAsVec<<T as GlibPtrDefault>::GlibType, *const ffi::GSList> for T
2426where
2427 T: GlibPtrDefault
2428 + FromGlibPtrNone<<T as GlibPtrDefault>::GlibType>
2429 + FromGlibPtrFull<<T as GlibPtrDefault>::GlibType>,
2430{
2431 unsafe fn from_glib_none_num_as_vec(ptr: *const ffi::GSList, num: usize) -> Vec<T> {
2432 FromGlibContainerAsVec::from_glib_none_num_as_vec(ptr:mut_override(ptr), num)
2433 }
2434
2435 unsafe fn from_glib_container_num_as_vec(_: *const ffi::GSList, _: usize) -> Vec<T> {
2436 // Can't really free a *const
2437 unimplemented!()
2438 }
2439
2440 unsafe fn from_glib_full_num_as_vec(_: *const ffi::GSList, _: usize) -> Vec<T> {
2441 // Can't really free a *const
2442 unimplemented!()
2443 }
2444}
2445
2446impl<T> FromGlibPtrArrayContainerAsVec<<T as GlibPtrDefault>::GlibType, *const ffi::GSList> for T
2447where
2448 T: GlibPtrDefault
2449 + FromGlibPtrNone<<T as GlibPtrDefault>::GlibType>
2450 + FromGlibPtrFull<<T as GlibPtrDefault>::GlibType>,
2451{
2452 unsafe fn from_glib_none_as_vec(ptr: *const ffi::GSList) -> Vec<T> {
2453 FromGlibPtrArrayContainerAsVec::from_glib_none_as_vec(ptr:mut_override(ptr))
2454 }
2455
2456 unsafe fn from_glib_container_as_vec(_: *const ffi::GSList) -> Vec<T> {
2457 // Can't really free a *const
2458 unimplemented!()
2459 }
2460
2461 unsafe fn from_glib_full_as_vec(_: *const ffi::GSList) -> Vec<T> {
2462 // Can't really free a *const
2463 unimplemented!()
2464 }
2465}
2466
2467#[allow(clippy::implicit_hasher)]
2468impl FromGlibContainer<*const c_char, *mut ffi::GHashTable> for HashMap<String, String> {
2469 unsafe fn from_glib_none_num(ptr: *mut ffi::GHashTable, _: usize) -> Self {
2470 FromGlibPtrContainer::from_glib_none(ptr)
2471 }
2472
2473 unsafe fn from_glib_container_num(ptr: *mut ffi::GHashTable, _: usize) -> Self {
2474 FromGlibPtrContainer::from_glib_full(ptr)
2475 }
2476
2477 unsafe fn from_glib_full_num(ptr: *mut ffi::GHashTable, _: usize) -> Self {
2478 FromGlibPtrContainer::from_glib_full(ptr)
2479 }
2480}
2481
2482#[allow(clippy::implicit_hasher)]
2483impl FromGlibPtrContainer<*const c_char, *mut ffi::GHashTable> for HashMap<String, String> {
2484 unsafe fn from_glib_none(ptr: *mut ffi::GHashTable) -> Self {
2485 unsafe extern "C" fn read_string_hash_table(
2486 key: ffi::gpointer,
2487 value: ffi::gpointer,
2488 hash_map: ffi::gpointer,
2489 ) {
2490 let key: String = from_glib_none(key as *const c_char);
2491 let value: String = from_glib_none(value as *const c_char);
2492 let hash_map: &mut HashMap<String, String> =
2493 &mut *(hash_map as *mut HashMap<String, String>);
2494 hash_map.insert(key, value);
2495 }
2496 let mut map = HashMap::with_capacity(ffi::g_hash_table_size(ptr) as usize);
2497 ffi::g_hash_table_foreach(
2498 ptr,
2499 Some(read_string_hash_table),
2500 &mut map as *mut HashMap<String, String> as *mut _,
2501 );
2502 map
2503 }
2504
2505 unsafe fn from_glib_container(ptr: *mut ffi::GHashTable) -> Self {
2506 FromGlibPtrContainer::from_glib_full(ptr)
2507 }
2508
2509 unsafe fn from_glib_full(ptr: *mut ffi::GHashTable) -> Self {
2510 let map = FromGlibPtrContainer::from_glib_none(ptr);
2511 ffi::g_hash_table_unref(ptr);
2512 map
2513 }
2514}
2515
2516impl<T> FromGlibContainerAsVec<<T as GlibPtrDefault>::GlibType, *mut ffi::GPtrArray> for T
2517where
2518 T: GlibPtrDefault
2519 + FromGlibPtrNone<<T as GlibPtrDefault>::GlibType>
2520 + FromGlibPtrFull<<T as GlibPtrDefault>::GlibType>,
2521{
2522 unsafe fn from_glib_none_num_as_vec(ptr: *mut ffi::GPtrArray, num: usize) -> Vec<T> {
2523 if num == 0 || ptr.is_null() {
2524 return Vec::new();
2525 }
2526 let pdata = (*ptr).pdata;
2527 debug_assert!((*ptr).len as usize >= num);
2528 let mut res = Vec::with_capacity(num);
2529 for i in 0..num {
2530 let item_ptr: <T as GlibPtrDefault>::GlibType = Ptr::from(ptr::read(pdata.add(i)));
2531 if !item_ptr.is_null() {
2532 res.push(from_glib_none(item_ptr));
2533 }
2534 }
2535 res
2536 }
2537
2538 unsafe fn from_glib_container_num_as_vec(ptr: *mut ffi::GPtrArray, num: usize) -> Vec<T> {
2539 let res = FromGlibContainer::from_glib_none_num(ptr, num);
2540 if !ptr.is_null() {
2541 ffi::g_ptr_array_unref(ptr);
2542 }
2543 res
2544 }
2545
2546 unsafe fn from_glib_full_num_as_vec(ptr: *mut ffi::GPtrArray, num: usize) -> Vec<T> {
2547 if ptr.is_null() {
2548 return Vec::new();
2549 }
2550 if num == 0 {
2551 ffi::g_ptr_array_unref(ptr);
2552 return Vec::new();
2553 }
2554 let pdata = (*ptr).pdata;
2555 debug_assert!((*ptr).len as usize >= num);
2556 let mut res = Vec::with_capacity(num);
2557 for i in 0..num {
2558 let item_ptr: <T as GlibPtrDefault>::GlibType = Ptr::from(ptr::read(pdata.add(i)));
2559 if !item_ptr.is_null() {
2560 res.push(from_glib_none(item_ptr));
2561 }
2562 }
2563 ffi::g_ptr_array_unref(ptr);
2564 res
2565 }
2566}
2567
2568impl<T> FromGlibPtrArrayContainerAsVec<<T as GlibPtrDefault>::GlibType, *mut ffi::GPtrArray> for T
2569where
2570 T: GlibPtrDefault
2571 + FromGlibPtrNone<<T as GlibPtrDefault>::GlibType>
2572 + FromGlibPtrFull<<T as GlibPtrDefault>::GlibType>,
2573{
2574 unsafe fn from_glib_none_as_vec(ptr: *mut ffi::GPtrArray) -> Vec<T> {
2575 let num: usize = (*ptr).len as usize;
2576 FromGlibContainer::from_glib_none_num(ptr, num)
2577 }
2578
2579 unsafe fn from_glib_container_as_vec(ptr: *mut ffi::GPtrArray) -> Vec<T> {
2580 let num: usize = (*ptr).len as usize;
2581 FromGlibContainer::from_glib_container_num(ptr, num)
2582 }
2583
2584 unsafe fn from_glib_full_as_vec(ptr: *mut ffi::GPtrArray) -> Vec<T> {
2585 let num: usize = (*ptr).len as usize;
2586 FromGlibContainer::from_glib_full_num(ptr, num)
2587 }
2588}
2589
2590impl<T> FromGlibContainerAsVec<<T as GlibPtrDefault>::GlibType, *const ffi::GPtrArray> for T
2591where
2592 T: GlibPtrDefault
2593 + FromGlibPtrNone<<T as GlibPtrDefault>::GlibType>
2594 + FromGlibPtrFull<<T as GlibPtrDefault>::GlibType>,
2595{
2596 unsafe fn from_glib_none_num_as_vec(ptr: *const ffi::GPtrArray, num: usize) -> Vec<T> {
2597 FromGlibContainerAsVec::from_glib_none_num_as_vec(ptr:mut_override(ptr), num)
2598 }
2599
2600 unsafe fn from_glib_container_num_as_vec(_: *const ffi::GPtrArray, _: usize) -> Vec<T> {
2601 // Can't really free a *const
2602 unimplemented!()
2603 }
2604
2605 unsafe fn from_glib_full_num_as_vec(_: *const ffi::GPtrArray, _: usize) -> Vec<T> {
2606 // Can't really free a *const
2607 unimplemented!()
2608 }
2609}
2610
2611impl<T> FromGlibPtrArrayContainerAsVec<<T as GlibPtrDefault>::GlibType, *const ffi::GPtrArray> for T
2612where
2613 T: GlibPtrDefault
2614 + FromGlibPtrNone<<T as GlibPtrDefault>::GlibType>
2615 + FromGlibPtrFull<<T as GlibPtrDefault>::GlibType>,
2616{
2617 unsafe fn from_glib_none_as_vec(ptr: *const ffi::GPtrArray) -> Vec<T> {
2618 FromGlibPtrArrayContainerAsVec::from_glib_none_as_vec(ptr:mut_override(ptr))
2619 }
2620
2621 unsafe fn from_glib_container_as_vec(_: *const ffi::GPtrArray) -> Vec<T> {
2622 // Can't really free a *const
2623 unimplemented!()
2624 }
2625
2626 unsafe fn from_glib_full_as_vec(_: *const ffi::GPtrArray) -> Vec<T> {
2627 // Can't really free a *const
2628 unimplemented!()
2629 }
2630}
2631
2632/// Trait for types that have the same memory representation as a pointer to their FFI type.
2633///
2634/// Values of types implementing this trait can be transmuted to pointers of the FFI type,
2635/// references to pointers of pointers to the FFI type.
2636pub unsafe trait TransparentPtrType: Clone + Sized + GlibPtrDefault {}
2637
2638/// Trait for types that have the same memory representation as their FFI type.
2639///
2640/// Values of types implementing this trait can be transmuted directly to the FFI type, references
2641/// to pointers to the FFI type.
2642pub unsafe trait TransparentType: Clone + Sized {
2643 type GlibType;
2644}
2645
2646unsafe impl<T: TransparentPtrType> TransparentType for T {
2647 type GlibType = <T as GlibPtrDefault>::GlibType;
2648}
2649
2650#[cfg(test)]
2651mod tests {
2652 use std::{collections::HashMap, fs};
2653
2654 use tempfile::tempdir;
2655
2656 use super::*;
2657 use crate::{FileTest, GString};
2658
2659 #[test]
2660 fn boolean() {
2661 assert_eq!(true.into_glib(), ffi::GTRUE);
2662 assert_eq!(false.into_glib(), ffi::GFALSE);
2663 assert!(unsafe { bool::from_glib(ffi::GTRUE) });
2664 assert!(!unsafe { bool::from_glib(ffi::GFALSE) });
2665 assert!(unsafe { bool::from_glib(42) });
2666 }
2667
2668 #[test]
2669 fn ordering() {
2670 assert_eq!(Ordering::Less.into_glib(), -1);
2671 assert_eq!(Ordering::Equal.into_glib(), 0);
2672 assert_eq!(Ordering::Greater.into_glib(), 1);
2673 assert_eq!(Ordering::Less, unsafe { Ordering::from_glib(-42) });
2674 assert_eq!(Ordering::Less, unsafe { Ordering::from_glib(-1) });
2675 assert_eq!(Ordering::Equal, unsafe { Ordering::from_glib(0) });
2676 assert_eq!(Ordering::Greater, unsafe { Ordering::from_glib(1) });
2677 assert_eq!(Ordering::Greater, unsafe { Ordering::from_glib(42) });
2678 }
2679
2680 #[test]
2681 fn string() {
2682 let s = "ABC";
2683 let owned = "ABC".to_string();
2684 let cstring = CString::new("ABC").unwrap();
2685
2686 let stash = s.to_glib_none();
2687 assert_eq!(unsafe { CStr::from_ptr(stash.0) }, cstring.as_c_str());
2688
2689 let stash = owned.to_glib_none();
2690 assert_eq!(unsafe { CStr::from_ptr(stash.0) }, cstring.as_c_str());
2691
2692 let ptr: *mut c_char = s.to_glib_full();
2693 assert_eq!(unsafe { CStr::from_ptr(ptr) }, cstring.as_c_str());
2694
2695 unsafe {
2696 ffi::g_free(ptr as *mut _);
2697 }
2698
2699 let ptr: *mut c_char = owned.to_glib_full();
2700 assert_eq!(unsafe { CStr::from_ptr(ptr) }, cstring.as_c_str());
2701
2702 assert_eq!(s, unsafe { String::from_glib_none(ptr) });
2703 assert_eq!(owned, unsafe { String::from_glib_full(ptr) });
2704 }
2705
2706 #[test]
2707 fn string_hash_map() {
2708 let mut map = HashMap::new();
2709 map.insert("A".into(), "1".into());
2710 map.insert("B".into(), "2".into());
2711 map.insert("C".into(), "3".into());
2712 let ptr: *mut ffi::GHashTable = map.to_glib_full();
2713 let map = unsafe { HashMap::from_glib_full(ptr) };
2714 assert_eq!(map.get("A"), Some(&"1".into()));
2715 assert_eq!(map.get("B"), Some(&"2".into()));
2716 assert_eq!(map.get("C"), Some(&"3".into()));
2717 }
2718
2719 #[test]
2720 fn string_array() {
2721 let v = vec!["A".to_string(), "B".to_string(), "C".to_string()];
2722 let stash = v.to_glib_none();
2723 let ptr: *mut *mut c_char = stash.0;
2724 let ptr_copy = unsafe { ffi::g_strdupv(ptr) };
2725
2726 let actual: Vec<String> = unsafe { FromGlibPtrContainer::from_glib_full(ptr_copy) };
2727 assert_eq!(v, actual);
2728 }
2729
2730 #[test]
2731 fn gstring_array() {
2732 let v = vec!["A".to_string(), "B".to_string(), "C".to_string()];
2733 let stash = v.to_glib_none();
2734 let ptr: *mut *mut c_char = stash.0;
2735 let ptr_copy = unsafe { ffi::g_strdupv(ptr) };
2736
2737 let actual: Vec<GString> = unsafe { FromGlibPtrContainer::from_glib_full(ptr_copy) };
2738 assert_eq!(v, actual);
2739 }
2740
2741 #[test]
2742 fn ptr_array() {
2743 let strings = &["A", "B", "C"];
2744 let (ptr, _stash) =
2745 ToGlibContainerFromSlice::<*mut ffi::GPtrArray>::to_glib_none_from_slice(strings);
2746 let v: Vec<GString> = unsafe { FromGlibPtrArrayContainerAsVec::from_glib_none_as_vec(ptr) };
2747 assert_eq!(&v, strings);
2748 }
2749
2750 #[test]
2751 #[cfg(not(target_os = "macos"))]
2752 fn test_paths() {
2753 let tmp_dir = tempdir().unwrap();
2754
2755 // Test if passing paths to GLib and getting them back
2756 // gives us useful results
2757 let dir_1 = tmp_dir.path().join("abcd");
2758 fs::create_dir(&dir_1).unwrap();
2759 assert_eq!(crate::path_get_basename(&dir_1), Path::new("abcd"));
2760 assert_eq!(
2761 crate::path_get_basename(dir_1.canonicalize().unwrap()),
2762 Path::new("abcd")
2763 );
2764 // This currently fails on Windows because C:\\Users\\runneradmin
2765 // gets shortened to C:\\Users\\RUNNER~1
2766 #[cfg(not(windows))]
2767 assert_eq!(
2768 crate::path_get_dirname(dir_1.canonicalize().unwrap()),
2769 tmp_dir.path()
2770 );
2771 assert!(crate::file_test(
2772 &dir_1,
2773 FileTest::EXISTS | FileTest::IS_DIR
2774 ));
2775 assert!(crate::file_test(
2776 dir_1.canonicalize().unwrap(),
2777 FileTest::EXISTS | FileTest::IS_DIR
2778 ));
2779
2780 // And test with some non-ASCII characters
2781 let dir_2 = tmp_dir.as_ref().join("øäöü");
2782 fs::create_dir(&dir_2).unwrap();
2783 assert_eq!(crate::path_get_basename(&dir_2), Path::new("øäöü"));
2784 assert_eq!(
2785 crate::path_get_basename(dir_2.canonicalize().unwrap()),
2786 Path::new("øäöü")
2787 );
2788 // This currently fails on Windows because C:\\Users\\runneradmin
2789 // gets shortened to C:\\Users\\RUNNER~1
2790 #[cfg(not(windows))]
2791 assert_eq!(
2792 crate::path_get_dirname(dir_2.canonicalize().unwrap()),
2793 tmp_dir.path()
2794 );
2795 assert!(crate::file_test(
2796 &dir_2,
2797 FileTest::EXISTS | FileTest::IS_DIR
2798 ));
2799 assert!(crate::file_test(
2800 dir_2.canonicalize().unwrap(),
2801 FileTest::EXISTS | FileTest::IS_DIR
2802 ));
2803 }
2804
2805 #[test]
2806 #[cfg(target_os = "macos")]
2807 fn test_paths() {
2808 let t_dir = tempdir().unwrap();
2809 let tmp_dir = t_dir.path().canonicalize().unwrap();
2810
2811 // Test if passing paths to GLib and getting them back
2812 // gives us useful results
2813 let dir_1 = tmp_dir.join("abcd");
2814 fs::create_dir(&dir_1).unwrap();
2815 assert_eq!(crate::path_get_basename(&dir_1), Path::new("abcd"));
2816 assert_eq!(
2817 crate::path_get_basename(dir_1.canonicalize().unwrap()),
2818 Path::new("abcd")
2819 );
2820 assert_eq!(
2821 crate::path_get_dirname(dir_1.canonicalize().unwrap()),
2822 tmp_dir
2823 );
2824 assert!(crate::file_test(
2825 &dir_1,
2826 FileTest::EXISTS | FileTest::IS_DIR
2827 ));
2828 assert!(crate::file_test(
2829 &dir_1.canonicalize().unwrap(),
2830 FileTest::EXISTS | FileTest::IS_DIR
2831 ));
2832 }
2833
2834 #[test]
2835 fn none_value() {
2836 const CLONG_NONE: libc::c_long = -1;
2837
2838 #[derive(Debug, PartialEq, Eq)]
2839 struct SpecialU32(u32);
2840 impl IntoGlib for SpecialU32 {
2841 type GlibType = libc::c_uint;
2842 fn into_glib(self) -> libc::c_uint {
2843 self.0 as libc::c_uint
2844 }
2845 }
2846 impl OptionIntoGlib for SpecialU32 {
2847 const GLIB_NONE: Self::GlibType = CLONG_NONE as libc::c_uint;
2848 }
2849
2850 assert_eq!(SpecialU32(0).into_glib(), 0);
2851 assert_eq!(SpecialU32(42).into_glib(), 42);
2852 assert_eq!(Some(SpecialU32(0)).into_glib(), 0);
2853 assert_eq!(Some(SpecialU32(42)).into_glib(), 42);
2854 assert_eq!(
2855 Option::None::<SpecialU32>.into_glib(),
2856 SpecialU32::GLIB_NONE
2857 );
2858
2859 impl TryFromGlib<libc::c_uint> for SpecialU32 {
2860 type Error = GlibNoneError;
2861 #[allow(clippy::unnecessary_cast)]
2862 unsafe fn try_from_glib(val: libc::c_uint) -> Result<Self, GlibNoneError> {
2863 if val == SpecialU32::GLIB_NONE {
2864 return Err(GlibNoneError);
2865 }
2866
2867 Ok(SpecialU32(val as u32))
2868 }
2869 }
2870
2871 assert_eq!(unsafe { SpecialU32::try_from_glib(0) }, Ok(SpecialU32(0)));
2872 assert_eq!(unsafe { SpecialU32::try_from_glib(42) }, Ok(SpecialU32(42)));
2873 assert_eq!(
2874 unsafe { SpecialU32::try_from_glib(SpecialU32::GLIB_NONE) },
2875 Err(GlibNoneError)
2876 );
2877
2878 assert_eq!(
2879 unsafe { Option::<SpecialU32>::from_glib(0) },
2880 Some(SpecialU32(0))
2881 );
2882 assert_eq!(
2883 unsafe { Option::<SpecialU32>::from_glib(42) },
2884 Some(SpecialU32(42))
2885 );
2886 assert!(unsafe { Option::<SpecialU32>::from_glib(SpecialU32::GLIB_NONE) }.is_none());
2887 }
2888
2889 #[test]
2890 fn invalid_value() {
2891 use std::{convert::TryFrom, num::TryFromIntError};
2892
2893 #[derive(Debug, PartialEq, Eq)]
2894 struct U32(u32);
2895
2896 impl TryFromGlib<libc::c_long> for U32 {
2897 type Error = TryFromIntError;
2898 unsafe fn try_from_glib(val: libc::c_long) -> Result<Self, TryFromIntError> {
2899 Ok(U32(u32::try_from(val)?))
2900 }
2901 }
2902
2903 assert_eq!(unsafe { U32::try_from_glib(0) }, Ok(U32(0)));
2904 assert_eq!(unsafe { U32::try_from_glib(42) }, Ok(U32(42)));
2905 assert!(unsafe { U32::try_from_glib(-1) }.is_err());
2906 assert!(unsafe { U32::try_from_glib(-42) }.is_err());
2907 }
2908
2909 #[test]
2910 fn none_or_invalid_value() {
2911 use std::{convert::TryFrom, num::TryFromIntError};
2912
2913 #[derive(Debug, PartialEq, Eq)]
2914 struct SpecialU32(u32);
2915 impl IntoGlib for SpecialU32 {
2916 type GlibType = libc::c_long;
2917 fn into_glib(self) -> libc::c_long {
2918 self.0 as libc::c_long
2919 }
2920 }
2921 impl OptionIntoGlib for SpecialU32 {
2922 const GLIB_NONE: Self::GlibType = -1;
2923 }
2924
2925 assert_eq!(SpecialU32(0).into_glib(), 0);
2926 assert_eq!(SpecialU32(42).into_glib(), 42);
2927 assert_eq!(Some(SpecialU32(42)).into_glib(), 42);
2928 assert_eq!(
2929 Option::None::<SpecialU32>.into_glib(),
2930 SpecialU32::GLIB_NONE
2931 );
2932
2933 impl TryFromGlib<libc::c_long> for SpecialU32 {
2934 type Error = GlibNoneOrInvalidError<TryFromIntError>;
2935 unsafe fn try_from_glib(
2936 val: libc::c_long,
2937 ) -> Result<Self, GlibNoneOrInvalidError<TryFromIntError>> {
2938 if val == SpecialU32::GLIB_NONE {
2939 return Err(GlibNoneOrInvalidError::None);
2940 }
2941
2942 Ok(SpecialU32(u32::try_from(val)?))
2943 }
2944 }
2945
2946 assert_eq!(unsafe { SpecialU32::try_from_glib(0) }, Ok(SpecialU32(0)));
2947 assert_eq!(unsafe { SpecialU32::try_from_glib(42) }, Ok(SpecialU32(42)));
2948 assert!(unsafe { SpecialU32::try_from_glib(SpecialU32::GLIB_NONE) }
2949 .unwrap_err()
2950 .is_none());
2951 assert!(unsafe { SpecialU32::try_from_glib(-42) }
2952 .unwrap_err()
2953 .is_invalid());
2954
2955 assert_eq!(
2956 unsafe { Result::<Option<SpecialU32>, _>::from_glib(0) },
2957 Ok(Some(SpecialU32(0)))
2958 );
2959 assert_eq!(
2960 unsafe { Result::<Option<SpecialU32>, _>::from_glib(42) },
2961 Ok(Some(SpecialU32(42)))
2962 );
2963 assert_eq!(
2964 unsafe { Result::<Option<SpecialU32>, _>::from_glib(SpecialU32::GLIB_NONE) },
2965 Ok(None)
2966 );
2967 assert!(unsafe { Result::<Option<SpecialU32>, _>::from_glib(-42) }.is_err());
2968 }
2969}
2970