| # Layout |
| |
| 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: |
| |
| <!-- ignore: simplified code --> |
| ```rust,ignore |
| pub struct Vec<T> { |
| ptr: *mut T, |
| cap: usize, |
| len: usize, |
| } |
| ``` |
| |
| And indeed this would compile. Unfortunately, it would be too strict. The |
| compiler will give us too strict variance. So a `&Vec<&'static str>` |
| couldn't be used where a `&Vec<&'a str>` was expected. See [the chapter |
| on ownership and lifetimes][ownership] for all the details on variance. |
| |
| 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, |
| 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: |
| |
| * We are covariant over `T` |
| * We may own a value of type `T` (this is not relevant for our example here, but see |
| [the chapter on PhantomData][phantom-data] on why the real `std::vec::Vec<T>` needs this) |
| * We are Send/Sync if `T` is Send/Sync |
| * Our pointer is never null (so `Option<Vec<T>>` is null-pointer-optimized) |
| |
| 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 implementing Send/Sync if `T` is, |
| we get the same results as using `Unique<T>`: |
| |
| ```rust |
| use std::ptr::NonNull; |
| |
| pub struct Vec<T> { |
| ptr: NonNull<T>, |
| cap: usize, |
| len: usize, |
| } |
| |
| unsafe impl<T: Send> Send for Vec<T> {} |
| unsafe impl<T: Sync> Sync for Vec<T> {} |
| # fn main() {} |
| ``` |
| |
| [ownership]: ../ownership.html |
| [phantom-data]: ../phantom-data.md |
| [NonNull]: ../../std/ptr/struct.NonNull.html |