diff --git a/src/lib.rs b/src/lib.rs index d8b5405..c0edca8 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -292,6 +292,39 @@ where } } + /// Get a reference to an array from a slice, if the slice is exactly the size of the array. + /// + /// Returns `None` if the slice's length is not exactly equal to the array size. + #[inline] + #[must_use] + pub const fn slice_as_array(slice: &[T]) -> Option<&Self> { + if slice.len() == U::USIZE { + // SAFETY: `Self` is ensured to be layout-identical to `[T; U::USIZE]`, and immediately + // above we validated that `slice` is also layout-identical to `[T; U::USIZE]`, + // therefore the cast is valid. + unsafe { Some(&*slice.as_ptr().cast()) } + } else { + None + } + } + + /// Get a mutable reference to an array from a slice, if the slice is exactly the size of the + /// array. + /// + /// Returns `None` if the slice's length is not exactly equal to the array size. + #[inline] + #[must_use] + pub const fn slice_as_mut_array(slice: &mut [T]) -> Option<&mut Self> { + if slice.len() == U::USIZE { + // SAFETY: `Self` is ensured to be layout-identical to `[T; U::USIZE]`, and immediately + // above we validated that `slice` is also layout-identical to `[T; U::USIZE]`, + // therefore the cast is valid. + unsafe { Some(&mut *slice.as_mut_ptr().cast()) } + } else { + None + } + } + /// Splits the shared slice into a slice of `U`-element arrays, starting at the beginning /// of the slice, and a remainder slice with length strictly less than `U`. /// @@ -883,6 +916,38 @@ unsafe impl Send for Array where T: Send {} /// also be `Sync`. unsafe impl Sync for Array where T: Sync {} +impl<'a, T, U> TryFrom<&'a [T]> for &'a Array +where + U: ArraySize, +{ + type Error = TryFromSliceError; + + #[inline] + fn try_from(slice: &'a [T]) -> Result { + check_slice_length::(slice)?; + + // SAFETY: `Array` is a `repr(transparent)` newtype for a core + // array with length checked above. + Ok(unsafe { &*slice.as_ptr().cast() }) + } +} + +impl<'a, T, U> TryFrom<&'a mut [T]> for &'a mut Array +where + U: ArraySize, +{ + type Error = TryFromSliceError; + + #[inline] + fn try_from(slice: &'a mut [T]) -> Result { + check_slice_length::(slice)?; + + // SAFETY: `Array` is a `repr(transparent)` newtype for a core + // array with length checked above. + Ok(unsafe { &mut *slice.as_mut_ptr().cast() }) + } +} + impl<'a, T, U> TryFrom<&'a [T]> for Array where Self: Clone, @@ -952,38 +1017,6 @@ where } } -impl<'a, T, U> TryFrom<&'a [T]> for &'a Array -where - U: ArraySize, -{ - type Error = TryFromSliceError; - - #[inline] - fn try_from(slice: &'a [T]) -> Result { - check_slice_length::(slice)?; - - // SAFETY: `Array` is a `repr(transparent)` newtype for a core - // array with length checked above. - Ok(unsafe { &*slice.as_ptr().cast() }) - } -} - -impl<'a, T, U> TryFrom<&'a mut [T]> for &'a mut Array -where - U: ArraySize, -{ - type Error = TryFromSliceError; - - #[inline] - fn try_from(slice: &'a mut [T]) -> Result { - check_slice_length::(slice)?; - - // SAFETY: `Array` is a `repr(transparent)` newtype for a core - // array with length checked above. - Ok(unsafe { &mut *slice.as_mut_ptr().cast() }) - } -} - // Deprecated legacy methods to ease migrations from `generic-array` impl Array where diff --git a/tests/mod.rs b/tests/mod.rs index caec665..7dde1e4 100644 --- a/tests/mod.rs +++ b/tests/mod.rs @@ -10,7 +10,7 @@ const EXAMPLE_SLICE: &[u8] = &[1, 2, 3, 4, 5, 6]; const _FOO: ArrayN = Array([1, 2, 3, 4]); #[test] -fn tryfrom_slice_for_array() { +fn tryfrom_slice_for_clonable_array() { assert!(Array::::try_from(EXAMPLE_SLICE).is_err()); assert!(Array::::try_from(EXAMPLE_SLICE).is_err()); @@ -31,6 +31,24 @@ fn tryfrom_slice_for_array_ref() { assert!(<&Array::>::try_from(EXAMPLE_SLICE).is_err()); } +#[test] +fn slice_as_array() { + type A = Array; + assert_eq!(A::slice_as_array(&[]), None); + assert_eq!(A::slice_as_array(&[1]), None); + assert_eq!(A::slice_as_array(&[1, 2]), Some(&Array([1, 2]))); + assert_eq!(A::slice_as_array(&[1, 2, 3]), None); +} + +#[test] +fn slice_as_mut_array() { + type A = Array; + assert_eq!(A::slice_as_mut_array(&mut []), None); + assert_eq!(A::slice_as_mut_array(&mut [1]), None); + assert_eq!(A::slice_as_mut_array(&mut [1, 2]), Some(&mut Array([1, 2]))); + assert_eq!(A::slice_as_mut_array(&mut [1, 2, 3]), None); +} + #[test] fn concat() { let prefix = Array::::try_from(&EXAMPLE_SLICE[..2]).unwrap();