Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
97 changes: 65 additions & 32 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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`.
///
Expand Down Expand Up @@ -883,6 +916,38 @@ unsafe impl<T, U: ArraySize> Send for Array<T, U> where T: Send {}
/// also be `Sync`.
unsafe impl<T, U: ArraySize> Sync for Array<T, U> where T: Sync {}

impl<'a, T, U> TryFrom<&'a [T]> for &'a Array<T, U>
where
U: ArraySize,
{
type Error = TryFromSliceError;

#[inline]
fn try_from(slice: &'a [T]) -> Result<Self, TryFromSliceError> {
check_slice_length::<T, U>(slice)?;

// SAFETY: `Array<T, U>` 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<T, U>
where
U: ArraySize,
{
type Error = TryFromSliceError;

#[inline]
fn try_from(slice: &'a mut [T]) -> Result<Self, TryFromSliceError> {
check_slice_length::<T, U>(slice)?;

// SAFETY: `Array<T, U>` 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<T, U>
where
Self: Clone,
Expand Down Expand Up @@ -952,38 +1017,6 @@ where
}
}

impl<'a, T, U> TryFrom<&'a [T]> for &'a Array<T, U>
where
U: ArraySize,
{
type Error = TryFromSliceError;

#[inline]
fn try_from(slice: &'a [T]) -> Result<Self, TryFromSliceError> {
check_slice_length::<T, U>(slice)?;

// SAFETY: `Array<T, U>` 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<T, U>
where
U: ArraySize,
{
type Error = TryFromSliceError;

#[inline]
fn try_from(slice: &'a mut [T]) -> Result<Self, TryFromSliceError> {
check_slice_length::<T, U>(slice)?;

// SAFETY: `Array<T, U>` 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<T, U> Array<T, U>
where
Expand Down
20 changes: 19 additions & 1 deletion tests/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ const EXAMPLE_SLICE: &[u8] = &[1, 2, 3, 4, 5, 6];
const _FOO: ArrayN<u8, 4> = Array([1, 2, 3, 4]);

#[test]
fn tryfrom_slice_for_array() {
fn tryfrom_slice_for_clonable_array() {
assert!(Array::<u8, U0>::try_from(EXAMPLE_SLICE).is_err());
assert!(Array::<u8, U3>::try_from(EXAMPLE_SLICE).is_err());

Expand All @@ -31,6 +31,24 @@ fn tryfrom_slice_for_array_ref() {
assert!(<&Array::<u8, U7>>::try_from(EXAMPLE_SLICE).is_err());
}

#[test]
fn slice_as_array() {
type A = Array<u8, U2>;
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<u8, U2>;
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::<u8, U2>::try_from(&EXAMPLE_SLICE[..2]).unwrap();
Expand Down