|
| 1 | +# Layout of Rust array types and slices |
| 2 | + |
| 3 | +## Layout of Rust array types |
| 4 | + |
| 5 | +Array types, `[T; N]`, store `N` values of type `T` with a constant _stride_. |
| 6 | +Here, _stride_ is the distance between each pair of consecutive values within |
| 7 | +the array. |
| 8 | + |
| 9 | +The _offset_ of the first array element is `0`, that is, a pointer to the array |
| 10 | +and a pointer to its first element both point to the same memory address. |
| 11 | + |
| 12 | +The _alignment_ of array types is greater or equal to the alignment of its |
| 13 | +element type. If the element type is `repr(C)` the layout of the array is |
| 14 | +guaranteed to be the same as the layout of a C array with the same element type. |
| 15 | + |
| 16 | +> **Note**: the type of array arguments in C function signatures, e.g., `void |
| 17 | +> foo(T x[N])`, decays to a pointer. That is, these functions do not take arrays |
| 18 | +> as an arguments, they take a pointer to the first element of the array |
| 19 | +> instead. Array types are therefore _improper C types_ (not C FFI safe) in Rust |
| 20 | +> foreign function declarations, e.g., `extern { fn foo(x: [T; N]) -> [U; M]; |
| 21 | +> }`. Pointers to arrays are fine: `extern { fn foo(x: *const [T; N]) -> *const |
| 22 | +> [U; M]; }`, and `struct`s and `union`s containing arrays are also fine. |
| 23 | +
|
| 24 | +The _stride_ of the array is constant for all element pairs and it is computed |
| 25 | +as the _size_ of the element type rounded up to the next multiple of the |
| 26 | +_alignment_ of the element type. |
| 27 | + |
| 28 | +### Special case `stride == size` |
| 29 | + |
| 30 | +When the element _size_ is a multiple of the element's _alignment_, then `stride |
| 31 | +== size`, and the elements are laid out contiguously in memory, e.g., `[u8; 4]`. |
| 32 | +In this case, the _size_ of the array can be computed as `size_of::<T>() * N`, |
| 33 | +and a pointer to the `i`-th element of the array can be obtained by offsetting a |
| 34 | +pointer to the first element of the array by `i`[^1]. |
| 35 | + |
| 36 | +> **Note:** In the current Rust implementation, _size_ is always a multiple of |
| 37 | +> the element's _alignment_, and therefore `stride == size` always holds. This |
| 38 | +> is, however, not guaranteed by the [layout of structs and tuples]. |
| 39 | +
|
| 40 | +[^1]: When `stride > size` the pointer needs to be advanced by the array |
| 41 | + _stride_ instead of by the element _size_. |
| 42 | + |
| 43 | +[layout of structs and tuples]: ./structs-and-tuples.md |
| 44 | + |
| 45 | +### Layout compatibility with packed SIMD vectors |
| 46 | + |
| 47 | +The [layout of packed SIMD vector types][Vector] [^2] requires the _size_ and |
| 48 | +_alignment_ of the vector elements to match. That is, types with [packed SIMD |
| 49 | +vector][Vector] layout are layout compatible with arrays having the same element |
| 50 | +type and the same number of elements as the vector. |
| 51 | + |
| 52 | +[^2]: The [packed SIMD vector][Vector] layout is the layout of `repr(simd)` types like [`__m128`]. |
| 53 | + |
| 54 | +[Vector]: packed-simd-vectors.md |
| 55 | +[`__m128`]: https://doc.rust-lang.org/core/arch/x86_64/struct.__m128.html |
| 56 | + |
| 57 | +## Layout of Rust slices |
| 58 | + |
| 59 | +The layout of a slice `[T]` of length `N` is the same as that of a `[T; N]` array. |
| 60 | + |
| 61 | +## Unresolved questions |
| 62 | + |
| 63 | +### Guaranteeing `stride == size` ? |
| 64 | + |
| 65 | +Currently, the [layout of structs and tuples] does not guarantee that the |
| 66 | +element _size_ is a multiple of its _alignment_. For example, consider: |
| 67 | + |
| 68 | +```rust,ignore |
| 69 | +struct A(u16, u8); |
| 70 | +type B = [A; 4]; |
| 71 | +``` |
| 72 | + |
| 73 | +In the current Rust implementation, `A` has an alignment and a size of `4`, and |
| 74 | +`B` has a size of `16`, such that `B` contains four `A`s that are contiguously |
| 75 | +laid in memory. |
| 76 | + |
| 77 | +However, a future Rust implementation could implement a layout optimization that |
| 78 | +reduces the size of `A` to `3`. For the elements of `B` to be properly aligned, |
| 79 | +`B` would need to choose a `stride == 4`, resulting in a `stride > size`. |
| 80 | + |
| 81 | +Guaranteeing `stride >= size` is forward-compatible with such |
| 82 | +layout-optimization proposals: |
| 83 | + |
| 84 | + * [rust-lang/rfcs/1397: Spearate size and stride for types](https://github.com/rust-lang/rfcs/issues/1397) |
| 85 | + * [rust-lang/rust/17027: Collapse trailing padding](https://github.com/rust-lang/rust/issues/17027) |
0 commit comments