foreign/foreign.rs
1/// Traits to map between C structs and native Rust types.
2/// Similar to glib-rs but a bit simpler and possibly more
3/// idiomatic.
4use std::fmt;
5use std::fmt::Debug;
6use std::mem::{self, MaybeUninit};
7use std::ptr;
8
9/// A type for which there is a canonical representation as a C datum.
10pub trait FreeForeign {
11 /// The representation of `Self` as a C datum. Typically a
12 /// `struct`, though there are exceptions: for example `String`
13 /// and `str` use `c_char` for strings, since C strings are of
14 /// `char *` type. These exceptional cases will not implement
15 /// the `FixedAlloc` trait.
16 type Foreign;
17
18 /// Free the C datum pointed to by `p`.
19 ///
20 /// # Safety
21 ///
22 /// `p` must be `NULL` or point to valid data.
23 ///
24 /// ```
25 /// # use foreign::{CloneToForeign, FreeForeign};
26 /// let foreign = "Hello, world!".clone_to_foreign();
27 /// unsafe {
28 /// String::free_foreign(foreign.into_inner());
29 /// }
30 /// ```
31 unsafe fn free_foreign(p: *mut Self::Foreign);
32}
33
34/// A type for which a representation as a C datum can be produced.
35pub trait CloneToForeign: FreeForeign {
36 /// Convert a native Rust object to a foreign C pointer, copying
37 /// everything pointed to by `self`; return an [`OwnedPointer`]
38 /// which will take care of freeing the storage (same as
39 /// `to_glib_none` in `glib-rs`)
40 fn clone_to_foreign(&self) -> OwnedPointer<Self>;
41
42 /// Convert a native Rust object to a foreign C pointer, copying
43 /// everything pointed to by `self` (same as `to_glib_full`
44 /// in `glib-rs`).
45 ///
46 /// This function is useful when C functions will take ownership
47 /// of the returned pointer; alternatively, the pointer can
48 /// be freed with the `free_foreign` associated function.
49 #[must_use]
50 fn clone_to_foreign_ptr(&self) -> *mut Self::Foreign {
51 self.clone_to_foreign().into_inner()
52 }
53}
54
55/// A type which is stored in a fixed amount of memory given by
56/// `mem::size_of::<Self::Foreign>()`.
57///
58/// # Safety
59///
60/// Define this trait only if `CloneToForeign` allocates a single memory block,
61/// of constant size `mem::size_of::<Self::Foreign>()`.
62pub unsafe trait FixedAlloc: CloneToForeign + FromForeign + FreeForeign + Sized {
63 /// Convert a native Rust object to a foreign C struct, copying its
64 /// contents to preallocated memory at `dest`.
65 ///
66 /// ```
67 /// # use std::mem::MaybeUninit;
68 /// # use foreign::FixedAlloc;
69 /// let mut dest = MaybeUninit::uninit();
70 /// unsafe {
71 /// u8::clone_into_foreign(dest.as_mut_ptr(), &42);
72 /// assert_eq!(dest.assume_init(), 42);
73 /// }
74 /// ```
75 ///
76 /// # Safety
77 ///
78 /// `dest` must be allocated and writable.
79 unsafe fn clone_into_foreign(dest: *mut Self::Foreign, src: &Self);
80
81 /// Copy `src.len()` elements from memory at address `src` into a Rust array,
82 /// using [`cloned_from_foreign`](FromForeign::cloned_from_foreign) on each
83 /// element.
84 ///
85 /// ```
86 /// # use std::mem::MaybeUninit;
87 /// # use foreign::FixedAlloc;
88 /// let src: [u8; 3] = [1, 2, 3];
89 /// let dest: [u8; 3] = unsafe {
90 /// u8::clone_array_from_foreign(src.as_ptr())
91 /// };
92 /// assert_eq!(dest, src);
93 /// ```
94 ///
95 /// # Safety
96 ///
97 /// `src` must be allocated, large enough to host `N` values of type
98 /// `Self::Foreign`, and readable.
99 unsafe fn clone_array_from_foreign<const N: usize>(mut src: *const Self::Foreign) -> [Self; N] {
100 unsafe {
101 // SAFETY: MaybeUninit<Self> has the same layout as Self
102 let mut uninit = MaybeUninit::<[Self; N]>::uninit();
103
104 let mut dest = uninit.as_mut_ptr().cast::<Self>();
105 for _ in 0..N {
106 ptr::write(dest, Self::cloned_from_foreign(src));
107 dest = dest.offset(1);
108 src = src.offset(1);
109 }
110
111 // SAFETY: each element was initialized with write()
112 uninit.assume_init()
113 }
114 }
115
116 /// Copy the `src.len()` elements of the slice into memory at address `dest`,
117 /// using [`clone_into_foreign`](FixedAlloc::clone_into_foreign) on each
118 /// element.
119 ///
120 /// ```
121 /// # use std::mem::MaybeUninit;
122 /// # use foreign::FixedAlloc;
123 /// let mut dest: MaybeUninit::<[u8; 3]> = MaybeUninit::uninit();
124 /// unsafe {
125 /// u8::clone_from_native_slice(dest.as_mut_ptr().cast(), &[1, 2, 3]);
126 /// assert_eq!(dest.assume_init(), [1, 2, 3]);
127 /// };
128 /// ```
129 ///
130 /// # Safety
131 ///
132 /// `dest` must be allocated, large enough to host `N` values of type
133 /// `Self::Foreign`, and writable.
134 unsafe fn clone_from_native_slice(mut dest: *mut Self::Foreign, src: &[Self]) {
135 unsafe {
136 for item in src {
137 Self::clone_into_foreign(dest, item);
138 dest = dest.offset(1);
139 }
140 }
141 }
142}
143
144/// A type for C data that can be converted to native Rust object, taking ownership
145/// of the C datum. You should not need to implement this trait as long as the
146/// Rust types implement `FromForeign`.
147pub trait IntoNative<U> {
148 /// Convert a C datum to a native Rust object, taking ownership of
149 /// the pointer or Rust object (same as `from_glib_full` in `glib-rs`)
150 ///
151 /// # Safety
152 ///
153 /// `self` must point to valid data, or can be `NULL` if `U` is an
154 /// `Option` type. It becomes invalid after the function returns.
155 ///
156 /// ```
157 /// # use foreign::{CloneToForeign, IntoNative};
158 /// let s = "Hello, world!".to_string();
159 /// let foreign = s.clone_to_foreign();
160 /// let native: String = unsafe {
161 /// foreign.into_native()
162 /// // foreign is not leaked
163 /// };
164 /// assert_eq!(s, native);
165 /// ```
166 unsafe fn into_native(self) -> U;
167}
168
169impl<T, U> IntoNative<U> for *mut T
170where
171 U: FromForeign<Foreign = T>,
172{
173 unsafe fn into_native(self) -> U {
174 U::from_foreign(self)
175 }
176}
177
178/// A type which can be constructed from a canonical representation as a
179/// C datum.
180pub trait FromForeign: FreeForeign + Sized {
181 /// Convert a C datum to a native Rust object, copying everything
182 /// pointed to by `p` (same as `from_glib_none` in `glib-rs`)
183 ///
184 /// # Safety
185 ///
186 /// `p` must point to valid data, or can be `NULL` is `Self` is an
187 /// `Option` type.
188 ///
189 /// ```
190 /// # use foreign::FromForeign;
191 /// let p = c"Hello, world!".as_ptr();
192 /// let s = unsafe {
193 /// String::cloned_from_foreign(p as *const std::ffi::c_char)
194 /// };
195 /// assert_eq!(s, "Hello, world!");
196 /// ```
197 unsafe fn cloned_from_foreign(p: *const Self::Foreign) -> Self;
198
199 /// Convert a C datum to a native Rust object, taking ownership of
200 /// the pointer or Rust object (same as `from_glib_full` in `glib-rs`)
201 ///
202 /// The default implementation calls `cloned_from_foreign` and frees `p`.
203 ///
204 /// # Safety
205 ///
206 /// `p` must point to valid data, or can be `NULL` is `Self` is an
207 /// `Option` type. `p` becomes invalid after the function returns.
208 ///
209 /// ```
210 /// # use foreign::{CloneToForeign, FromForeign};
211 /// let s = "Hello, world!";
212 /// let foreign = s.clone_to_foreign();
213 /// unsafe {
214 /// assert_eq!(String::from_foreign(foreign.into_inner()), s);
215 /// }
216 /// // foreign is not leaked
217 /// ```
218 unsafe fn from_foreign(p: *mut Self::Foreign) -> Self {
219 let result = Self::cloned_from_foreign(p);
220 Self::free_foreign(p);
221 result
222 }
223}
224
225/// A RAII pointer that is automatically freed when it goes out of scope.
226pub struct OwnedPointer<T: FreeForeign + ?Sized> {
227 ptr: *mut <T as FreeForeign>::Foreign,
228}
229
230impl<T: FreeForeign + ?Sized> OwnedPointer<T> {
231 /// Return a new `OwnedPointer` that wraps the NULL pointer.
232 pub fn null_mut() -> Self {
233 OwnedPointer {
234 ptr: ptr::null_mut(),
235 }
236 }
237
238 /// Return a new `OwnedPointer` that wraps the pointer `ptr`.
239 ///
240 /// # Safety
241 ///
242 /// The pointer must be valid and live until the returned `OwnedPointer`
243 /// is dropped.
244 pub unsafe fn new(ptr: *mut <T as FreeForeign>::Foreign) -> Self {
245 OwnedPointer { ptr }
246 }
247
248 /// Safely create an `OwnedPointer` from one that has the same
249 /// freeing function.
250 /// ```
251 /// # use foreign::{CloneToForeign, OwnedPointer};
252 /// let s = "Hello, world!";
253 /// let foreign_str = s.clone_to_foreign();
254 /// let foreign_string = OwnedPointer::<String>::from(foreign_str);
255 /// # assert_eq!(foreign_string.into_native(), s);
256 pub fn from<U>(x: OwnedPointer<U>) -> Self
257 where
258 U: FreeForeign<Foreign = <T as FreeForeign>::Foreign> + ?Sized,
259 {
260 unsafe {
261 // SAFETY: the pointer type and free function are the same,
262 // only the type changes
263 OwnedPointer::new(x.into_inner())
264 }
265 }
266
267 /// Safely convert an `OwnedPointer` into one that has the same
268 /// freeing function.
269 /// ```
270 /// # use foreign::{CloneToForeign, OwnedPointer};
271 /// let s = "Hello, world!";
272 /// let foreign_str = s.clone_to_foreign();
273 /// let foreign_string: OwnedPointer<String> = foreign_str.into();
274 /// # assert_eq!(foreign_string.into_native(), s);
275 pub fn into<U>(self) -> OwnedPointer<U>
276 where
277 U: FreeForeign<Foreign = <T as FreeForeign>::Foreign>,
278 {
279 OwnedPointer::from(self)
280 }
281
282 /// Return the pointer that is stored in the `OwnedPointer`. The
283 /// pointer is valid for as long as the `OwnedPointer` itself.
284 ///
285 /// ```
286 /// # use foreign::CloneToForeign;
287 /// let s = "Hello, world!";
288 /// let foreign = s.clone_to_foreign();
289 /// let p = foreign.as_ptr();
290 /// let len = unsafe { libc::strlen(p) };
291 /// drop(foreign);
292 /// # assert_eq!(len, 13);
293 /// ```
294 pub fn as_ptr(&self) -> *const <T as FreeForeign>::Foreign {
295 self.ptr
296 }
297
298 pub fn as_mut_ptr(&self) -> *mut <T as FreeForeign>::Foreign {
299 self.ptr
300 }
301
302 /// Return the pointer that is stored in the `OwnedPointer`,
303 /// consuming the `OwnedPointer` but not freeing the pointer.
304 ///
305 /// ```
306 /// # use foreign::CloneToForeign;
307 /// let s = "Hello, world!";
308 /// let p = s.clone_to_foreign().into_inner();
309 /// let len = unsafe { libc::strlen(p) };
310 /// // p needs to be freed manually
311 /// # assert_eq!(len, 13);
312 /// # unsafe { libc::free(p as *mut libc::c_void); }
313 /// ```
314 #[must_use]
315 pub fn into_inner(mut self) -> *mut <T as FreeForeign>::Foreign {
316 let result = mem::replace(&mut self.ptr, ptr::null_mut());
317 mem::forget(self);
318 result
319 }
320}
321
322impl<T: FromForeign> OwnedPointer<T> {
323 /// Convert a C datum to a native Rust object, taking ownership of
324 /// the pointer or Rust object (same as `from_glib_full` in `glib-rs`)
325 ///
326 /// ```
327 /// # use foreign::{CloneToForeign, IntoNative};
328 /// let s = "Hello, world!".to_string();
329 /// let foreign = s.clone_to_foreign();
330 /// let native: String = unsafe {
331 /// foreign.into_native()
332 /// // foreign is not leaked
333 /// };
334 /// assert_eq!(s, native);
335 /// ```
336 pub fn into_native(self) -> T {
337 // SAFETY: the pointer was passed to the unsafe constructor OwnedPointer::new
338 unsafe { T::from_foreign(self.into_inner()) }
339 }
340}
341
342impl<T: FreeForeign + ?Sized> Debug for OwnedPointer<T> {
343 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
344 let name = std::any::type_name::<T>();
345 let name = format!("OwnedPointer<{name}>");
346 f.debug_tuple(&name).field(&self.as_ptr()).finish()
347 }
348}
349
350impl<T: CloneToForeign + Default> Default for OwnedPointer<T> {
351 fn default() -> Self {
352 <T as Default>::default().clone_to_foreign()
353 }
354}
355
356impl<T: FreeForeign + ?Sized> Drop for OwnedPointer<T> {
357 fn drop(&mut self) {
358 let p = mem::replace(&mut self.ptr, ptr::null_mut());
359 // SAFETY: the pointer was passed to the unsafe constructor OwnedPointer::new
360 unsafe { T::free_foreign(p) }
361 }
362}
363
364/// A pointer whose contents were borrowed from a Rust object, and
365/// therefore whose lifetime is limited to the lifetime of the
366/// underlying Rust object. The Rust object was borrowed from a
367/// shared reference, and therefore the pointer is not mutable.
368pub struct BorrowedPointer<P: FreeForeign + ?Sized, T> {
369 ptr: *const <P as FreeForeign>::Foreign,
370 storage: T,
371}
372
373impl<P: FreeForeign + ?Sized, T> BorrowedPointer<P, T> {
374 /// Return a new `BorrowedPointer` that wraps the pointer `ptr`.
375 /// `storage` can contain any other data that `ptr` points to,
376 /// and that should be dropped when the `BorrowedPointer` goes out
377 /// of scope.
378 ///
379 /// # Safety
380 ///
381 /// The pointer must be valid for the lifetime of the `BorrowedPointer`.
382 /// If the pointer points into the storage, `T` must be pinned.
383 pub unsafe fn new(ptr: *const <P as FreeForeign>::Foreign, storage: T) -> Self {
384 BorrowedPointer { ptr, storage }
385 }
386
387 /// Return the pointer that is stored in the `BorrowedPointer`. The
388 /// pointer is valid for as long as the `BorrowedPointer` itself.
389 ///
390 /// ```
391 /// # use foreign::BorrowForeign;
392 /// # use std::ffi::CString;
393 /// let s = CString::new("Hello, world!").unwrap();
394 /// let borrowed = s.borrow_foreign();
395 /// let len = unsafe { libc::strlen(borrowed.as_ptr()) };
396 /// # assert_eq!(len, 13);
397 /// ```
398 pub fn as_ptr(&self) -> *const <P as FreeForeign>::Foreign {
399 self.ptr
400 }
401
402 /// Safely convert a `BorrowedPointer` into one that has the same
403 /// underlying type.
404 ///
405 /// (Not yet sure this is useful as part of the public API).
406 pub(crate) fn into<Q>(self) -> BorrowedPointer<Q, T>
407 where
408 Q: FreeForeign<Foreign = <P as FreeForeign>::Foreign>,
409 {
410 BorrowedPointer {
411 ptr: self.ptr,
412 storage: self.storage,
413 }
414 }
415
416 pub(crate) fn map<Q: FreeForeign<Foreign = P::Foreign>, F: FnOnce(T) -> U, U>(
417 self,
418 f: F,
419 ) -> BorrowedPointer<Q, U> {
420 BorrowedPointer {
421 ptr: self.ptr,
422 storage: f(self.storage),
423 }
424 }
425}
426
427impl<T: CloneToForeign + ?Sized> BorrowedPointer<T, &T> {
428 /// Clone the underlying data for the receiver, creating a new
429 /// C datum that contains the same data.
430 ///
431 /// ```
432 /// # use foreign::BorrowForeign;
433 /// # use std::ffi::CString;
434 /// let s = CString::new("Hello, world!").unwrap();
435 /// assert_eq!(s.borrow_foreign().as_ptr(), s.as_ptr());
436 /// assert_ne!(s.borrow_foreign().to_owned().as_ptr(), s.as_ptr());
437 /// ```
438 ///
439 /// ```
440 /// # use foreign::BorrowForeign;
441 /// # use std::ffi::CString;
442 /// let s: i8 = 42;
443 /// assert_eq!(s.borrow_foreign().as_ptr(), &s as *const _);
444 /// assert_ne!(s.borrow_foreign().to_owned().as_ptr(), &s as *const _);
445 /// ```
446 pub fn to_owned(&self) -> OwnedPointer<T> {
447 self.storage.clone_to_foreign()
448 }
449}
450
451impl<P: FreeForeign + ?Sized, T> Debug for BorrowedPointer<P, T> {
452 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
453 let ptr_name = std::any::type_name::<*mut <P as FreeForeign>::Foreign>();
454 let storage_name = std::any::type_name::<T>();
455 let name = format!("BorrowedPointer<{ptr_name}, {storage_name}>");
456 f.debug_tuple(&name).field(&self.as_ptr()).finish()
457 }
458}
459
460/// A type for which a C representation can be borrowed without cloning.
461pub trait BorrowForeign<'a>: FreeForeign {
462 /// The type of any extra data that are needed while the `BorrowedPointer` is alive.
463 type Storage: 'a;
464
465 /// Return a wrapper for a C representation of `self`. The wrapper
466 /// borrows the data from `self` and allows access via a constant pointer.
467 ///
468 /// ```
469 /// # use foreign::BorrowForeign;
470 /// # use std::ffi::CString;
471 /// let s = CString::new("Hello, world!").unwrap();
472 /// let borrowed = s.borrow_foreign();
473 /// let len = unsafe { libc::strlen(borrowed.as_ptr()) };
474 /// # assert_eq!(len, 13);
475 /// ```
476 fn borrow_foreign(&'a self) -> BorrowedPointer<Self, Self::Storage>;
477}
478
479/// A type for which a C representation can be created by consuming the
480/// Rust representation, hopefully without cloning much of the internal data.
481pub trait IntoForeign: FreeForeign {
482 /// The type of any extra data that are needed while the `BorrowedMutPointer` is alive.
483 ///
484 /// Usually `Self`, though does not have to be. For example,
485 /// [into_foreign()](IntoForeign::into_foreign()) could discard the
486 /// unnecessary parts of `self` or perform other conversions. In
487 /// particular, a `Cow<'_, str>` will use a `CString` as the storage.
488 type Storage: 'static;
489
490 /// Return a wrapper for a C representation of `self`. The wrapper
491 /// becomes the owner of `self` and allows access via a constant pointer.
492 ///
493 /// ```
494 /// # use foreign::IntoForeign;
495 /// let s = "Hello, world!".to_string();
496 /// let borrowed = s.into_foreign();
497 /// let len = unsafe { libc::strlen(borrowed.as_ptr()) };
498 /// # assert_eq!(len, 13);
499 /// ```
500 fn into_foreign(self) -> BorrowedMutPointer<Self, Self::Storage>;
501}
502
503/// A pointer whose contents were borrowed from a Rust object, and
504/// therefore whose lifetime is limited to the lifetime of the
505/// underlying Rust object. The Rust object is borrowed from an
506/// exclusive reference, and therefore the pointer is mutable.
507pub struct BorrowedMutPointer<P: FreeForeign + ?Sized, T> {
508 ptr: *mut <P as FreeForeign>::Foreign,
509 storage: T,
510}
511
512impl<P: FreeForeign + ?Sized, T> BorrowedMutPointer<P, T> {
513 /// Return a new `BorrowedMutPointer` that wraps the pointer `ptr`.
514 /// `storage` can contain any other data that `ptr` points to,
515 /// and that should be dropped when the `BorrowedMutPointer` goes out
516 /// of scope.
517 ///
518 /// # Safety
519 ///
520 /// The pointer must be valid for the lifetime of the `BorrowedPointer`.
521 /// If the pointer points into the storage, `T` must be pinned.
522 pub unsafe fn new(ptr: *mut <P as FreeForeign>::Foreign, storage: T) -> Self {
523 BorrowedMutPointer { ptr, storage }
524 }
525
526 /// Return the pointer that is stored in the `BorrowedMutPointer`. The
527 /// returned pointer is constant and is valid for as long as the
528 /// `BorrowedMutPointer` itself.
529 pub fn as_ptr(&self) -> *const <P as FreeForeign>::Foreign {
530 self.ptr
531 }
532
533 /// Return the pointer that is stored in the `BorrowedMutPointer`. The
534 /// returned pointer is mutable and is valid for as long as the
535 /// `BorrowedMutPointer` itself.
536 pub fn as_mut_ptr(&mut self) -> *mut <P as FreeForeign>::Foreign {
537 self.ptr
538 }
539
540 /// Safely convert a `BorrowedMutPointer` into one that has the same
541 /// underlying type.
542 ///
543 /// (Not yet sure this is useful as part of the public API).
544 pub(crate) fn into<Q>(self) -> BorrowedMutPointer<Q, T>
545 where
546 Q: FreeForeign<Foreign = <P as FreeForeign>::Foreign>,
547 {
548 BorrowedMutPointer {
549 ptr: self.ptr,
550 storage: self.storage,
551 }
552 }
553
554 pub(crate) fn map<Q: FreeForeign<Foreign = P::Foreign>, U, F: FnOnce(T) -> U>(
555 self,
556 f: F,
557 ) -> BorrowedMutPointer<Q, U> {
558 BorrowedMutPointer {
559 ptr: self.ptr,
560 storage: f(self.storage),
561 }
562 }
563}
564
565impl<P: FreeForeign + ?Sized, T> Debug for BorrowedMutPointer<P, T> {
566 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
567 let name = std::any::type_name::<*mut <P as FreeForeign>::Foreign>();
568 let name = format!("BorrowedMutPointer<{name}>");
569 f.debug_tuple(&name).field(&self.as_ptr()).finish()
570 }
571}
572
573/// A type for which a C representation can be borrowed mutably without cloning.
574pub trait BorrowForeignMut<'a>: FreeForeign {
575 /// The type of any extra data that are needed while the `BorrowedMutPointer` is alive.
576 type Storage: 'a;
577
578 /// Return a wrapper for a C representation of `self`. The wrapper
579 /// borrows the data from `self` and allows access via a mutable pointer.
580 ///
581 /// # Examples
582 ///
583 /// ```
584 /// # use foreign::BorrowForeignMut;
585 /// let mut i = 123i8;
586 /// let mut borrowed = i.borrow_foreign_mut();
587 /// unsafe {
588 /// assert_eq!(*borrowed.as_ptr(), 123i8);
589 /// *borrowed.as_mut_ptr() = 45i8;
590 /// }
591 /// assert_eq!(i, 45i8);
592 /// ```
593 /// is analogous to:
594 /// ```
595 /// let mut i = 123i8;
596 /// let borrowed = &mut i;
597 /// assert_eq!(*borrowed, 123i8);
598 /// *borrowed = 45i8;
599 /// assert_eq!(i, 45i8);
600 /// ```
601 ///
602 /// For integer types, or anything that implements [`FixedAlloc`], it is also possible
603 /// to borrow from a `Vec` or array:
604 ///
605 /// ```
606 /// # use std::ffi::{CStr, c_char};
607 /// # use foreign::BorrowForeignMut;
608 /// let mut v: [u8; 64] = [0; 64];
609 /// # if cfg!(miri) { return; }
610 /// unsafe {
611 /// libc::sprintf(v.borrow_foreign_mut().as_mut_ptr().cast::<c_char>(),
612 /// c"hello %s".as_ptr(),
613 /// c"world".as_ptr());
614 /// }
615 /// assert_eq!(CStr::from_bytes_until_nul(&v).unwrap(), c"hello world");
616 /// ```
617 fn borrow_foreign_mut(&'a mut self) -> BorrowedMutPointer<Self, Self::Storage>;
618}