Skip to content

Commit 36cf96b

Browse files
committed
Make align_to an inherent method
1 parent e49877c commit 36cf96b

File tree

1 file changed

+27
-25
lines changed

1 file changed

+27
-25
lines changed

text/0000-is-aligned-intrinsic.md

+27-25
Original file line numberDiff line numberDiff line change
@@ -82,52 +82,54 @@ Usually one should pass in the result of an `align_of` call.
8282
Add a new method `align_offset` to `*const T` and `*mut T`, which forwards to the
8383
`align_offset` intrinsic.
8484

85-
Add two new functions `align_to` and `align_to_mut` to `core::slice` and `std::slice`
86-
with the following signature:
85+
Add two new methods `align_to` and `align_to_mut` to the slice type.
8786

8887
```rust
89-
unsafe fn align_to<T, U>(&[U]) -> (&[U], &[T], &[U]) { /**/ }
90-
unsafe fn align_to_mut<T, U>(&mut [U]) -> (&mut [U], &mut [T], &mut [U]) { /**/ }
88+
impl<T> [T] {
89+
/* ... other methods ... */
90+
unsafe fn align_to<U>(&self) -> (&[T], &[U], &[T]) { /**/ }
91+
unsafe fn align_to_mut<U>(&mut self) -> (&mut [T], &mut [U], &mut [T]) { /**/ }
92+
}
9193
```
9294

9395
`align_to` can be implemented as
9496

9597
```rust
96-
unsafe fn align_to<T, U>(slice: &[U]) -> (&[U], &[T], &[U]) {
98+
unsafe fn align_to<U>(&self) -> (&[T], &[U], &[T]) {
9799
use core::mem::{size_of, align_of};
98-
assert!(size_of::<T>() != 0 && size_of::<U>() != 0, "don't use `align_to` with zsts");
99-
if size_of::<T>() % size_of::<U>() == 0 {
100-
let align = align_of::<T>();
101-
let size = size_of::<T>();
102-
let source_size = size_of::<U>();
100+
assert!(size_of::<U>() != 0 && size_of::<T>() != 0, "don't use `align_to` with zsts");
101+
if size_of::<U>() % size_of::<T>() == 0 {
102+
let align = align_of::<U>();
103+
let size = size_of::<U>();
104+
let source_size = size_of::<T>();
103105
// number of bytes that need to be skipped until the pointer is aligned
104-
let offset = slice.as_ptr().align_offset(align);
105-
// if `align_of::<T>() <= align_of::<U>()`, or if pointer is accidentally aligned, then `offset == 0`
106+
let offset = self.as_ptr().align_offset(align);
107+
// if `align_of::<U>() <= align_of::<T>()`, or if pointer is accidentally aligned, then `offset == 0`
106108
//
107-
// due to `size_of::<T>() % size_of::<U>() == 0`,
108-
// the fact that `size_of::<U>() > align_of::<U>()`,
109-
// and the fact that `align_of::<T>() > align_of::<U>()` if `offset != 0` we know
109+
// due to `size_of::<U>() % size_of::<T>() == 0`,
110+
// the fact that `size_of::<T>() > align_of::<T>()`,
111+
// and the fact that `align_of::<U>() > align_of::<T>()` if `offset != 0` we know
110112
// that `offset % source_size == 0`
111113
let head_count = offset / source_size;
112-
let split_position = core::cmp::max(slice.len(), head_count);
113-
let (head, tail) = slice.split_at(split_position);
114+
let split_position = core::cmp::max(self.len(), head_count);
115+
let (head, tail) = self.split_at(split_position);
114116
// might be zero if not enough elements
115117
let mid_count = tail.len() * source_size / size;
116-
let mid = core::slice::from_raw_parts::<T>(tail.as_ptr() as *const _, mid_count);
117-
let tail = &tail[mid_count * size_of::<T>()..];
118+
let mid = core::slice::from_raw_parts::<U>(tail.as_ptr() as *const _, mid_count);
119+
let tail = &tail[mid_count * size_of::<U>()..];
118120
(head, mid, tail)
119121
} else {
120-
// can't properly fit a T into a sequence of `U`
121-
// FIXME: use GCD(size_of::<T>(), size_of::<U>()) as minimum `mid` size
122-
(slice, &[], &[])
122+
// can't properly fit a U into a sequence of `T`
123+
// FIXME: use GCD(size_of::<U>(), size_of::<T>()) as minimum `mid` size
124+
(self, &[], &[])
123125
}
124126
}
125127
```
126128

127129
on all current platforms. `align_to_mut` is expanded accordingly.
128130

129131
Users of the functions must process all the returned slices and
130-
cannot rely on any behaviour except that the `&[T]`'s elements are correctly
132+
cannot rely on any behaviour except that the `&[U]`'s elements are correctly
131133
aligned and that all bytes of the original slice are present in the resulting
132134
three slices.
133135

@@ -235,7 +237,7 @@ With the `align_to` function this could be written as
235237
let len = text.len();
236238
let ptr = text.as_ptr();
237239

238-
let (head, mid, tail) = std::slice::align_to::<(usize, usize), _>(text);
240+
let (head, mid, tail) = text.align_to::<(usize, usize)>();
239241

240242
// search up to an aligned boundary
241243
if let Some(index) = head.iter().position(|elt| *elt == x) {
@@ -266,7 +268,7 @@ tail.iter().position(|elt| *elt == x).map(|i| head.len() + mid.len() + i)
266268
A lint could be added to `clippy` which detects hand-written alignment checks and
267269
suggests to use the `align_to` function instead.
268270

269-
The `std::mem::align` function's documentation should point to `std::slice::align_to`
271+
The `std::mem::align` function's documentation should point to `[T]::align_to`
270272
in order to increase the visibility of the function. The documentation of
271273
`std::mem::align` should note that it is unidiomatic to manually align pointers,
272274
since that might not be supported on all platforms and is prone to implementation

0 commit comments

Comments
 (0)