stackpin/
lib.rs

1//! The `stackpin` crate exposes a [`StackPinned`] type that allows to represent [`!Unpin`] data that should be [pinned](https://doc.rust-lang.org/std/pin/index.html) to the stack
2//! at the point of declaration.
3//! The crate exposes a trait, [`FromUnpinned`], as well as a [`stack_let`] macro that makes safely creating [`StackPinned`] instances easier.
4//! The crate also exposes the [`PinStack`] type alias for `Pin<StackPinned<T>>`.
5//!
6//! This crate was inspired from the [pin-utils] crate, the main differences being:
7//! * [pin-utils] provides a macro to return a `Pin<&mut T>` instance,
8//!   with a "mutable reference" semantics that includes reborrow. The `stackpin` crate promotes a
9//!   "root handle" semantics that guarantees that a function consuming a [`PinStack<T>`] consumes
10//!   the *only* handle to `T`, and not a reborrowed reference.
11//! * The syntax for the `stack_let!(mut id : ty = expr)` macro attempts to mimic a regular `let mut id : ty = expr` statement.
12//! * The provided [`FromUnpinned`] trait and [`Unpinned`] struct aim at separating unmovable types
13//! from the data that can be used to construct them. `stackpin` aims at promoting a model where
14//! all unmovable types are only accessible once pinned.
15//! * The [`StackPinned<T>`] type expresses strong guarantee about the fact that the destructor for
16//! `T` will be run.
17//! * The `stackpin` crate solely focuses on stack pinning. The [pin-utils] crate also provides
18//! other utilities such as pin projection.
19//!
20//! # Stack pinnable types
21//!
22//! A type T that wants to benefit from the guarantees provided by [`StackPinned`] should be
23//! [`!Unpin`]. This is necessary to enforce the "drop will be run" guarantee.
24//!
25//! Additionally, the `stackpin` crate promotes an idiom where "unmovable" types are strictly
26//! separated from movable types, and are preferably only accessible through `PinStack`.
27//!
28//! For example, let's consider the following `Unmovable` struct (from the [documentation for the
29//! `pin` module](https://doc.rust-lang.org/std/pin/index.html)):
30//! ```
31//! use std::marker::PhantomPinned;
32//! use std::ptr::NonNull;
33//! struct Unmovable {
34//!     // Owned data
35//!     s: String,
36//!     // Self referential pointer meant to point to `s`
37//!     slice: NonNull<String>,
38//!     // Obligatory marker that makes this struct `!Unpin`.
39//!     // Without this, implementing `FromUnpinned` for `Unmovable` would not be safe.
40//!     _pinned: PhantomPinned,
41//! }
42//! ```
43//!
44//! It is important to note that this struct is **not** unmovable by itself, as there are no such types in Rust.
45//! Instead, we are going to enforce this through privacy: since the fields of the struct are private, no instance can be created
46//! from outside the module.
47//! Similarly, no public "constructor" function `pub fn new() -> Unmovable` should be provided.
48//!
49//! So, how will clients consume `Unmovable` instances?
50//!
51//! The recommended solution using `stackpin` is to implement `FromUnpinned<Data>` for `Unmovable`, where `Data` is the
52//! type that would normally serve as parameters in a "constructor" function.
53//! ```
54//! # use std::marker::PhantomPinned;
55//! # use std::ptr::NonNull;
56//! # struct Unmovable {
57//! #     s: String,
58//! #     slice: NonNull<String>,
59//! #     _pinned: PhantomPinned,
60//! # }
61//! use stackpin::FromUnpinned;
62//! // An `Unmovable` can be created from a `String`
63//! unsafe impl FromUnpinned<String> for Unmovable {
64//!     // This associated type can be used to retain information between the creation of the instance and its pinning.
65//!     // This allows for some sort of "two-steps initialization" without having to store the initialization part in the
66//!     // type itself.
67//!     // Here, we don't need it, so we just set it to `()`.
68//!     type PinData = ();
69//!
70//!     // Simply builds the Unmovable from the String.
71//!     // The implementation of this function is not allowed to consider that the type won't ever move **yet**.
72//!     // (in particular, the `Self` instance is returned by this function)
73//!     // Note, however, that safe users of FromUnpinned will:
74//!     // * Not do anything to with the returned `Self` instance between the call to
75//!     //   `from_unpinned` and the call to `on_pin`.
76//!     // * Not panic between calling the two functions
77//!     // * Always call the second function if the first has been called.
78//!     unsafe fn from_unpinned(s: String) -> (Self, ()) {
79//!         (
80//!             Self {
81//!                 s,
82//!                 // We will "fix" this dangling pointer once the data will be pinned
83//!                 // and guaranteed not to move anymore.
84//!                 slice: NonNull::dangling(),
85//!                 _pinned: PhantomPinned,
86//!             },
87//!             (),
88//!         )
89//!     }
90//!
91//!     // Performs a second initialization step on an instance that is already guaranteed to never move again.
92//!     // This allows to e.g. set self borrow with the guarantee that they will remain valid.
93//!     unsafe fn on_pin(&mut self, _data: ()) {
94//!         // Data will never move again, set the pointer to our own internal String whose address
95//!         // will never change anymore
96//!         self.slice = NonNull::from(&self.s);
97//!     }
98//! }
99//! ```
100//! With `FromUnpinned<Data>` implemented for `T`, one can now add a "constructor method" that would return an
101//! `Unpinned<Data, T>`. The `Unpinned<U, T>` struct is a simple helper struct around `U` that maintains the destination
102//! type `T`. This is used by the [`stack_let`] macro to infer the type of `T` that the user may want to produce.
103//!
104//! ```
105//! # use std::marker::PhantomPinned;
106//! # use std::ptr::NonNull;
107//! # struct Unmovable {
108//! #     s: String,
109//! #     slice: NonNull<String>,
110//! #     _pinned: PhantomPinned,
111//! # }
112//! # use stackpin::Unpinned;
113//! # use stackpin::FromUnpinned;
114//! # unsafe impl FromUnpinned<String> for Unmovable {
115//! #     type PinData = ();
116//! #     unsafe fn from_unpinned(s: String) -> (Self, ()) {
117//! #         (
118//! #             Self {
119//! #                 s,
120//! #                 slice: NonNull::dangling(),
121//! #                 _pinned: PhantomPinned,
122//! #             },
123//! #             (),
124//! #         )
125//! #     }
126//! #     unsafe fn on_pin(&mut self, _data: ()) {
127//! #         self.slice = NonNull::from(&self.s);
128//! #     }
129//! # }
130//! impl Unmovable {
131//!     fn new_unpinned<T: Into<String>>(s: T) -> Unpinned<String, Unmovable> {
132//!        Unpinned::new(s.into())
133//!     }
134//! }
135//! ```
136//!
137//! Then, a user of the `Unmovable` struct can simply build an instance by using the [`stack_let`] macro:
138//! ```
139//! # use std::marker::PhantomPinned;
140//! # use std::ptr::NonNull;
141//! # struct Unmovable {
142//! #     s: String,
143//! #     slice: NonNull<String>,
144//! #     _pinned: PhantomPinned,
145//! # }
146//! # use stackpin::Unpinned;
147//! # use stackpin::FromUnpinned;
148//! # unsafe impl FromUnpinned<String> for Unmovable {
149//! #     type PinData = ();
150//! #     unsafe fn from_unpinned(s: String) -> (Self, ()) {
151//! #         (
152//! #             Self {
153//! #                 s,
154//! #                 slice: NonNull::dangling(),
155//! #                 _pinned: PhantomPinned,
156//! #             },
157//! #             (),
158//! #         )
159//! #     }
160//! #     unsafe fn on_pin(&mut self, _data: ()) {
161//! #         self.slice = NonNull::from(&self.s);
162//! #     }
163//! # }
164//! # impl Unmovable {
165//! #     fn new_unpinned<T: Into<String>>(s: T) -> Unpinned<String, Unmovable> {
166//! #        Unpinned::new(s.into())
167//! #     }
168//! # }
169//! use stackpin::stack_let;
170//! // ...
171//! stack_let!(unmovable = Unmovable::new_unpinned("Intel the Beagle")); // this creates the unmovable instance on the stack and binds `unmovable` with a `PinStack<Unmovable>`
172//! // ...
173//! ```
174//!
175//! [pin-utils]: https://docs.rs/pin-utils
176//! [`StackPinned`]: struct.StackPinned.html
177//! [`StackPinned<T>`]: struct.StackPinned.html
178//! [`FromUnpinned`]: trait.FromUnpinned.html
179//! [`stack_let`]: macro.stack_let.html
180//! [`PinStack`]: type.PinStack.html
181//! [`PinStack<T>`]: type.PinStack.html
182//! [`Unpinned`]: struct.Unpinned.html
183//! [`!Unpin`]: https://doc.rust-lang.org/std/pin/index.html#unpin
184
185use std::marker::PhantomData;
186use std::ops::Deref;
187use std::ops::DerefMut;
188use std::pin::Pin;
189
190/// Struct that represents data that is pinned to the stack, at the point of declaration.
191///
192/// Because this property cannot be guaranteed by safe rust, constructing an instance of a
193/// [`StackPinned`] directly is `unsafe`.
194/// Rather, one should use the [`stack_let`] macro that returns a [`PinStack`] instance.
195///
196/// In particular, one should note the following about [`StackPinned`] instance:
197/// * It is impossible to safely pass a [`StackPinned`] instance to a function
198/// * It is impossible to safely return a [`StackPinned`] instance from a function
199/// * It is impossible to safely store a [`StackPinned`] instance inside of a struct
200///
201/// Instead, one should replace [`StackPinned<T>`] with [`PinStack<T>`] in each of these situations.
202///
203/// A [`PinStack<T>`] instance does have its benefits:
204/// * The underlying `T` instance is guaranteed to never move for `T: !Unpin` once pinned.
205///   This is useful for `T` types whose instances should never move.
206/// * For `T: !Unpin`, the destructor of `T` is guaranteed to run when the T leaves the stack frame it was allocated on,
207///   even if one uses [`std::mem::forget`](https://doc.rust-lang.org/std/mem/fn.forget.html) on
208///   the [`PinStack<T>`] instance.
209///
210/// [`StackPinned`]: struct.StackPinned.html
211/// [`StackPinned<T>`]: struct.StackPinned.html
212/// [`PinStack`]: type.PinStack.html
213/// [`PinStack<T>`]: type.PinStack.html
214/// [`stack_let`]: macro.stack_let.html
215#[repr(transparent)]
216pub struct StackPinned<'pin, T>(&'pin mut T);
217
218impl<'pin, T> StackPinned<'pin, T> {
219    /// # Safety
220    /// Currently the only way to build a safe [`StackPinned<T>`] instance is to use the
221    /// [`stack_let`] macro that will return a [`PinStack<T>`] instance.
222    ///
223    /// [`StackPinned<T>`]: struct.StackPinned.html
224    /// [`PinStack<T>`]: type.PinStack.html
225    /// [`stack_let`]: macro.stack_let.html
226    #[inline(always)]
227    pub unsafe fn new(t: &'pin mut T) -> Self {
228        Self(t)
229    }
230}
231
232impl<'pin, T> Deref for StackPinned<'pin, T> {
233    type Target = T;
234    fn deref(&self) -> &Self::Target {
235        &self.0
236    }
237}
238
239impl<'pin, T> DerefMut for StackPinned<'pin, T> {
240    fn deref_mut(&mut self) -> &mut <Self as Deref>::Target {
241        &mut self.0
242    }
243}
244
245/// Trait to build [`StackPinned`] values from unpinned types.
246///
247/// Implementers of `FromUnpinned<Source>` indicate that they can be built from a `Source` instance,
248/// to the condition that they will be pinned afterwards.
249///
250/// # Safety
251///
252/// This trait both exposes unsafe functions **and** is unsafe to implement.
253/// * Unsafe functions are exposed because the functions have the preconditions of having to be
254/// called from the [`stack_let`] macro.
255/// * The trait itself is unsafe to implement because implementers must provide implementations of
256/// the functions that must uphold invariants that cannot be checked by the compiler. See the
257/// documentation of each function for information on the invariants.
258///
259/// [`stack_let`]: macro.stack_let.html
260/// [`StackPinned`]: struct.StackPinned.html
261pub unsafe trait FromUnpinned<Source>
262where
263    Self: Sized,
264{
265    /// This associated type can be used to retain information between the creation of the instance and its pinning.
266    /// This allows for some sort of "two-steps initialization" without having to store the initialization part in the
267    /// type itself.
268    type PinData;
269
270    /// Performs a first initialization step, resulting in the creation of the `Self` instance.
271    ///
272    /// # Safety
273    ///
274    /// * This function is used by the construction macro, it is never safe to call directly.
275    /// * Implementers of this function  are **not** allowed to consider that the type won't ever move **yet**.
276    ///   (in particular, the `Self` instance is returned by this function). The type should be
277    ///   movable at this point.
278    unsafe fn from_unpinned(src: Source) -> (Self, Self::PinData);
279
280    /// Performs a second initialization step, resulting in the pinning of the `Self` instance.
281    ///
282    /// # Safety
283    ///
284    /// * This function is used by the construction macro, it is never safe to call directly.
285    /// * Implementers of this function **are** allowed to consider that the type won't move ever again.
286    ///   You can for instance set autoborrows safely in this function.
287    /// * For convenience, a naked mutable borrow is directly given.
288    ///   Implementers of this function are **not** allowed to move out of this mutable borrow.
289    unsafe fn on_pin(&mut self, pin_data: Self::PinData);
290}
291
292/// A helper struct around `U` that remembers the `T` destination type.
293///
294/// This struct is typically used to build [`PinStack`] values using the [`stack_let`] macro
295/// without having to specify the destination type.
296///
297/// # Example
298///
299/// ```
300/// # use std::marker::PhantomPinned;
301/// # use std::ptr::NonNull;
302/// # struct Unmovable {
303/// #     s: String,
304/// #     slice: NonNull<String>,
305/// #     _pinned: PhantomPinned,
306/// # }
307/// # use stackpin::Unpinned;
308/// # use stackpin::FromUnpinned;
309/// # unsafe impl FromUnpinned<String> for Unmovable {
310/// #     type PinData = ();
311/// #     unsafe fn from_unpinned(s: String) -> (Self, ()) {
312/// #         (
313/// #             Self {
314/// #                 s,
315/// #                 slice: NonNull::dangling(),
316/// #                 _pinned: PhantomPinned,
317/// #             },
318/// #             (),
319/// #         )
320/// #     }
321/// #     unsafe fn on_pin(&mut self, _data: ()) {
322/// #         self.slice = NonNull::from(&self.s);
323/// #     }
324/// # }
325/// use stackpin::stack_let;
326/// // Without `Unpinned`
327/// fn new_string(s : impl Into<String>) -> String { s.into() }
328/// stack_let!(unmovable : Unmovable = new_string("toto"));
329/// // With `Unpinned`
330/// fn new_unpinned(s : impl Into<String>) -> Unpinned<String, Unmovable> { Unpinned::new(s.into()) }
331/// stack_let!(unmovable = new_unpinned("toto"));
332/// ```
333///
334/// [`stack_let`]: macro.stack_let.html
335/// [`PinStack`]: type.PinStack.html
336pub struct Unpinned<U, T: FromUnpinned<U>> {
337    u: U,
338    t: std::marker::PhantomData<T>,
339}
340
341unsafe impl<U, T: FromUnpinned<U>> FromUnpinned<Unpinned<U, T>> for T {
342    type PinData = <T as FromUnpinned<U>>::PinData;
343
344    unsafe fn from_unpinned(src: Unpinned<U, T>) -> (Self, Self::PinData) {
345        <T as FromUnpinned<U>>::from_unpinned(src.u)
346    }
347
348    unsafe fn on_pin(&mut self, pin_data: Self::PinData) {
349        <T as FromUnpinned<U>>::on_pin(self, pin_data)
350    }
351}
352
353impl<U, T: FromUnpinned<U>> Unpinned<U, T> {
354    pub fn new(u: U) -> Self {
355        Self { u, t: PhantomData }
356    }
357}
358
359#[doc(hidden)]
360#[macro_export]
361macro_rules! internal_pin_stack {
362    ($id:ident) => {
363        // Shadow the original binding so that it can't directly be accessed ever again.
364        let $id: $crate::PinStack<_> = unsafe {
365            let $id = $crate::StackPinned::new(&mut $id);
366
367            std::pin::Pin::new_unchecked($id)
368        };
369    };
370    (mut $id:ident) => {
371        // Shadow the original binding so that it can't directly be accessed ever again.
372        let mut $id: $crate::PinStack<_> = unsafe {
373            let $id = $crate::StackPinned::new(&mut $id);
374
375            std::pin::Pin::new_unchecked($id)
376        };
377    };
378}
379
380#[doc(hidden)]
381pub unsafe fn write_pinned<Source, Dest>(source: Source, pdest: *mut Dest)
382where
383    Dest: FromUnpinned<Source>,
384{
385    let (dest, data) = FromUnpinned::<Source>::from_unpinned(source);
386    std::ptr::write(pdest, dest);
387    FromUnpinned::<Source>::on_pin(&mut *pdest, data);
388}
389
390#[doc(hidden)]
391pub unsafe fn from_unpinned<Source, Dest>(
392    source: Unpinned<Source, Dest>,
393) -> (Dest, Dest::PinData, PhantomData<Unpinned<Source, Dest>>)
394where
395    Dest: FromUnpinned<Source>,
396{
397    let (dest, data) = FromUnpinned::from_unpinned(source);
398    (dest, data, PhantomData)
399}
400
401#[doc(hidden)]
402pub unsafe fn from_source<Dest, Source>(
403    source: Source,
404) -> (Dest, Dest::PinData, PhantomData<Source>)
405where
406    Dest: FromUnpinned<Source>,
407{
408    let (dest, data) = FromUnpinned::from_unpinned(source);
409    (dest, data, PhantomData)
410}
411
412#[doc(hidden)]
413pub unsafe fn on_pin<Source, Dest>(
414    pdest: *mut Dest,
415    data: Dest::PinData,
416    _source: PhantomData<Source>,
417) where
418    Dest: FromUnpinned<Source>,
419{
420    FromUnpinned::<Source>::on_pin(&mut *pdest, data);
421}
422
423/// `stack_let!(id = expr)` binds a [`PinStack<T>`] to `id` if `expr` is an expression of type `U` where [`T: FromUnpinned<U>`].
424///
425/// If `expr` is of type [`Unpinned<U, T>`] for some `U`, then no type annotation is necessary.
426/// If `expr` is of type `U` where [`T: FromUnpinned<U>`], use `stack_let!(id : T = expr)`.
427///
428/// To bind `id` mutably, use `stack_let!(mut id = expr)`.
429///
430/// [`PinStack<T>`]: type.PinStack.html
431/// [`T: FromUnpinned<U>`]: trait.FromUnpinned.html
432/// [`Unpinned<U, T>`]: struct.Unpinned.html
433#[macro_export]
434macro_rules! stack_let {
435    ($id: ident = $expr: expr) => {
436        let (mut $id, _stack_data, _stack_phantom) = unsafe { $crate::from_unpinned($expr) };
437        unsafe { $crate::on_pin(&mut $id as *mut _, _stack_data, _stack_phantom) }
438
439        $crate::internal_pin_stack!($id);
440    };
441    (mut $id: ident = $expr: expr) => {
442        let (mut $id, _stack_data, _stack_phantom) = unsafe { $crate::from_unpinned($expr) };
443        unsafe { $crate::on_pin(&mut $id as *mut _, _stack_data, _stack_phantom) }
444
445        $crate::internal_pin_stack!(mut $id);
446    };
447    ($id: ident : $type:ty = $expr: expr) => {
448        let (mut $id, _stack_data, _stack_phantom) =
449            unsafe { $crate::from_source::<$type, _>($expr) };
450        unsafe { $crate::on_pin(&mut $id as *mut _, _stack_data, _stack_phantom) }
451
452        $crate::internal_pin_stack!($id);
453    };
454    (mut $id: ident : $type:ty = $expr: expr) => {
455        let (mut $id, _stack_data, _stack_phantom) =
456            unsafe { $crate::from_source::<$type, _>($expr) };
457        unsafe { $crate::on_pin(&mut $id as *mut _, _stack_data, _stack_phantom) }
458
459        $crate::internal_pin_stack!(mut $id);
460    };
461}
462
463/// Short-hand for `Pin<StackPinned<T>>`
464pub type PinStack<'a, T> = Pin<StackPinned<'a, T>>;
465
466#[cfg(test)]
467mod tests {
468    use super::FromUnpinned;
469    use super::PinStack;
470    use super::Unpinned;
471    use std::marker::PhantomPinned;
472    use std::ptr::NonNull;
473
474    struct Unmovable {
475        data: String,
476        slice: NonNull<String>,
477        _pin: PhantomPinned,
478    }
479
480    impl Unmovable {
481        fn slice(&self) -> &str {
482            unsafe { self.slice.as_ref() }
483        }
484
485        fn slice_mut<'a>(this: &'a mut PinStack<Unmovable>) -> &'a mut str {
486            unsafe { this.as_mut().get_unchecked_mut().slice.as_mut() }
487        }
488    }
489
490    impl Unmovable {
491        fn new_unpinned(src: String) -> Unpinned<String, Unmovable> {
492            Unpinned::new(src)
493        }
494    }
495
496    unsafe impl FromUnpinned<String> for Unmovable {
497        type PinData = ();
498        unsafe fn from_unpinned(src: String) -> (Self, Self::PinData) {
499            (
500                Self {
501                    data: src,
502                    slice: NonNull::dangling(),
503                    _pin: PhantomPinned,
504                },
505                (),
506            )
507        }
508
509        unsafe fn on_pin(&mut self, _pin_data: Self::PinData) {
510            self.slice = NonNull::from(&self.data);
511        }
512    }
513
514    #[test]
515    fn let_stack_unmovable() {
516        let test_str = "Intel the Beagle is the greatest dog in existence";
517        stack_let!(mut unmovable = Unmovable::new_unpinned(String::from(test_str)));
518        let slice = Unmovable::slice_mut(&mut unmovable);
519        slice.make_ascii_uppercase();
520        assert_eq!(test_str.to_ascii_uppercase(), Unmovable::slice(&unmovable));
521    }
522}