safer_ffi/
boxed.rs

1//! `#[repr(C)]` [`Box`][`rust::Box`]ed types.
2//!
3//! # When to use [`repr_c::Box<T>`] _vs._ [`ThinBox<T>`]?
4//!
5//! In `fn` signatures, prefer [`repr_c::Box<T>`], since it reads more nicely.
6//!
7//! But [`repr_c::Box<T>`], by virtue of having been defined as a type alias rather than its own,
8//! dedicated, new-type wrapper `struct` (for historical reasons, the author wishes to fix this in
9//! some future version), comes with a couple limitations of which to be mindful:
10//!
11//!   - you cannot use associated functions on [`repr_c::Box<T>`]:
12//!
13//!     ```rust ,compile_fail
14//!     use ::safer_ffi::prelude::*;
15//!
16//!     repr_c::Box::new(42); // Error!
17//!     ```
18//!
19//!     ```rust ,ignore
20//!     # /*
21//!     error[E0599]: no function or associated item named `new` found for type
22//!     `_` in the current scope --> src/arc.rs:19:14
23//!         |
24//!     7   | repr_c::Box::new(42); // Error!
25//!         |              ^^^ function or associated item not found in `_`
26//!         |
27//!         = help: items from traits can only be used if the trait is in scope
28//!     # */
29//!     ```
30//!
31//!   - you should not `impl Trait for repr_c::Box<T> {`. Indeed, the `type` alias is defined as an
32//!     associated type "output" [through a `trait`][tr], and from the point of view of _coherence_
33//!     (the SemVer-aware overlapping-`impl`s checker), when from within a downstream crate, such as
34//!     yours (🫵), this is treated as a fully _blanket_ (generic) type param.
35//!
36//!     ```rust ,compile_fail
37//!     use ::safer_ffi::prelude::*;
38//!
39//!     trait MyFancyTrait {}
40//!
41//!     impl MyFancyTrait for i32 {}
42//!
43//!     // Error, *potentially*-overlapping `impl` in the future: what if
44//!     // `safer-ffi` were to define the assoc type of `FitForCBox` as `i32`?
45//!     //
46//!     // Anyhow, this is treated the same as if it had been:
47//!     // `impl<T> MyFancyTrait for T {}`, hence the overlap with `i32` above.
48//!     impl MyFancyTrait for repr_c::Box<bool> {}
49//!     ```
50//!
51//!     ```rust ,ignore
52//!     # /*
53//!     error[E0119]: conflicting implementations of trait `MyFancyTrait` for type `i32`
54//!       --> src/boxed.rs:44:1
55//!        |
56//!     9  | impl MyFancyTrait for i32 {}
57//!        | ------------------------- first implementation here
58//!     ...
59//!     16 | impl MyFancyTrait for repr_c::Box<bool> {}
60//!        | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `i32`
61//!     # */
62//!     ```
63//!
64//!       - To be completely honest, I don't feel like this failing is _that_ justified, and it may
65//!         just be a bug in _coherence_, but oh well, it is what it is 🤷.
66//!
67//! In either of these situations, you may want to directly target [`ThinBox<T>`] instead.
68//!
69//! [tr]: [`FitForCBox`]
70use_prelude!();
71
72ReprC! {
73    #[repr(transparent)]
74    /// An FFI-safe representation of a standard-library `Box<T>`, as a thin pointer.
75    ///
76    /// (It is thus the same as [`Box<T>`][`rust::Box`], (_e.g._, same `#[repr(C)]` layout), but
77    /// with **no non-aliasing guarantee**.)
78    ///
79    /// # When to use [`repr_c::Box<T>`] _vs._ [`ThinBox<T>`]?
80    ///
81    /// See [the module docs][self]
82    pub
83    struct ThinBox[T] (
84        ptr::NonNullOwned<T>,
85    );
86}
87
88impl<T> From<rust::Box<T>> for ThinBox<T> {
89    #[inline]
90    fn from(boxed: rust::Box<T>) -> ThinBox<T> {
91        Self(ptr::NonNull::from(rust::Box::leak(boxed)).into())
92    }
93}
94
95impl<T> ThinBox<T> {
96    #[inline]
97    pub fn new(value: T) -> Self {
98        rust::Box::new(value).into()
99    }
100
101    #[inline]
102    pub fn into(self: ThinBox<T>) -> rust::Box<T> {
103        let mut this = mem::ManuallyDrop::new(self);
104        unsafe { rust::Box::from_raw(this.0.as_mut_ptr()) }
105    }
106}
107
108impl<T> Drop for ThinBox<T> {
109    #[inline]
110    fn drop(self: &'_ mut ThinBox<T>) {
111        unsafe {
112            drop::<rust::Box<T>>(rust::Box::from_raw(self.0.as_mut_ptr()));
113        }
114    }
115}
116
117impl<T> Deref for ThinBox<T> {
118    type Target = T;
119
120    #[inline]
121    fn deref(self: &'_ ThinBox<T>) -> &'_ T {
122        unsafe { &*self.0.as_ptr() }
123    }
124}
125
126impl<T> DerefMut for ThinBox<T> {
127    #[inline]
128    fn deref_mut(self: &'_ mut ThinBox<T>) -> &'_ mut T {
129        unsafe { &mut *(self.0.as_mut_ptr()) }
130    }
131}
132
133unsafe impl<T> Send for ThinBox<T> where rust::Box<T>: Send {}
134
135unsafe impl<T> Sync for ThinBox<T> where rust::Box<T>: Sync {}
136
137impl<T: Clone> Clone for ThinBox<T> {
138    #[inline]
139    fn clone(self: &'_ Self) -> Self {
140        Self::new(T::clone(self))
141    }
142}
143
144impl<T: fmt::Debug> fmt::Debug for ThinBox<T> {
145    fn fmt(
146        self: &'_ Self,
147        fmt: &'_ mut fmt::Formatter<'_>,
148    ) -> fmt::Result {
149        T::fmt(self, fmt)
150    }
151}
152
153#[doc(no_inline)]
154pub use crate::slice::slice_boxed;
155#[doc(no_inline)]
156pub use crate::string::str_boxed;
157
158/// A `?Sized`-aware alias, for convenience:
159///
160///   - when `T : Sized`, this is [`ThinBox<T>`];
161///   - when `T = [U]`, this is [`c_slice::Box<U>`];
162///   - when `T = dyn 'static + Send + FnMut(…) -> _`, this is [the dedicated hand-rolled FFI-safe
163///     `dyn` "closure" struct of the given arity][crate::closure::boxed].
164///
165/// # When to use [`repr_c::Box<T>`] _vs._ [`ThinBox<T>`]?
166///
167/// See [the module docs][self]
168pub type Box<T> = <T as FitForCBox>::CBoxWrapped;
169
170#[doc(hidden)]
171#[deprecated = "Use `ThinBox<T>` instead"]
172pub type Box_<T> = ThinBox<T>;
173
174/// Helper trait enabling the definition of [`Box<T>`].
175pub trait FitForCBox {
176    type CBoxWrapped;
177}
178
179impl<T: Sized> FitForCBox for T {
180    type CBoxWrapped = ThinBox<T>;
181}
182
183impl<T: Sized> FitForCBox for [T] {
184    type CBoxWrapped = c_slice::Box<T>;
185}