diff --git a/hybrid-array/src/lib.rs b/hybrid-array/src/lib.rs index 41ff4a92..06438399 100644 --- a/hybrid-array/src/lib.rs +++ b/hybrid-array/src/lib.rs @@ -5,7 +5,6 @@ html_logo_url = "https://raw.githubusercontent.com/RustCrypto/meta/master/logo.svg", html_favicon_url = "https://raw.githubusercontent.com/RustCrypto/meta/master/logo.svg" )] -#![forbid(unsafe_code)] #![warn( clippy::cast_lossless, clippy::cast_possible_truncation, @@ -67,6 +66,12 @@ pub trait ArrayOps: /// Create array from Rust's core array type. fn from_core_array(arr: [T; N]) -> Self; + /// Create array reference from reference to Rust's core array type. + fn from_core_array_ref(arr: &[T; N]) -> &Self; + + /// Create mutable array reference from reference to Rust's core array type. + fn from_core_array_mut(arr: &mut [T; N]) -> &mut Self; + /// Create array where each array element `T` is returned by the `cb` call. fn from_fn(mut cb: F) -> Self where @@ -140,6 +145,16 @@ macro_rules! impl_array_size { Self(arr) } + fn from_core_array_ref(array_ref: &[T; $len]) -> &Self { + // SAFETY: `$ty` is a `repr(transparent)` newtype for `[T; $len]` + unsafe { &*(array_ref.as_ptr() as *const Self) } + } + + fn from_core_array_mut(array_ref: &mut [T; $len]) -> &mut Self { + // SAFETY: `$ty` is a `repr(transparent)` newtype for `[T; $len]` + unsafe { &mut *(array_ref.as_mut_ptr() as *mut Self) } + } + #[inline] fn from_slice(slice: &[T]) -> Result where @@ -307,6 +322,45 @@ where pub fn as_mut_slice(&mut self) -> &mut [T] { self.0.as_mut() } + + /// Convert the given slice into a reference to a hybrid array. + /// + /// # Panics + /// + /// Panics if the slice's length doesn't match the array type. + // TODO(tarcieri): deprecate this before the v0.2 release + // #[deprecated(since = "0.2.0", note = "use TryFrom instead")] + #[inline] + pub fn ref_from_slice(slice: &[T]) -> &Self { + slice.try_into().expect("slice length mismatch") + } + + /// Convert the given mutable slice to a mutable reference to a hybrid array. + /// + /// # Panics + /// + /// Panics if the slice's length doesn't match the array type. + // TODO(tarcieri): deprecate this before the v0.2 release + // #[deprecated(since = "0.2.0", note = "use TryFrom instead")] + #[inline] + pub fn ref_from_mut_slice(slice: &mut [T]) -> &mut Self { + slice.try_into().expect("slice length mismatch") + } + + /// Clone the contents of the slice as a new hybrid array. + /// + /// # Panics + /// + /// Panics if the slice's length doesn't match the array type. + // TODO(tarcieri): deprecate this before the v0.2 release + // #[deprecated(since = "0.2.0", note = "use TryFrom instead")] + #[inline] + pub fn clone_from_slice(slice: &[T]) -> Self + where + Self: Clone, + { + Self::ref_from_slice(slice).clone() + } } impl AsRef<[T; N]> for Array @@ -364,6 +418,28 @@ where } } +impl<'a, T, U, const N: usize> From<&'a [T; N]> for &'a Array +where + Array: ArrayOps, + U: ArraySize, +{ + #[inline] + fn from(array_ref: &'a [T; N]) -> &'a Array { + >::from_core_array_ref(array_ref) + } +} + +impl<'a, T, U, const N: usize> From<&'a mut [T; N]> for &'a mut Array +where + Array: ArrayOps, + U: ArraySize, +{ + #[inline] + fn from(array_ref: &'a mut [T; N]) -> &'a mut Array { + >::from_core_array_mut(array_ref) + } +} + impl Index for Array where [T]: Index, @@ -402,5 +478,47 @@ 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() as *const Self) }) + } +} + +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 { *(slice.as_ptr() as *mut Self) }) + } +} + /// Byte array type. pub type ByteArray = Array; + +/// Generate a [`TryFromSliceError`] if the slice doesn't match the given length. +fn check_slice_length(slice: &[T]) -> Result<(), TryFromSliceError> { + if slice.len() != U::USIZE { + // Hack: `TryFromSliceError` lacks a public constructor + <&[T; 1]>::try_from([].as_slice())?; + } + + Ok(()) +}