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}