Skip to content

Commit f6bcb91

Browse files
committed
std: refactor explanation of NonNull
Signed-off-by: xizheyin <xizheyin@smail.nju.edu.cn>
1 parent 91fad92 commit f6bcb91

File tree

1 file changed

+13
-26
lines changed

1 file changed

+13
-26
lines changed

library/core/src/ptr/non_null.rs

Lines changed: 13 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -11,36 +11,23 @@ use crate::{fmt, hash, intrinsics, mem, ptr};
1111

1212
/// `*mut T` but non-zero and [covariant].
1313
///
14-
/// This is often the correct thing to use when building data structures using
15-
/// raw pointers, but is ultimately more dangerous to use because of its additional
16-
/// properties. If you're not sure if you should use `NonNull<T>`, just use `*mut T`!
14+
/// `NonNull<T>` is a non-null raw pointer, commonly used for building data structures with raw pointers.
15+
/// It is **covariant** over `T`, which is the correct choice for most safe abstractions (such as `Box`, `Rc`, `Arc`, `Vec`, etc).
1716
///
18-
/// Unlike `*mut T`, the pointer must always be non-null, even if the pointer
19-
/// is never dereferenced. This is so that enums may use this forbidden value
20-
/// as a discriminant -- `Option<NonNull<T>>` has the same size as `*mut T`.
21-
/// However the pointer may still dangle if it isn't dereferenced.
17+
/// If you need **invariance** (for example, when implementing types like `Cell<T>`), you can add a marker field to your type:
2218
///
23-
/// Unlike `*mut T`, `NonNull<T>` was chosen to be covariant over `T`. This makes it
24-
/// possible to use `NonNull<T>` when building covariant types, but introduces the
25-
/// risk of unsoundness if used in a type that shouldn't actually be covariant.
26-
/// (The opposite choice was made for `*mut T` even though technically the unsoundness
27-
/// could only be caused by calling unsafe functions.)
28-
///
29-
/// Covariance is correct for most safe abstractions, such as `Box`, `Rc`, `Arc`, `Vec`,
30-
/// and `LinkedList`. This is the case because they provide a public API that follows the
31-
/// normal shared XOR mutable rules of Rust.
19+
/// ```rust
20+
/// use std::marker::PhantomData;
21+
/// use std::cell::Cell;
22+
/// use std::ptr::NonNull;
3223
///
33-
/// If your type cannot safely be covariant, you must ensure it contains some
34-
/// additional field to provide invariance. Often this field will be a [`PhantomData`]
35-
/// type like `PhantomData<Cell<T>>` or `PhantomData<&'a mut T>`.
24+
/// struct MyCell<T> {
25+
/// ptr: NonNull<T>,
26+
/// _invariant: PhantomData<Cell<T>>,
27+
/// }
28+
/// ```
3629
///
37-
/// Notice that `NonNull<T>` has a `From` instance for `&T`. However, this does
38-
/// not change the fact that mutating through a (pointer derived from a) shared
39-
/// reference is undefined behavior unless the mutation happens inside an
40-
/// [`UnsafeCell<T>`]. The same goes for creating a mutable reference from a shared
41-
/// reference. When using this `From` instance without an `UnsafeCell<T>`,
42-
/// it is your responsibility to ensure that `as_mut` is never called, and `as_ptr`
43-
/// is never used for mutation.
30+
/// In most cases, you should use `NonNull<T>` when you want a non-null pointer. If you are unsure, using a raw pointer (`*mut T`) is also fine.
4431
///
4532
/// # Representation
4633
///

0 commit comments

Comments
 (0)