diff options
| author | Niv Kaminer <nivkner@zoho.com> | 2018-08-07 21:14:57 +0300 |
|---|---|---|
| committer | Niv Kaminer <nivkner@zoho.com> | 2018-08-07 21:14:57 +0300 |
| commit | 68e766afab32a45e55728e11c17b996848a7dd49 (patch) | |
| tree | a56d88f250843512bef610da7626f8f93d336a62 | |
| parent | 87bbd2eeef1ad321b294e2d3b0fb2dc960390c86 (diff) | |
| download | rust-68e766afab32a45e55728e11c17b996848a7dd49.tar.gz rust-68e766afab32a45e55728e11c17b996848a7dd49.zip | |
remove general pinning information from Unpin trait
| -rw-r--r-- | src/libcore/marker.rs | 97 |
1 files changed, 9 insertions, 88 deletions
diff --git a/src/libcore/marker.rs b/src/libcore/marker.rs index d398ca62157..596727a0141 100644 --- a/src/libcore/marker.rs +++ b/src/libcore/marker.rs @@ -603,101 +603,22 @@ unsafe impl<T: ?Sized> Freeze for *mut T {} unsafe impl<'a, T: ?Sized> Freeze for &'a T {} unsafe impl<'a, T: ?Sized> Freeze for &'a mut T {} -/// Types that are safe to move. +/// Types which can be safely moved after being pinned. /// -/// Since moving objects is almost always safe, it is automatically implemented in most cases. +/// Since Rust itself has no notion of immovable types, and will consider moves to always be safe, +/// this trait cannot prevent types from moving by itself. /// -/// This trait is mainly used to build self referencial structs, -/// since moving an object with pointers to itself will invalidate them, -/// causing undefined behavior. +/// Instead it can be used to prevent moves through the type system, +/// by controlling the behavior of special pointers types like [`PinMut`], +/// which "pin" the type in place by wrapping it in a type which can only be dereferenced immutably. /// -/// # The Pin API +/// Implementing this trait lifts the restrictions of pinning off a type, +/// which then allows it to move out of said pointers with functions such as [`swap`]. /// -/// The `Unpin` trait doesn't actually change the behavior of the compiler around moves, -/// so code like this will compile just fine: -/// -/// ```rust -/// #![feature(pin)] -/// use std::marker::Pinned; -/// -/// struct Unmovable { -/// _pin: Pinned, // this marker type prevents Unpin from being implemented for this type -/// } -/// -/// let unmoved = Unmovable { _pin: Pinned }; -/// let moved = unmoved; -/// ``` -/// -/// In order to actually prevent the pinned objects from moving, -/// it has to be wrapped in special pointer types, -/// which currently include [`PinMut`] and [`PinBox`]. -/// -/// The way they work is by implementing [`DerefMut`] for all types that implement Unpin, -/// but only [`Deref`] otherwise. -/// -/// 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`]. +/// This trait is automatically implemented for almost every type. /// /// [`PinMut`]: ../mem/struct.PinMut.html -/// [`PinBox`]: ../../alloc/boxed/struct.PinBox.html -/// [`DerefMut`]: ../ops/trait.DerefMut.html -/// [`Deref`]: ../ops/trait.Deref.html /// [`swap`]: ../mem/fn.swap.html -/// -/// # Examples -/// -/// ```rust -/// #![feature(pin)] -/// -/// use std::boxed::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 auto trait Unpin {} |
