Skip to content

Commit 7c39c79

Browse files
committed
Start converting Vec example to stable Rust - use NonNull instead of Unique
1 parent bfe1ab9 commit 7c39c79

File tree

1 file changed

+7
-49
lines changed

1 file changed

+7
-49
lines changed

src/vec-layout.md

Lines changed: 7 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -29,66 +29,24 @@ so we'd like to not use it if possible, though.
2929

3030
As a recap, Unique is a wrapper around a raw pointer that declares that:
3131

32-
* We are variant over `T`
32+
* We are covariant over `T`
3333
* We may own a value of type `T` (for drop check)
3434
* We are Send/Sync if `T` is Send/Sync
3535
* Our pointer is never null (so `Option<Vec<T>>` is null-pointer-optimized)
3636

37-
We can implement all of the above requirements except for the last
38-
one in stable Rust:
37+
We can implement all of the above requirements in stable Rust. To do this, instead of using `Unique<T>` we will use [`NonNull<T>`](https://doc.rust-lang.org/stable/std/ptr/struct.NonNull.html), another wrapper around a raw pointer, which gives us two of the above properties, namely it is covariant over `T` and is declared to never be null. By
38+
adding a `PhantomData<T>` (for drop check) and implementing Send/Sync if `T` is, we then get the same results as if we had used `Unique<T>`:
3939

4040
```rust
41-
use std::marker::PhantomData;
42-
use std::ops::Deref;
43-
use std::mem;
44-
45-
struct Unique<T> {
46-
ptr: *const T, // *const for variance
47-
_marker: PhantomData<T>, // For the drop checker
48-
}
49-
50-
// Deriving Send and Sync is safe because we are the Unique owners
51-
// of this data. It's like Unique<T> is "just" T.
52-
unsafe impl<T: Send> Send for Unique<T> {}
53-
unsafe impl<T: Sync> Sync for Unique<T> {}
54-
55-
impl<T> Unique<T> {
56-
pub fn new(ptr: *mut T) -> Self {
57-
Unique { ptr: ptr, _marker: PhantomData }
58-
}
59-
60-
pub fn as_ptr(&self) -> *mut T {
61-
self.ptr as *mut T
62-
}
63-
}
64-
65-
# fn main() {}
66-
```
67-
68-
Unfortunately the mechanism for stating that your value is non-zero is
69-
unstable and unlikely to be stabilized soon. As such we're just going to
70-
take the hit and use std's Unique:
71-
72-
73-
```rust
74-
#![feature(ptr_internals)]
75-
76-
use std::ptr::{Unique, self};
77-
7841
pub struct Vec<T> {
79-
ptr: Unique<T>,
42+
ptr: NonNull<T>,
8043
cap: usize,
8144
len: usize,
45+
_marker: PhantomData<T>,
8246
}
8347

84-
# fn main() {}
48+
unsafe impl<T: Send> Send for Vec<T> {}
49+
unsafe impl<T: Sync> Sync for Vec<T> {}
8550
```
8651

87-
If you don't care about the null-pointer optimization, then you can use the
88-
stable code. However we will be designing the rest of the code around enabling
89-
this optimization. It should be noted that `Unique::new` is unsafe to call, because
90-
putting `null` inside of it is Undefined Behavior. Our stable Unique doesn't
91-
need `new` to be unsafe because it doesn't make any interesting guarantees about
92-
its contents.
93-
9452
[ownership]: ownership.html

0 commit comments

Comments
 (0)