Skip to content

Commit ae406aa

Browse files
Improve chapter about Vec<T> (#381)
Co-authored-by: Daniel Henry-Mantilla <daniel.henry.mantilla@gmail.com>
1 parent 03fbddb commit ae406aa

File tree

7 files changed

+26
-33
lines changed

7 files changed

+26
-33
lines changed

src/vec/vec-alloc.md

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,6 @@ impl<T> Vec<T> {
2828
ptr: NonNull::dangling(),
2929
len: 0,
3030
cap: 0,
31-
_marker: PhantomData,
3231
}
3332
}
3433
}

src/vec/vec-final.md

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@ use std::ptr::{self, NonNull};
1010
struct RawVec<T> {
1111
ptr: NonNull<T>,
1212
cap: usize,
13-
_marker: PhantomData<T>,
1413
}
1514

1615
unsafe impl<T: Send> Send for RawVec<T> {}
@@ -25,7 +24,6 @@ impl<T> RawVec<T> {
2524
RawVec {
2625
ptr: NonNull::dangling(),
2726
cap: cap,
28-
_marker: PhantomData,
2927
}
3028
}
3129

src/vec/vec-insert-remove.md

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -22,9 +22,11 @@ pub fn insert(&mut self, index: usize, elem: T) {
2222
2323
unsafe {
2424
// ptr::copy(src, dest, len): "copy from src to dest len elems"
25-
ptr::copy(self.ptr.as_ptr().add(index),
26-
self.ptr.as_ptr().add(index + 1),
27-
self.len - index);
25+
ptr::copy(
26+
self.ptr.as_ptr().add(index),
27+
self.ptr.as_ptr().add(index + 1),
28+
self.len - index,
29+
);
2830
ptr::write(self.ptr.as_ptr().add(index), elem);
2931
self.len += 1;
3032
}
@@ -42,9 +44,11 @@ pub fn remove(&mut self, index: usize) -> T {
4244
unsafe {
4345
self.len -= 1;
4446
let result = ptr::read(self.ptr.as_ptr().add(index));
45-
ptr::copy(self.ptr.as_ptr().add(index + 1),
46-
self.ptr.as_ptr().add(index),
47-
self.len - index);
47+
ptr::copy(
48+
self.ptr.as_ptr().add(index + 1),
49+
self.ptr.as_ptr().add(index),
50+
self.len - index,
51+
);
4852
result
4953
}
5054
}

src/vec/vec-into-iter.md

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,6 @@ pub struct IntoIter<T> {
4949
cap: usize,
5050
start: *const T,
5151
end: *const T,
52-
_marker: PhantomData<T>,
5352
}
5453
```
5554

@@ -61,13 +60,13 @@ impl<T> IntoIterator for Vec<T> {
6160
type Item = T;
6261
type IntoIter = IntoIter<T>;
6362
fn into_iter(self) -> IntoIter<T> {
64-
// Can't destructure Vec since it's Drop
65-
let ptr = self.ptr;
66-
let cap = self.cap;
67-
let len = self.len;
68-
6963
// Make sure not to drop Vec since that would free the buffer
70-
mem::forget(self);
64+
let vec = ManuallyDrop::new(self);
65+
66+
// Can't destructure Vec since it's Drop
67+
let ptr = vec.ptr;
68+
let cap = vec.cap;
69+
let len = vec.len;
7170
7271
unsafe {
7372
IntoIter {
@@ -80,7 +79,6 @@ impl<T> IntoIterator for Vec<T> {
8079
} else {
8180
ptr.as_ptr().add(len)
8281
},
83-
_marker: PhantomData,
8482
}
8583
}
8684
}

src/vec/vec-layout.md

Lines changed: 8 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -15,13 +15,10 @@ pub struct Vec<T> {
1515
}
1616
```
1717

18-
And indeed this would compile. Unfortunately, it would be incorrect. First, the
18+
And indeed this would compile. Unfortunately, it would be too strict. The
1919
compiler will give us too strict variance. So a `&Vec<&'static str>`
20-
couldn't be used where an `&Vec<&'a str>` was expected. More importantly, it
21-
will give incorrect ownership information to the drop checker, as it will
22-
conservatively assume we don't own any values of type `T`. See [the chapter
23-
on ownership and lifetimes][ownership] for all the details on variance and
24-
drop check.
20+
couldn't be used where a `&Vec<&'a str>` was expected. See [the chapter
21+
on ownership and lifetimes][ownership] for all the details on variance.
2522

