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))] |
134 | use std::os::unix::prelude::*; |
135 | use 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 | |
149 | use libc::{c_char, size_t}; |
150 | |
151 | // rustdoc-stripper-ignore-next |
152 | /// A pointer |
153 | pub 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 | |
159 | impl<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 | |
176 | impl<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 ] |
198 | pub 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 ] |
208 | pub 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. |
214 | pub 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 ] |
222 | pub 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 | /// ``` |
255 | pub struct Stash<'a, P: Copy, T: ?Sized + ToGlibPtr<'a, P>>( |
256 | pub P, |
257 | pub <T as ToGlibPtr<'a, P>>::Storage, |
258 | ); |
259 | |
260 | pub struct StashMut<'a, P: Copy, T: ?Sized>(pub P, pub <T as ToGlibPtrMut<'a, P>>::Storage) |
261 | where |
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)] |
273 | pub struct Borrowed<T>(mem::ManuallyDrop<T>); |
274 | |
275 | impl<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 | |
296 | impl<T> AsRef<T> for Borrowed<T> { |
297 | #[inline ] |
298 | fn as_ref(&self) -> &T { |
299 | &self.0 |
300 | } |
301 | } |
302 | |
303 | impl<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. |
314 | pub 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. |
327 | pub trait IntoGlib { |
328 | type GlibType: Copy; |
329 | |
330 | fn into_glib(self) -> Self::GlibType; |
331 | } |
332 | |
333 | impl 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 | |
346 | impl IntoGlib for char { |
347 | type GlibType = u32; |
348 | |
349 | #[inline ] |
350 | fn into_glib(self) -> u32 { |
351 | self as u32 |
352 | } |
353 | } |
354 | |
355 | unsafe impl TransparentType for char { |
356 | type GlibType = u32; |
357 | } |
358 | |
359 | impl 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 | |
368 | impl 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 | |
381 | impl<O, E, G> IntoGlib for Result<O, E> |
382 | where |
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. |
400 | pub trait OptionIntoGlib: IntoGlib { |
401 | const GLIB_NONE: Self::GlibType; |
402 | } |
403 | |
404 | impl<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. |
420 | pub trait GlibPtrDefault { |
421 | type GlibType: Ptr; |
422 | } |
423 | |
424 | impl<'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. |
430 | pub 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. |
459 | pub 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 | |
470 | impl<'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 | |
489 | impl<'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 | |
502 | impl<'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)] |
519 | pub enum CowStash<B, O> { |
520 | Borrowed(B), |
521 | Owned(O), |
522 | } |
523 | |
524 | impl<'a, P: Ptr, T> ToGlibPtr<'a, P> for Cow<'a, T> |
525 | where |
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 | |
554 | impl<'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 | |
588 | impl<'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 | |
603 | impl<'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 | |
618 | impl<'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 | |
633 | impl<'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 | |
652 | impl<'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 | |
671 | impl<'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 | |
690 | impl<'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. |
711 | pub 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 | |
718 | impl<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 | |
727 | impl GlibPtrDefault for str { |
728 | type GlibType = *mut c_char; |
729 | } |
730 | |
731 | impl GlibPtrDefault for String { |
732 | type GlibType = *mut c_char; |
733 | } |
734 | |
735 | #[cfg (not(windows))] |
736 | pub(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)] |
746 | pub(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))] |
774 | pub(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)] |
785 | pub(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 | |
802 | impl<'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 | |
812 | impl<'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 | |
828 | impl<'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 | |
838 | impl<'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 | |
854 | impl GlibPtrDefault for Path { |
855 | type GlibType = *mut c_char; |
856 | } |
857 | |
858 | impl GlibPtrDefault for PathBuf { |
859 | type GlibType = *mut c_char; |
860 | } |
861 | |
862 | impl<'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 | |
872 | impl<'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 | |
888 | impl<'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 | |
898 | impl<'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 | |
914 | impl GlibPtrDefault for OsStr { |
915 | type GlibType = *mut c_char; |
916 | } |
917 | |
918 | impl GlibPtrDefault for OsString { |
919 | type GlibType = *mut c_char; |
920 | } |
921 | |
922 | pub trait ToGlibContainerFromSlice<'a, P> |
923 | where |
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 | |
936 | macro_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 | |
970 | impl_to_glib_container_from_slice_fundamental!(u8); |
971 | impl_to_glib_container_from_slice_fundamental!(i8); |
972 | impl_to_glib_container_from_slice_fundamental!(u16); |
973 | impl_to_glib_container_from_slice_fundamental!(i16); |
974 | impl_to_glib_container_from_slice_fundamental!(u32); |
975 | impl_to_glib_container_from_slice_fundamental!(i32); |
976 | impl_to_glib_container_from_slice_fundamental!(u64); |
977 | impl_to_glib_container_from_slice_fundamental!(i64); |
978 | impl_to_glib_container_from_slice_fundamental!(f32); |
979 | impl_to_glib_container_from_slice_fundamental!(f64); |
980 | |
981 | macro_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 | |
1072 | impl_to_glib_container_from_slice_string!(&'a str, *mut c_char); |
1073 | impl_to_glib_container_from_slice_string!(&'a str, *const c_char); |
1074 | impl_to_glib_container_from_slice_string!(String, *mut c_char); |
1075 | impl_to_glib_container_from_slice_string!(String, *const c_char); |
1076 | impl_to_glib_container_from_slice_string!(&'a Path, *mut c_char); |
1077 | impl_to_glib_container_from_slice_string!(&'a Path, *const c_char); |
1078 | impl_to_glib_container_from_slice_string!(PathBuf, *mut c_char); |
1079 | impl_to_glib_container_from_slice_string!(PathBuf, *const c_char); |
1080 | impl_to_glib_container_from_slice_string!(&'a OsStr, *mut c_char); |
1081 | impl_to_glib_container_from_slice_string!(&'a OsStr, *const c_char); |
1082 | impl_to_glib_container_from_slice_string!(OsString, *mut c_char); |
1083 | impl_to_glib_container_from_slice_string!(OsString, *const c_char); |
1084 | impl_to_glib_container_from_slice_string!(crate::GString, *mut c_char); |
1085 | impl_to_glib_container_from_slice_string!(crate::GString, *const c_char); |
1086 | |
1087 | impl<'a, T> ToGlibContainerFromSlice<'a, *mut ffi::GList> for T |
1088 | where |
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 | |
1133 | impl<'a, T> ToGlibContainerFromSlice<'a, *const ffi::GList> for T |
1134 | where |
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" )] |
1160 | pub struct List(ptr::NonNull<ffi::GList>); |
1161 | |
1162 | impl Drop for List { |
1163 | #[inline ] |
1164 | fn drop(&mut self) { |
1165 | unsafe { ffi::g_list_free(self.0.as_ptr()) } |
1166 | } |
1167 | } |
1168 | |
1169 | impl<'a, T> ToGlibContainerFromSlice<'a, *mut ffi::GSList> for &'a T |
1170 | where |
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 | |
1216 | impl<'a, T> ToGlibContainerFromSlice<'a, *const ffi::GSList> for &'a T |
1217 | where |
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" )] |
1244 | pub struct SList(ptr::NonNull<ffi::GSList>); |
1245 | |
1246 | impl Drop for SList { |
1247 | #[inline ] |
1248 | fn drop(&mut self) { |
1249 | unsafe { ffi::g_slist_free(self.0.as_ptr()) } |
1250 | } |
1251 | } |
1252 | |
1253 | impl<'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)] |
1275 | impl<'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" )] |
1304 | pub struct HashTable(ptr::NonNull<ffi::GHashTable>); |
1305 | |
1306 | impl 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" )] |
1314 | pub struct PtrArray(ptr::NonNull<ffi::GPtrArray>); |
1315 | |
1316 | impl 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 | |
1325 | impl<'a, T> ToGlibContainerFromSlice<'a, *mut ffi::GPtrArray> for T |
1326 | where |
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 | |
1377 | impl<'a, T> ToGlibContainerFromSlice<'a, *const ffi::GPtrArray> for T |
1378 | where |
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. |
1406 | pub 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 ] |
1413 | pub unsafe fn from_glib<G: Copy, T: FromGlib<G>>(val: G) -> T { |
1414 | FromGlib::from_glib(val) |
1415 | } |
1416 | |
1417 | impl FromGlib<ffi::gboolean> for bool { |
1418 | #[inline ] |
1419 | unsafe fn from_glib(val: ffi::gboolean) -> Self { |
1420 | val != ffi::GFALSE |
1421 | } |
1422 | } |
1423 | |
1424 | impl 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. |
1433 | pub 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 ] |
1441 | pub 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)] |
1450 | pub struct GlibNoneError; |
1451 | |
1452 | impl fmt::Display for GlibNoneError { |
1453 | fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { |
1454 | write!(fmt, "glib value is None" ) |
1455 | } |
1456 | } |
1457 | |
1458 | impl std::error::Error for GlibNoneError {} |
1459 | |
1460 | impl<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)] |
1470 | pub enum GlibNoneOrInvalidError<I: Error> { |
1471 | Invalid(I), |
1472 | None, |
1473 | } |
1474 | |
1475 | impl<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 | |
1498 | impl<I: Error> From<I> for GlibNoneOrInvalidError<I> { |
1499 | #[inline ] |
1500 | fn from(invalid: I) -> Self { |
1501 | Self::Invalid(invalid) |
1502 | } |
1503 | } |
1504 | |
1505 | impl<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 | |
1517 | impl<I: Error> Error for GlibNoneOrInvalidError<I> {} |
1518 | |
1519 | impl<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. |
1549 | pub 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. |
1573 | pub 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. |
1606 | pub 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 ] |
1621 | pub 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 ] |
1630 | pub 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 ] |
1639 | pub unsafe fn from_glib_borrow<P: Ptr, T: FromGlibPtrBorrow<P>>(ptr: P) -> Borrowed<T> { |
1640 | FromGlibPtrBorrow::from_glib_borrow(ptr) |
1641 | } |
1642 | |
1643 | impl<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 | |
1654 | impl<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 | |
1666 | impl<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 | |
1677 | impl 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 |
1686 | impl 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 |
1696 | impl 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 |
1705 | impl 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))] |
1715 | pub(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)] |
1725 | pub(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))] |
1738 | pub(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)] |
1748 | pub(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 | |
1761 | impl 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 | |
1769 | impl 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 | |
1778 | impl 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 | |
1786 | impl 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))] |
1796 | pub(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)] |
1803 | pub(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)] |
1812 | impl 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)] |
1829 | impl 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)] |
1844 | impl 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)] |
1859 | impl 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 | |
1873 | impl 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 | |
1881 | impl 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 | |
1890 | impl 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 | |
1898 | impl 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. |
1908 | pub 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. |
1926 | pub 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 | |
1937 | pub 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 | |
1949 | pub trait FromGlibContainerAsVec<T, P: Ptr> |
1950 | where |
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 | |
1958 | pub trait FromGlibPtrArrayContainerAsVec<P: Ptr, PP: Ptr>: FromGlibContainerAsVec<P, PP> |
1959 | where |
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 | |
1967 | impl 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 | |
1993 | impl 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 | |
2009 | macro_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 | |
2057 | impl_from_glib_container_as_vec_fundamental!(u8); |
2058 | impl_from_glib_container_as_vec_fundamental!(i8); |
2059 | impl_from_glib_container_as_vec_fundamental!(u16); |
2060 | impl_from_glib_container_as_vec_fundamental!(i16); |
2061 | impl_from_glib_container_as_vec_fundamental!(u32); |
2062 | impl_from_glib_container_as_vec_fundamental!(i32); |
2063 | impl_from_glib_container_as_vec_fundamental!(u64); |
2064 | impl_from_glib_container_as_vec_fundamental!(i64); |
2065 | impl_from_glib_container_as_vec_fundamental!(f32); |
2066 | impl_from_glib_container_as_vec_fundamental!(f64); |
2067 | |
2068 | macro_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 |
2161 | impl_from_glib_container_as_vec_string!(String, *const c_char); |
2162 | impl_from_glib_container_as_vec_string!(String, *mut c_char); |
2163 | |
2164 | impl_from_glib_container_as_vec_string!(PathBuf, *const c_char); |
2165 | impl_from_glib_container_as_vec_string!(PathBuf, *mut c_char); |
2166 | impl_from_glib_container_as_vec_string!(OsString, *const c_char); |
2167 | impl_from_glib_container_as_vec_string!(OsString, *mut c_char); |
2168 | |
2169 | impl<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 | |
2183 | impl<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 | |
2199 | impl<T> FromGlibContainerAsVec<<T as GlibPtrDefault>::GlibType, *mut ffi::GSList> for T |
2200 | where |
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 | |
2252 | impl<T> FromGlibPtrArrayContainerAsVec<<T as GlibPtrDefault>::GlibType, *mut ffi::GSList> for T |
2253 | where |
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 | |
2291 | impl<T> FromGlibContainerAsVec<<T as GlibPtrDefault>::GlibType, *mut ffi::GList> for T |
2292 | where |
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 | |
2344 | impl<T> FromGlibPtrArrayContainerAsVec<<T as GlibPtrDefault>::GlibType, *mut ffi::GList> for T |
2345 | where |
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 | |
2383 | impl<T> FromGlibContainerAsVec<<T as GlibPtrDefault>::GlibType, *const ffi::GList> for T |
2384 | where |
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 | |
2404 | impl<T> FromGlibPtrArrayContainerAsVec<<T as GlibPtrDefault>::GlibType, *const ffi::GList> for T |
2405 | where |
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 | |
2425 | impl<T> FromGlibContainerAsVec<<T as GlibPtrDefault>::GlibType, *const ffi::GSList> for T |
2426 | where |
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 | |
2446 | impl<T> FromGlibPtrArrayContainerAsVec<<T as GlibPtrDefault>::GlibType, *const ffi::GSList> for T |
2447 | where |
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)] |
2468 | impl 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)] |
2483 | impl 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 | |
2516 | impl<T> FromGlibContainerAsVec<<T as GlibPtrDefault>::GlibType, *mut ffi::GPtrArray> for T |
2517 | where |
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 | |
2568 | impl<T> FromGlibPtrArrayContainerAsVec<<T as GlibPtrDefault>::GlibType, *mut ffi::GPtrArray> for T |
2569 | where |
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 | |
2590 | impl<T> FromGlibContainerAsVec<<T as GlibPtrDefault>::GlibType, *const ffi::GPtrArray> for T |
2591 | where |
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 | |
2611 | impl<T> FromGlibPtrArrayContainerAsVec<<T as GlibPtrDefault>::GlibType, *const ffi::GPtrArray> for T |
2612 | where |
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. |
2636 | pub 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. |
2642 | pub unsafe trait TransparentType: Clone + Sized { |
2643 | type GlibType; |
2644 | } |
2645 | |
2646 | unsafe impl<T: TransparentPtrType> TransparentType for T { |
2647 | type GlibType = <T as GlibPtrDefault>::GlibType; |
2648 | } |
2649 | |
2650 | #[cfg (test)] |
2651 | mod 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 | |