stackbox/stackbox/mod.rs
1use ::core::mem::ManuallyDrop;
2use crate::{prelude::*,
3 ptr,
4 Slot,
5};
6
7pub
8mod slice;
9
10/// Stack<sup>1</sup>-allocated `Box`. Think of this as of `&'frame mut T`, but
11/// with `move` semantics (no reborrowing!) which allow the "reference" to drop
12/// its pointee.
13///
14/// <small><sup>1</sup> Pedantic nit: actually, it is _local_-allocated: if the
15/// local is created inside a generator such as an `async` block or function,
16/// crossing a `yield` / `.await` point (thus captured by the generator),
17/// and that generator / future is `Box`-ed, then the local will be living on
18/// the heap.</small>
19///
20/// Given the `move` semantics / lack of reborrowing, there may seem to be
21/// little point in using this over the seemingly more flexible
22/// `&'frame mut T`, or the clearly more simple `T`.
23///
24/// And indeed that is mostly true: the usage of this wrapper is a bit _niche_.
25/// Use this wrapper when:
26///
27/// 1. You want / _need_ the move semantics (`FnOnce`) ⇒ no `&mut` for you
28/// (assuming `Option::take` is too cumbersome, costly or directly unusable
29/// for your use case).
30///
31/// 1. You _need_ the indirection:
32///
33/// - if `T` is big, and you need move semantics, moving `T` around may
34/// be expensive if the compiler is not able to elide the
35/// bitwise-copies (`memcpy`) that happen when the value is moved.
36///
37/// - ### Main usage
38///
39/// If you need a **fat pointer to perform some type erasure**, while
40/// preserving ownership / `move` semantics, and you don't want (or
41/// actually _can't_) use the heap allocation from [`Box`], then this
42/// type is for you!
43///
44/// ### Examples of type erasure
45///
46/// #### 1 - Array to slice coercion and `IntoIter`
47///
48/// `IntoIterator` for ~~arrays~~ slices:
49///
50/// ```rust
51/// # use ::core::mem::drop as stuff;
52/// use ::stackbox::prelude::*;
53///
54/// stackbox!(let boxed_slice: StackBox<'_, [_]> = [
55/// String::from("Hello, "),
56/// String::from("World!"),
57/// ]);
58/// for s in boxed_slice {
59/// println!("{}", s);
60/// stuff::<String>(s);
61/// }
62/// ```
63///
64/// - or with some [`#[with]` sugar:](https://docs.rs/with_locals):
65///
66/// <details>
67///
68/// ```rust
69/// # use ::core::mem::drop as stuff;
70/// use ::stackbox::prelude::*;
71/// use ::with_locals::with;
72///
73/// #[with('local)]
74/// fn main ()
75/// {
76/// let boxed_array: StackBox<'local, [String; 2]> = StackBox::new([
77/// String::from("Hello, "),
78/// String::from("World!"),
79/// ]);
80/// let boxed_slice: StackBox<'_, [String]> = boxed_array.into_slice();
81/// for s in boxed_slice {
82/// println!("{}", s);
83/// stuff::<String>(s);
84/// }
85/// }
86/// ```
87///
88/// ___
89///
90/// </details>
91///
92/// While `&mut [T; N] → &mut [T]` already covers most of the use cases,
93/// imagine needing the `[T]` slice type erasure (_e.g._, an `if` branch which
94/// yields arrays of different lengths) and also needing to have
95/// [`IntoIterator`] available to you. And you don't want to "stupidly" pay a
96/// heap allocation for something that should not deserve one:
97///
98/// ```rust
99/// # use ::core::mem::drop as stuff;
100/// use ::core::mem::ManuallyDrop;
101/// use ::stackbox::prelude::*;
102///
103/// # let some_condition = || true;
104/// mk_slots!(storage1, storage2); // uninit stack allocations.
105/// let boxed_slice_of_strings: StackBox<'_, [String]> =
106/// if some_condition() {
107/// StackBox::new_in(storage1, [
108/// String::from("Hi."),
109/// ])
110/// .into_slice() // [String; 1] → [String]
111/// } else {
112/// // If using the macro, the coercion happens automagically
113/// stackbox!(storage2, [
114/// "Hello, ".into(),
115/// "World!".into(),
116/// ])
117/// }
118/// ;
119/// for s in boxed_slice_of_strings {
120/// println!("{}", s);
121/// stuff::<String>(s);
122/// }
123/// ```
124///
125/// #### 2 - Allocation-less `dyn FnOnce` (and owned `dyn Any`)
126///
127/// See the [dedicated module for more info][`crate::dyn_traits`].
128///
129/// ```rust
130/// use ::stackbox::prelude::*;
131/// # let some_condition = || true;
132///
133/// mk_slots!(f1, f2);
134/// let f: StackBoxDynFnOnce_0<()> = if some_condition() {
135/// f1.stackbox(move || {
136/// // …
137/// }).into_dyn()
138/// } else {
139/// f2.stackbox(move || {
140/// // …
141/// }).into_dyn()
142/// };
143/// // …
144/// f.call();
145/// ```
146 // TYPE INVARIANTS:
147 // - See the `# Safety` section of [`StackBox::assume_owns`].
148#[repr(transparent)]
149pub
150struct StackBox<'frame, T : ?Sized + 'frame> {
151 /// Covariant and non-null and, ideally, tagged as unaliased.
152 unique_ptr: ptr::Unique<T>,
153 /// Covariant lifetime (this is an `&'frame mut MD<T>`, afterall).
154 _covariant_lt: ::core::marker::PhantomData<&'frame ()>,
155}
156
157impl<'frame, T : 'frame> StackBox<'frame, T> {
158 /// # Main non-`unsafe` non-macro non-callback constructor.
159 ///
160 /// To be used most of the time (when `T : Sized`, and when no implicit
161 /// implicit coercion is needed).
162 ///
163 /// - Creation of the [`Slot`]s is possible either manually, by binding
164 /// the return value of [`mk_slot()`] to some variable, by `ref mut`,
165 /// or if multiple slots are needed, they can be batch created thanks
166 /// to the [`mk_slots!`] convenience helper macro.
167 ///
168 /// ## Example
169 ///
170 /// ```rust
171 /// use ::stackbox::prelude::*;
172 ///
173 /// let slot = &mut mk_slot();
174 /// let boxed = if true {
175 /// StackBox::new_in(slot, 42)
176 /// } else {
177 /// StackBox::new_in(slot, 27)
178 /// };
179 /// assert_eq!(*boxed, 42);
180 /// ```
181 #[inline(always)]
182 pub
183 fn new_in (slot: &'frame mut Slot<T>, value: T)
184 -> StackBox<'frame, T>
185 {
186 slot.stackbox(value)
187 }
188
189 /// Alternative non-`unsafe` non-macro constructor, where instead of an
190 /// explicit [`Slot`] that defines the scope of validity of the
191 /// [`StackBox`] (its stack frame), a callback is used: the `StackBox` is
192 /// valid for the duration of the callback.
193 ///
194 /// ## Example
195 ///
196 /// ```rust
197 /// use ::stackbox::prelude::*;
198 ///
199 /// StackBox::with_new(42, |stackbox: StackBox<'_, i32>| {
200 /// let any: StackBoxDynAny<'_> = stackbox.into_dyn();
201 /// assert_eq!(
202 /// any.downcast_ref::<i32>().unwrap(),
203 /// &42,
204 /// );
205 /// }) // <- `StackBox` cannot outlive this point.
206 /// ```
207 ///
208 /// ## Ergonomic usage thanks to `#[::with_locals::with]`
209 ///
210 /// Using this constructor can be made quite ergonomic by using the
211 /// [`#[with]` CPS sugar](https://docs.rs/with_locals):
212 ///
213 /// ```rust
214 /// # macro_rules! ignore {($($t:tt)*) => ()} ignore! {
215 /// use ::stackbox::prelude::*;
216 /// use ::with_locals::with;
217 ///
218 /// #[with]
219 /// fn main ()
220 /// {
221 /// let stackbox: StackBox<'ref, /* … */> = StackBox::new({
222 /// /* … */
223 /// });
224 /// // …
225 /// }
226 /// # } fn main () {}
227 /// ```
228 #[inline]
229 pub
230 fn with_new<R, F> (value: T, ret: F) -> R
231 where
232 F: for<'local> FnOnce(StackBox<'local, T>) -> R,
233 {
234 ret(StackBox::new_in(&mut mk_slot(), value))
235 }
236
237 /// Unwraps / extracts / moves the pointee out of the [`StackBox`].
238 ///
239 /// ### Note
240 ///
241 /// This lets the used [`Slot`] [vacant][`Slot::VACANT`] again, which can
242 /// thus be reused to create another [`StackBox`].
243 // Note: `self` receiver is fine because there is no `DerefMove` yet.
244 #[inline]
245 pub
246 fn into_inner (self: StackBox<'frame, T>)
247 -> T
248 {
249 unsafe {
250 // Safety: from the type invariant.
251
252 // 1 - Disable the `Drop` glue.
253 let this = ManuallyDrop::new(self);
254 // 2 - We can now *take* the value:
255 ::core::ptr::read::<T>(&**this)
256 }
257 }
258}
259
260impl<'frame, T : ?Sized + 'frame> StackBox<'frame, T> {
261 /// Raw `unsafe` constructor, by taking ownership of a borrowing pointer.
262 ///
263 /// # Safety
264 ///
265 /// This type has ownership of the pointee `T`. This means that despite the
266 /// borrow-looking nature of the `&'frame mut`, the pointee should not be
267 /// used (⇒ not dropped!) once it has been pointed to by a `StackBox` /
268 /// given to this function: the `ManuallyDrop<T>` pointee will represent
269 /// deallocated memory after the `'frame` lifetime!
270 ///
271 /// As a rule of thumb, it is _sound_ to call this function when and only
272 /// when calling [`ManuallyDrop::drop`] is.
273 ///
274 /// When possible (`T : Sized`), prefer to use the non-`unsafe`
275 /// constructors:
276 ///
277 /// - Either [`StackBox::new_in`] (_e.g._, `Sized` case),
278 ///
279 /// - (or the [CPS / callback](
280 /// https://en.wikipedia.org/wiki/Continuation-passing_style)-based
281 /// [`StackBox::with_new`] constructor).
282 ///
283 /// - Or the [`stackbox!`] macro, for most usages.
284 #[inline]
285 pub
286 unsafe
287 fn assume_owns (it: &'frame mut ManuallyDrop<T>)
288 -> StackBox<'frame, T>
289 {
290 Self {
291 unique_ptr: ptr::Unique::<T>::from_raw(&mut **it),
292 _covariant_lt: Default::default(),
293 }
294 }
295
296 #[cfg(feature = "unsize")]
297 #[inline]
298 pub(in crate)
299 fn into_inner_unique(self)
300 -> ptr::Unique<T>
301 {
302 let this = ManuallyDrop::new(self);
303 unsafe {
304 // Safety: moving out of this which is not dropped.
305 // This is basically destructuring self which impls `Drop`.
306 ::core::ptr::read(&this.unique_ptr)
307 }
308 }
309}
310
311impl<'frame, T : ?Sized + 'frame>
312 ::core::ops::Deref
313for
314 StackBox<'frame, T>
315{
316 type Target = T;
317
318 #[inline]
319 fn deref (self: &'_ StackBox<'frame, T>)
320 -> &'_ T
321 {
322 &*self.unique_ptr
323 }
324}
325
326impl<'frame, T : ?Sized + 'frame>
327 ::core::ops::DerefMut
328for
329 StackBox<'frame, T>
330{
331 #[inline]
332 fn deref_mut (self: &'_ mut StackBox<'frame, T>)
333 -> &'_ mut T
334 {
335 &mut *self.unique_ptr
336 }
337}
338
339impl<T : ?Sized> Drop for StackBox<'_, T> {
340 #[inline]
341 fn drop (self: &'_ mut Self)
342 {
343 unsafe {
344 // # Safety
345 //
346 // - From the type invariant
347 ptr::Unique::<T>::drop_in_place(&mut self.unique_ptr)
348 }
349 }
350}
351
352#[cfg(feature = "unsize")]
353/// Allows conversion to a `StackBox` containing an unsized type.
354///
355/// # Usage
356///
357/// ```
358/// use core::fmt::Display;
359/// use unsize::{Coercion, CoerceUnsize};
360/// use stackbox::prelude::*;
361///
362/// let slot = &mut mk_slot();
363/// let num = StackBox::<usize>::new_in(slot, 42);
364///
365/// let display: StackBox<dyn Display> = num.unsize(Coercion::to_display());
366/// ```
367unsafe impl<'frame, T : 'frame, U: ?Sized + 'frame>
368 ::unsize::CoerciblePtr<U>
369for
370 StackBox<'frame, T>
371{
372 type Pointee = T;
373 type Output = StackBox<'frame, U>;
374
375 fn as_sized_ptr(self: &mut Self) -> *mut T {
376 &*self.unique_ptr as *const T as *mut T
377 }
378
379 unsafe fn replace_ptr(self, new: *mut U) -> StackBox<'frame, U> {
380 let _covariant_lt = self._covariant_lt;
381
382 let new_ptr = self
383 .into_inner_unique()
384 .into_raw_nonnull()
385 .as_mut()
386 .replace_ptr(new);
387
388 // Safety: we've forgotten the old pointer and this is the correctly unsized old pointer so
389 // valid for the pointed-to memory.
390 let unique_ptr = ptr::Unique::from_raw(new_ptr);
391
392 StackBox {
393 unique_ptr,
394 _covariant_lt,
395 }
396 }
397}
398
399/// Convenience macro for more ergonomic [`StackBox`] constructions.
400#[macro_export]
401macro_rules! stackbox {
402 (
403 // Same as `StackBox::new_in`, except for it allowing an unsized
404 // coercion to take place.
405 $place:expr,
406 $value:expr $(,)?
407 ) => (match ($place, $value) { (place, value) => {
408 let ptr = $crate::Slot::__init_raw(place, value);
409 unsafe {
410 let _ = $crate::__::concat!(
411 "Safety: `", stringify!($place), "` has just been initialized",
412 );
413 $crate::StackBox::assume_owns(ptr)
414 }
415 }});
416
417 (
418 // Create a new `mut` `StackBox` without mentioning the backing _slot_:
419 // `let mut <binding> = stackbox!($expr);`
420 // Examples:
421 // - `stackbox!(let mut new_var = <expr>);`
422 // - `stackbox!(let mut new_var: StackBox<[_]> = <array expr>);`
423 let mut $var:ident $(: $T:ty)? = $expr:expr
424 ) => (
425 $crate::stackbox!($expr => let mut $var $(: $T)?)
426 );
427
428 (
429 // Create a new `StackBox` without mentioning the backing _slot_:
430 // `let <binding> = stackbox!($expr);`
431 // Examples:
432 // - `stackbox!(let new_var = <expr>);`
433 // - `stackbox!(let new_var: StackBox<[_]> = <array expr>);`
434 let $var:ident $(: $T:ty)? = $expr:expr
435 ) => (
436 $crate::stackbox!($expr => let $var $(: $T)?)
437 );
438
439 (
440 // Internal-ish: assign the result of a `stackbox!($expr)` to "some place"
441 // where "some place" may be a new `let` binding or an actual assignment.
442 //
443 // No need to explicitly mention the backing _slot_ either.
444 // Examples:
445 // - `let var: Ty; stackbox!(<expr> => var);`
446 $expr:expr => $($binding:tt)*
447 ) => (
448 let ref mut ptr = $crate::__::ManuallyDrop::new($expr);
449 $($binding)* = unsafe { $crate::StackBox::assume_owns(ptr) };
450 );
451
452 (
453 // Shorthand for `stackbox!(let mut $var = $var)`
454 let mut $var:ident
455 ) => (
456 $crate::stackbox!(let mut $var = $var)
457 );
458
459 (
460 // Shorthand for `stackbox!(let $var = $var)`
461 let $var:ident
462 ) => (
463 $crate::stackbox!(let $var = $var)
464 );
465
466 (
467 // To be used as a temporary fed to a function parameter, or as a
468 // `[::with_locals::with]` "return" value.
469 //
470 // Examples:
471 // - `fun(stackbox!(value))`
472 $expr:expr
473 ) => (
474 match &mut $crate::__::ManuallyDrop::new($expr) { ptr => {
475 #[allow(unused_unsafe)] {
476 unsafe {
477 // Safety: anonymous temporary is unusable
478 $crate::StackBox::assume_owns(ptr)
479 }
480 }
481 }}
482 );
483}