2623
As we saw in the ownership chapter, the standard library uses `Unique<T>` in place of
2724
`*mut T` when it has a raw pointer to an allocation that it owns. Unique is unstable,
@@ -30,16 +27,16 @@ so we'd like to not use it if possible, though.
3027
As a recap, Unique is a wrapper around a raw pointer that declares that:
3128

3229
* We are covariant over `T`
33-
* We may own a value of type `T` (for drop check)
30+
* We may own a value of type `T` (this is not relevant for our example here, but see
31+
[the chapter on PhantomData][phantom-data] on why the real `std::vec::Vec<T>` needs this)
3432
* We are Send/Sync if `T` is Send/Sync
3533
* Our pointer is never null (so `Option<Vec<T>>` is null-pointer-optimized)
3634

3735
We can implement all of the above requirements in stable Rust. To do this, instead
3836
of using `Unique<T>` we will use [`NonNull<T>`][NonNull], another wrapper around a
3937
raw pointer, which gives us two of the above properties, namely it is covariant
40-
over `T` and is declared to never be null. By adding a `PhantomData<T>` (for drop
41-
check) and implementing Send/Sync if `T` is, we get the same results as using
42-
`Unique<T>`:
38+
over `T` and is declared to never be null. By implementing Send/Sync if `T` is,
39+
we get the same results as using `Unique<T>`:
4340

4441
```rust
4542
use std::ptr::NonNull;
@@ -49,7 +46,6 @@ pub struct Vec<T> {
4946
ptr: NonNull<T>,
5047
cap: usize,
5148
len: usize,
52-
_marker: PhantomData<T>,
5349
}
5450

5551
unsafe impl<T: Send> Send for Vec<T> {}
@@ -58,4 +54,5 @@ unsafe impl<T: Sync> Sync for Vec<T> {}
5854
```
5955

6056
[ownership]: ../ownership.html
57+
[phantom-data]: ../phantom-data.md
6158
[NonNull]: ../../std/ptr/struct.NonNull.html

src/vec/vec-raw.md

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,6 @@ allocating, growing, and freeing:
1313
struct RawVec<T> {
1414
ptr: NonNull<T>,
1515
cap: usize,
16-
_marker: PhantomData<T>,
1716
}
1817
1918
unsafe impl<T: Send> Send for RawVec<T> {}
@@ -25,7 +24,6 @@ impl<T> RawVec<T> {
2524
RawVec {
2625
ptr: NonNull::dangling(),
2726
cap: 0,
28-
_marker: PhantomData,
2927
}
3028
}
3129

src/vec/vec-zsts.md

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -33,14 +33,13 @@ method of `RawVec`.
3333
```rust,ignore
3434
impl<T> RawVec<T> {
3535
fn new() -> Self {
36-
// !0 is usize::MAX. This branch should be stripped at compile time.
37-
let cap = if mem::size_of::<T>() == 0 { !0 } else { 0 };
36+
// This branch should be stripped at compile time.
37+
let cap = if mem::size_of::<T>() == 0 { usize::MAX } else { 0 };
3838
3939
// `NonNull::dangling()` doubles as "unallocated" and "zero-sized allocation"
4040
RawVec {
4141
ptr: NonNull::dangling(),
4242
cap: cap,
43-
_marker: PhantomData,
4443
}
4544
}
4645

0 commit comments

Comments
 (0)