Skip to content

Commit cf96416

Browse files
committed
hybrid-array: make ArraySize an unsafe trait
It's used when checking the lengths of slices match an array size prior to using a pointer cast to convert types. If someone were to make their own `typenum::Unsigned` type and impl `ArraySize` for it with an `ArrayType` whose size does not match `Unsigned::USIZE`, that would be UB. Really `ArraySize` is not intended for downstream crates to impl anyway, but making it an `unsafe trait` at least captures the UB potential. Additionally this adds more debug checks to `check_slice_length` to ensure that if there is a length mismatch, it's at least caught in debug builds.
1 parent 14b1e13 commit cf96416

1 file changed

Lines changed: 19 additions & 3 deletions

File tree

hybrid-array/src/lib.rs

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -304,10 +304,16 @@ where
304304
}
305305

306306
/// Generate a [`TryFromSliceError`] if the slice doesn't match the given length.
307-
fn check_slice_length<T, U: Unsigned>(slice: &[T]) -> Result<(), TryFromSliceError> {
307+
#[cfg_attr(debug_assertions, allow(clippy::panic_in_result_fn))]
308+
fn check_slice_length<T, U: ArraySize>(slice: &[T]) -> Result<(), TryFromSliceError> {
309+
debug_assert_eq!(Array::<(), U>::default().len(), U::USIZE);
310+
308311
if slice.len() != U::USIZE {
309312
// Hack: `TryFromSliceError` lacks a public constructor
310313
<&[T; 1]>::try_from([].as_slice())?;
314+
315+
#[cfg(debug_assertions)]
316+
unreachable!();
311317
}
312318

313319
Ok(())
@@ -400,7 +406,17 @@ impl<T, const N: usize> ArrayExt<T> for [T; N] {
400406

401407
/// Trait which associates a [`usize`] size and `ArrayType` with a
402408
/// `typenum`-provided [`Unsigned`] integer.
403-
pub trait ArraySize: Unsigned {
409+
///
410+
/// # Safety
411+
///
412+
/// `ArrayType` MUST be an array with a number of elements exactly equal to
413+
/// [`Unsigned::USIZE`].
414+
///
415+
/// Failure to so will cause undefined behavior.
416+
///
417+
/// NOTE: do not implement this trait yourself. It is implemented for types in
418+
/// [`typenum::consts`].
419+
pub unsafe trait ArraySize: Unsigned {
404420
/// Array type which corresponds to this size.
405421
type ArrayType<T>: AsRef<[T]> + AsMut<[T]> + IntoArray<T> + ArrayExt<T>;
406422
}
@@ -457,7 +473,7 @@ macro_rules! impl_array_size {
457473
}
458474
}
459475

460-
impl ArraySize for typenum::$ty {
476+
unsafe impl ArraySize for typenum::$ty {
461477
type ArrayType<T> = [T; $len];
462478
}
463479

0 commit comments

Comments
 (0)