|
182 | 182 | //! is entirely up to the author of any given type. For many types, both answers are reasonable
|
183 | 183 | //! (e.g., there could be a version of `Vec` with structural pinning and another
|
184 | 184 | //! version where the contents remain movable even when the `Vec` is pinned).
|
185 |
| -//! If pinning is not structural, the wrapper can `impl<T> Unpin for Wrapper<T>`. |
186 |
| -//! If pinning is structural, the wrapper type can offer pinning projections. |
| 185 | +//! If the type should have pinning projections, pinning must be structural. |
187 | 186 | //! However, structural pinning comes with a few extra requirements:
|
188 | 187 | //!
|
189 |
| -//! 1. The wrapper must only be [`Unpin`] if all the fields one can project to are |
190 |
| -//! `Unpin`. This is the default, but `Unpin` is a safe trait, so as the author of |
191 |
| -//! the wrapper it is your responsibility *not* to add something like |
192 |
| -//! `impl<T> Unpin for Wrapper<T>`. (Notice that adding a projection operation |
193 |
| -//! requires unsafe code, so the fact that `Unpin` is a safe trait does not break |
194 |
| -//! the principle that you only have to worry about any of this if you use `unsafe`.) |
195 |
| -//! 2. The destructor of the wrapper must not move out of its argument. This is the exact |
196 |
| -//! point that was raised in the [previous section][drop-impl]: `drop` takes `&mut self`, |
197 |
| -//! but the wrapper (and hence its fields) might have been pinned before. |
198 |
| -//! You have to guarantee that you do not move a field inside your `Drop` implementation. |
199 |
| -//! In particular, as explained previously, this means that your wrapper type must *not* |
200 |
| -//! be `#[repr(packed)]`. |
201 |
| -//! 3. You must make sure that you uphold the [`Drop` guarantee][drop-guarantee]: |
202 |
| -//! once your wrapper is pinned, the memory that contains the |
203 |
| -//! content is not overwritten or deallocated without calling the content's destructors. |
204 |
| -//! This can be tricky, as witnessed by `VecDeque`: the destructor of `VecDeque` can fail |
205 |
| -//! to call `drop` on all elements if one of the destructors panics. This violates the |
206 |
| -//! `Drop` guarantee, because it can lead to elements being deallocated without |
207 |
| -//! their destructor being called. (`VecDeque` has no pinning projections, so this |
208 |
| -//! does not cause unsoundness.) |
209 |
| -//! 4. You must not offer any other operations that could lead to data being moved out of |
210 |
| -//! the fields when your type is pinned. This is usually not a concern, but can become |
211 |
| -//! tricky when interior mutability is involved. For example, imagine if `RefCell` |
212 |
| -//! had a method `fn get_pin_mut(self: Pin<&mut Self>) -> Pin<&mut T>`. |
213 |
| -//! Then we could do the following: |
214 |
| -//! ```compile_fail |
215 |
| -//! fn exploit_ref_cell<T>(rc: Pin<&mut RefCell<T>) { |
216 |
| -//! { let p = rc.as_mut().get_pin_mut(); } // here we get pinned access to the `T` |
217 |
| -//! let rc_shr: &RefCell<T> = rc.into_ref().get_ref(); |
218 |
| -//! let b = rc_shr.borrow_mut(); |
219 |
| -//! let content = &mut *b; // and here we have `&mut T` to the same data |
220 |
| -//! } |
221 |
| -//! ``` |
222 |
| -//! This is catastrophic, it means we can first pin the content of the `RefCell` |
223 |
| -//! (using `RefCell::get_pin_mut`) and then move that content using the mutable |
224 |
| -//! reference we got later. |
| 188 | +//! 1. The wrapper must only be [`Unpin`] if all the fields one can project to are |
| 189 | +//! `Unpin`. This is the default, but `Unpin` is a safe trait, so as the author of |
| 190 | +//! the wrapper it is your responsibility *not* to add something like |
| 191 | +//! `impl<T> Unpin for Wrapper<T>`. (Notice that adding a projection operation |
| 192 | +//! requires unsafe code, so the fact that `Unpin` is a safe trait does not break |
| 193 | +//! the principle that you only have to worry about any of this if you use `unsafe`.) |
| 194 | +//! 2. The destructor of the wrapper must not move out of its argument. This is the exact |
| 195 | +//! point that was raised in the [previous section][drop-impl]: `drop` takes `&mut self`, |
| 196 | +//! but the wrapper (and hence its fields) might have been pinned before. |
| 197 | +//! You have to guarantee that you do not move a field inside your `Drop` implementation. |
| 198 | +//! In particular, as explained previously, this means that your wrapper type must *not* |
| 199 | +//! be `#[repr(packed)]`. |
| 200 | +//! 3. You must make sure that you uphold the [`Drop` guarantee][drop-guarantee]: |
| 201 | +//! once your wrapper is pinned, the memory that contains the |
| 202 | +//! content is not overwritten or deallocated without calling the content's destructors. |
| 203 | +//! This can be tricky, as witnessed by `VecDeque`: the destructor of `VecDeque` can fail |
| 204 | +//! to call `drop` on all elements if one of the destructors panics. This violates the |
| 205 | +//! `Drop` guarantee, because it can lead to elements being deallocated without |
| 206 | +//! their destructor being called. (`VecDeque` has no pinning projections, so this |
| 207 | +//! does not cause unsoundness.) |
| 208 | +//! 4. You must not offer any other operations that could lead to data being moved out of |
| 209 | +//! the fields when your type is pinned. For example, if the wrapper contains an |
| 210 | +//! `Option<T>` and there is an operation such as `fn(Pin<&mut Wrapper<T>>) -> Option<T>`, |
| 211 | +//! that operation can be used to move a `T` out of a pinned `Wrapper` -- that means |
| 212 | +//! pinning cannot be structural. |
| 213 | +//! |
| 214 | +//! For a more complex example of moving data out of a pinnd type, imagine if `RefCell` |
| 215 | +//! had a method `fn get_pin_mut(self: Pin<&mut Self>) -> Pin<&mut T>`. |
| 216 | +//! Then we could do the following: |
| 217 | +//! ```compile_fail |
| 218 | +//! fn exploit_ref_cell<T>(rc: Pin<&mut RefCell<T>) { |
| 219 | +//! { let p = rc.as_mut().get_pin_mut(); } // here we get pinned access to the `T` |
| 220 | +//! let rc_shr: &RefCell<T> = rc.into_ref().get_ref(); |
| 221 | +//! let b = rc_shr.borrow_mut(); |
| 222 | +//! let content = &mut *b; // and here we have `&mut T` to the same data |
| 223 | +//! } |
| 224 | +//! ``` |
| 225 | +//! This is catastrophic, it means we can first pin the content of the `RefCell` |
| 226 | +//! (using `RefCell::get_pin_mut`) and then move that content using the mutable |
| 227 | +//! reference we got later. |
225 | 228 | //!
|
226 | 229 | //! On the other hand, if you decide *not* to offer any pinning projections, you
|
227 | 230 | //! do not have to do anything. If your type also does not do any pinning itself,
|
|
0 commit comments