diff options
| author | Niv Kaminer <nivkner@zoho.com> | 2018-08-14 19:06:51 +0300 |
|---|---|---|
| committer | Niv Kaminer <nivkner@zoho.com> | 2018-08-23 01:37:03 +0300 |
| commit | f9efd0578a890d9441da468cc5eed6b9f2ed87df (patch) | |
| tree | b0e768a76e3bf18c2b6b58d0120aa97a7a418f43 /src/liballoc | |
| parent | c1103885feb415f82ad36f04f54d229173077a84 (diff) | |
| download | rust-f9efd0578a890d9441da468cc5eed6b9f2ed87df.tar.gz rust-f9efd0578a890d9441da468cc5eed6b9f2ed87df.zip | |
move pin module to liballoc and reexport that
Diffstat (limited to 'src/liballoc')
| -rw-r--r-- | src/liballoc/pin.rs | 82 |
1 files changed, 79 insertions, 3 deletions
diff --git a/src/liballoc/pin.rs b/src/liballoc/pin.rs index bacc13fa74a..0ecf4ac0a69 100644 --- a/src/liballoc/pin.rs +++ b/src/liballoc/pin.rs @@ -10,17 +10,93 @@ //! Types which pin data to its location in memory //! -//! see the [standard library module] for more information +//! It is sometimes useful to have objects that are guaranteed to not move, +//! in the sense that their placement in memory in consistent, and can thus be relied upon. //! -//! [standard library module]: ../../std/pin/index.html +//! A prime example of such a scenario would be building self-referencial structs, +//! since moving an object with pointers to itself will invalidate them, +//! which could cause undefined behavior. +//! +//! In order to prevent objects from moving, they must be *pinned*, +//! by wrapping the data in special pointer types, such as [`PinMut`] and [`PinBox`]. +//! These restrict access to the underlying data to only be immutable by implementing [`Deref`], +//! unless the type implements the [`Unpin`] trait, +//! which indicates that it doesn't need these restrictions and can be safely mutated, +//! by implementing [`DerefMut`]. +//! +//! This is done because, while modifying an object can be done in-place, +//! it might also relocate a buffer when its at full capacity, +//! or it might replace one object with another without logically "moving" them with [`swap`]. +//! +//! [`PinMut`]: struct.PinMut.html +//! [`PinBox`]: struct.PinBox.html +//! [`Unpin`]: ../../core/marker/trait.Unpin.html +//! [`DerefMut`]: ../../core/ops/trait.DerefMut.html +//! [`Deref`]: ../../core/ops/trait.Deref.html +//! [`swap`]: ../../core/mem/fn.swap.html +//! +//! # Examples +//! +//! ```rust +//! #![feature(pin)] +//! +//! use std::pin::PinBox; +//! use std::marker::Pinned; +//! use std::ptr::NonNull; +//! +//! // This is a self referencial struct since the slice field points to the data field. +//! // We cannot inform the compiler about that with a normal reference, +//! // since this pattern cannot be described with the usual borrowing rules. +//! // Instead we use a raw pointer, though one which is known to not be null, +//! // since we know it's pointing at the string. +//! struct Unmovable { +//! data: String, +//! slice: NonNull<String>, +//! _pin: Pinned, +//! } +//! +//! impl Unmovable { +//! // To ensure the data doesn't move when the function returns, +//! // we place it in the heap where it will stay for the lifetime of the object, +//! // and the only way to access it would be through a pointer to it. +//! fn new(data: String) -> PinBox<Self> { +//! let res = Unmovable { +//! data, +//! // we only create the pointer once the data is in place +//! // otherwise it will have already moved before we even started +//! slice: NonNull::dangling(), +//! _pin: Pinned, +//! }; +//! let mut boxed = PinBox::new(res); +//! +//! let slice = NonNull::from(&boxed.data); +//! // we know this is safe because modifying a field doesn't move the whole struct +//! unsafe { PinBox::get_mut(&mut boxed).slice = slice }; +//! boxed +//! } +//! } +//! +//! let unmoved = Unmovable::new("hello".to_string()); +//! // The pointer should point to the correct location, +//! // so long as the struct hasn't moved. +//! // Meanwhile, we are free to move the pointer around. +//! let mut still_unmoved = unmoved; +//! assert_eq!(still_unmoved.slice, NonNull::from(&still_unmoved.data)); +//! +//! // Now the only way to access to data (safely) is immutably, +//! // so this will fail to compile: +//! // still_unmoved.data.push_str(" world"); +//! +//! ``` #![unstable(feature = "pin", issue = "49150")] +pub use core::pin::*; + use core::convert::From; use core::fmt; use core::future::{Future, FutureObj, LocalFutureObj, UnsafeFutureObj}; use core::marker::{Unpin, Unsize}; -use core::pin::PinMut; use core::ops::{CoerceUnsized, Deref, DerefMut}; use core::task::{Context, Poll}; |
