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}