mirror of https://github.com/rust-lang/nomicon
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
61 lines
2.0 KiB
61 lines
2.0 KiB
9 years ago
|
# Layout
|
||
10 years ago
|
|
||
10 years ago
|
First off, we need to come up with the struct layout. A Vec has three parts:
|
||
|
a pointer to the allocation, the size of the allocation, and the number of
|
||
|
elements that have been initialized.
|
||
|
|
||
|
Naively, this means we just want this design:
|
||
10 years ago
|
|
||
5 years ago
|
```rust,ignore
|
||
10 years ago
|
pub struct Vec<T> {
|
||
10 years ago
|
ptr: *mut T,
|
||
|
cap: usize,
|
||
|
len: usize,
|
||
|
}
|
||
|
```
|
||
|
|
||
10 years ago
|
And indeed this would compile. Unfortunately, it would be incorrect. First, the
|
||
|
compiler will give us too strict variance. So a `&Vec<&'static str>`
|
||
10 years ago
|
couldn't be used where an `&Vec<&'a str>` was expected. More importantly, it
|
||
10 years ago
|
will give incorrect ownership information to the drop checker, as it will
|
||
|
conservatively assume we don't own any values of type `T`. See [the chapter
|
||
|
on ownership and lifetimes][ownership] for all the details on variance and
|
||
|
drop check.
|
||
10 years ago
|
|
||
4 years ago
|
As we saw in the ownership chapter, the standard library uses `Unique<T>` in place of
|
||
|
`*mut T` when it has a raw pointer to an allocation that it owns. Unique is unstable,
|
||
10 years ago
|
so we'd like to not use it if possible, though.
|
||
|
|
||
|
As a recap, Unique is a wrapper around a raw pointer that declares that:
|
||
|
|
||
4 years ago
|
* We are covariant over `T`
|
||
10 years ago
|
* We may own a value of type `T` (for drop check)
|
||
|
* We are Send/Sync if `T` is Send/Sync
|
||
|
* Our pointer is never null (so `Option<Vec<T>>` is null-pointer-optimized)
|
||
|
|
||
4 years ago
|
We can implement all of the above requirements in stable Rust. To do this, instead
|
||
|
of using `Unique<T>` we will use [`NonNull<T>`][NonNull], 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 adding a `PhantomData<T>` (for drop
|
||
|
check) and implementing Send/Sync if `T` is, we get the same results as using
|
||
|
`Unique<T>`:
|
||
10 years ago
|
|
||
4 years ago
|
```rust
|
||
|
use std::ptr::NonNull;
|
||
10 years ago
|
use std::marker::PhantomData;
|
||
|
|
||
10 years ago
|
pub struct Vec<T> {
|
||
4 years ago
|
ptr: NonNull<T>,
|
||
10 years ago
|
cap: usize,
|
||
|
len: usize,
|
||
4 years ago
|
_marker: PhantomData<T>,
|
||
10 years ago
|
}
|
||
|
|
||
4 years ago
|
unsafe impl<T: Send> Send for Vec<T> {}
|
||
|
unsafe impl<T: Sync> Sync for Vec<T> {}
|
||
|
# fn main() {}
|
||
|
```
|
||
10 years ago
|
|
||
10 years ago
|
[ownership]: ownership.html
|
||
4 years ago
|
[NonNull]: ../std/ptr/struct.NonNull.html
|