stackbox/slot.rs
1use crate::prelude::*;
2
3use ::core::{
4 // marker::PhantomData,
5 mem,
6};
7
8/// Same as [`Slot::VACANT`], but using function call syntax to avoid firing
9/// the [trigger-happy `const_item_mutation` lint](
10/// https://github.com/rust-lang/rust/pull/75573).
11///
12/// A so-created `&mut Slot<T>` is then to be used to derive a
13/// [`StackBox`]`<'slot, T>` out of it, by feeding a value to the slot:
14///
15/// - either by using [`StackBox::new_in()`],
16///
17/// - or the equivalent [`.stackbox()`] convenience method on [`Slot`]s.
18///
19/// [`.stackbox()`]: `Slot::stackbox`
20#[inline(always)]
21pub
22const
23fn mk_slot<T> ()
24 -> Slot<T>
25{
26 Slot::VACANT
27}
28
29/// A `Sized` and [`uninit`][`::core::mem::MaybeUninit`] slot to
30/// manually handle the scope of [`StackBox`]'s backing inline allocations.
31///
32/// If needed, multiple such slots can be defined within the local scope and
33/// bound to a variadic number of identifiers (variable names) using the
34/// [`mk_slots!`][`crate::mk_slots`] macro.
35pub
36struct Slot<T> {
37 place: mem::MaybeUninit<T>,
38 // /// Invariant lifetime just in case.
39 // _borrow_mut_once: PhantomData<fn(&()) -> &mut &'frame ()>,
40}
41
42impl<T> Slot<T> {
43 /// A vacant slot, to be used to derive a [`StackBox`]`<'slot, T>` out of
44 /// it, by feeding a value to the slot:
45 ///
46 /// - either by using [`StackBox::new_in()`],
47 ///
48 /// - or the equivalent [`.stackbox()`] convenience method on [`Slot`]s.
49 ///
50 /// [`.stackbox()`]: `Slot::stackbox`
51 pub
52 const VACANT: Self = Slot {
53 place: mem::MaybeUninit::uninit(),
54 // _borrow_mut_once: PhantomData,
55 };
56
57 /// Convenience shortcut for [`StackBox::new_in()`].
58 #[inline(always)]
59 pub
60 fn stackbox<'frame> (self: &'frame mut Slot<T>, value: T)
61 -> StackBox<'frame, T>
62 where
63 T : 'frame,
64 {
65 let ptr = Self::__init_raw(self, value);
66 unsafe {
67 // Safety: `mem::MaybeUninit` does not drop it.
68 StackBox::assume_owns(ptr)
69 }
70 }
71
72 #[doc(hidden)] /** Not part of the public API */ pub
73 fn __init_raw<'frame> (this: &'frame mut Slot<T>, value: T)
74 -> &'frame mut ::core::mem::ManuallyDrop<T>
75 {
76 this.place = mem::MaybeUninit::new(value);
77 unsafe {
78 // Safety: value has been initialized.
79 mem::transmute::<
80 &'_ mut mem::MaybeUninit<T>,
81 &'_ mut mem::ManuallyDrop<T>,
82 >(
83 &mut this.place,
84 )
85 }
86 }
87}
88
89/// Convenience macro to batch-create multiple [`Slot`]s.
90///
91/// ```rust
92/// # use ::stackbox::prelude::*;
93/// mk_slots!(foo, bar, baz);
94/// # drop::<[&mut ::stackbox::Slot<()>; 3]>([foo, bar, baz]);
95/// ```
96///
97/// is a shorthand for multiple [`mk_slot()`][`mk_slot`] calls:
98///
99/// ```rust
100/// # use ::stackbox::prelude::*;
101/// let foo = &mut mk_slot();
102/// let bar = &mut mk_slot();
103/// let baz = &mut mk_slot();
104/// # drop::<[&mut ::stackbox::Slot<()>; 3]>([foo, bar, baz]);
105/// ```
106///
107/// A so-created `&mut Slot<T>` is then to be used to derive a
108/// [`StackBox`]`<'slot, T>` out of it, by feeding a value to the slot:
109///
110/// - either by using [`StackBox::new_in()`],
111///
112/// - or the equivalent [`.stackbox()`] convenience method on [`Slot`]s.
113///
114/// [`.stackbox()`]: `Slot::stackbox`
115#[macro_export]
116macro_rules! mk_slots {(
117 $($var_name:ident),+ $(,)?
118) => (
119 $(
120 let ref mut $var_name = $crate::prelude::mk_slot();
121 )+
122)}