diff options
| author | xizheyin <xizheyin@smail.nju.edu.cn> | 2025-06-04 01:39:02 +0800 |
|---|---|---|
| committer | xizheyin <xizheyin@smail.nju.edu.cn> | 2025-06-04 01:39:02 +0800 |
| commit | 871397342c9da1cdcee3c851a2c93b84aa512fba (patch) | |
| tree | 9ea7949e9fb3a628bef3fed7d9ae0facd8645ee5 | |
| parent | 91fad92585b2dafc52a074e502b2a6c1f093ca35 (diff) | |
| download | rust-871397342c9da1cdcee3c851a2c93b84aa512fba.tar.gz rust-871397342c9da1cdcee3c851a2c93b84aa512fba.zip | |
std: simplify `NonNull` variance documentation
Streamlined the explanation of covariance for `NonNull<T>`, focusing on practical usage and reducing scary explanation. Added a concise example for cases where invariance is required, showing how to use `PhantomData<Cell<T>> Signed-off-by: xizheyin <xizheyin@smail.nju.edu.cn>
| -rw-r--r-- | library/core/src/ptr/non_null.rs | 27 |
1 files changed, 16 insertions, 11 deletions
diff --git a/library/core/src/ptr/non_null.rs b/library/core/src/ptr/non_null.rs index 91b8d1bf9a7..f9089ae5239 100644 --- a/library/core/src/ptr/non_null.rs +++ b/library/core/src/ptr/non_null.rs @@ -20,19 +20,24 @@ use crate::{fmt, hash, intrinsics, mem, ptr}; /// as a discriminant -- `Option<NonNull<T>>` has the same size as `*mut T`. /// However the pointer may still dangle if it isn't dereferenced. /// -/// Unlike `*mut T`, `NonNull<T>` was chosen to be covariant over `T`. This makes it -/// possible to use `NonNull<T>` when building covariant types, but introduces the -/// risk of unsoundness if used in a type that shouldn't actually be covariant. -/// (The opposite choice was made for `*mut T` even though technically the unsoundness -/// could only be caused by calling unsafe functions.) +/// Unlike `*mut T`, `NonNull<T>` is covariant over `T`. This is usually the correct +/// choice for most data structures and safe abstractions, such as `Box`, `Rc`, `Arc`, `Vec`, +/// and `LinkedList`. /// -/// Covariance is correct for most safe abstractions, such as `Box`, `Rc`, `Arc`, `Vec`, -/// and `LinkedList`. This is the case because they provide a public API that follows the -/// normal shared XOR mutable rules of Rust. +/// In rare cases, if your type exposes a way to mutate the value of `T` through a `NonNull<T>`, +/// and you need to prevent unsoundness from variance (for example, if `T` could be a reference +/// with a shorter lifetime), you should add a field to make your type invariant, such as +/// `PhantomData<Cell<T>>` or `PhantomData<&'a mut T>`. /// -/// If your type cannot safely be covariant, you must ensure it contains some -/// additional field to provide invariance. Often this field will be a [`PhantomData`] -/// type like `PhantomData<Cell<T>>` or `PhantomData<&'a mut T>`. +/// Example of a type that must be invariant: +/// ```rust +/// use std::cell::Cell; +/// use std::marker::PhantomData; +/// struct Invariant<T> { +/// ptr: std::ptr::NonNull<T>, +/// _invariant: PhantomData<Cell<T>>, +/// } +/// ``` /// /// Notice that `NonNull<T>` has a `From` instance for `&T`. However, this does /// not change the fact that mutating through a (pointer derived from a) shared |
