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