Skip to content

Commit c50c194

Browse files
committed
remove duplicate of a sentence
1 parent 5634491 commit c50c194

File tree

1 file changed

+13
-12
lines changed

1 file changed

+13
-12
lines changed

src/vec/vec-zsts.md

Lines changed: 13 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
11
# Handling Zero-Sized Types
22

33
It's time. We're going to fight the specter that is zero-sized types. Safe Rust
4-
*never* needs to care about this, but Vec is very intensive on raw pointers and
4+
_never_ needs to care about this, but Vec is very intensive on raw pointers and
55
raw allocations, which are exactly the two things that care about
66
zero-sized types. We need to be careful of two things:
77

8-
* The raw allocator API has undefined behavior if you pass in 0 for an
8+
- The raw allocator API has undefined behavior if you pass in 0 for an
99
allocation size.
10-
* raw pointer offsets are no-ops for zero-sized types, which will break our
10+
- raw pointer offsets are no-ops for zero-sized types, which will break our
1111
C-style pointer iterator.
1212

1313
Thankfully we abstracted out pointer-iterators and allocating handling into
@@ -30,6 +30,7 @@ Due to our current architecture, all this means is writing 3 guards, one in each
3030
method of `RawVec`.
3131

3232
<!-- ignore: simplified code -->
33+
3334
```rust,ignore
3435
impl<T> RawVec<T> {
3536
fn new() -> Self {
@@ -108,6 +109,7 @@ nothing. The current solution to this is to cast the pointers to integers,
108109
increment, and then cast them back:
109110

110111
<!-- ignore: simplified code -->
112+
111113
```rust,ignore
112114
impl<T> RawValIter<T> {
113115
unsafe fn new(slice: &[T]) -> Self {
@@ -126,12 +128,13 @@ impl<T> RawValIter<T> {
126128
```
127129

128130
Now we have a different bug. Instead of our iterators not running at all, our
129-
iterators now run *forever*. We need to do the same trick in our iterator impls.
131+
iterators now run _forever_. We need to do the same trick in our iterator impls.
130132
Also, our size_hint computation code will divide by 0 for ZSTs. Since we'll
131133
basically be treating the two pointers as if they point to bytes, we'll just
132134
map size 0 to divide by 1. Here's what `next` will be:
133135

134136
<!-- ignore: simplified code -->
137+
135138
```rust,ignore
136139
fn next(&mut self) -> Option<T> {
137140
if self.start == self.end {
@@ -152,20 +155,21 @@ fn next(&mut self) -> Option<T> {
152155

153156
Do you see the "bug"? No one else did! The original author only noticed the
154157
problem when linking to this page years later. This code is kind of dubious
155-
because abusing the iterator pointers to be *counters* makes them unaligned!
156-
Our *one job* when using ZSTs is to keep pointers aligned! *forehead slap*
158+
because abusing the iterator pointers to be _counters_ makes them unaligned!
159+
Our _one job_ when using ZSTs is to keep pointers aligned! _forehead slap_
157160

158161
Raw pointers don't need to be aligned at all times, so the basic trick of
159-
using pointers as counters is *fine*, but they *should* definitely be aligned
160-
when passed to `ptr::read`! This is *possibly* needless pedantry
161-
because `ptr::read` is a noop for a ZST, but let's be a *little* more
162+
using pointers as counters is _fine_, but they _should_ definitely be aligned
163+
when passed to `ptr::read`! This is _possibly_ needless pedantry
164+
because `ptr::read` is a noop for a ZST, but let's be a _little_ more
162165
responsible and read from `NonNull::dangling` on the ZST path.
163166

164167
(Alternatively you could call `read_unaligned` on the ZST path. Either is fine,
165168
because either way we're making up a value from nothing and it all compiles
166169
to doing nothing.)
167170

168171
<!-- ignore: simplified code -->
172+
169173
```rust,ignore
170174
impl<T> Iterator for RawValIter<T> {
171175
type Item = T;
@@ -215,8 +219,6 @@ impl<T> DoubleEndedIterator for RawValIter<T> {
215219

216220
And that's it. Iteration works!
217221

218-
And that's it. Iteration works!
219-
220222
One last thing that we need to take into account, is that now when our vec gets dropped it deallocates the memory that was allocated during the time our vec was alive. With ZSTs we did not allocate any memory, and infact we never do. So right now we have unsoundness in our code where we still try deallocate a `NonNull::dangling()` ptr that we use to simulate the ZST in our vec, This means that we would cause an undefined behaviour if we try to deallocate something that we never allocated (obviously and for the right reasons). Lets fix tha, in our raw_vec we are going to tweak our Drop trait and check that we deallocate only types that are sized.
221223

222224
```rust,ignore
@@ -232,4 +234,3 @@ impl<T> Drop for RawVec<T> {
232234
}
233235
}
234236
```
235-

0 commit comments

Comments
 (0)