diff --git a/src/sequence.rs b/src/sequence.rs index f57c1f901..4bb8241b9 100644 --- a/src/sequence.rs +++ b/src/sequence.rs @@ -2,7 +2,7 @@ use super::*; use core::mem::MaybeUninit; -use core::ops::{Add, Sub}; +use core::ops::{Add, Div, Mul, Sub}; use core::ptr; use typenum::operator_aliases::*; @@ -532,3 +532,145 @@ where (removed, mem::transmute_copy(&array)) } } + +/// Defines a `GenericSequence` of `GenericArray`s which can be flattened into a single `GenericArray`, +/// at zero cost. +/// +/// # Safety +/// While the [`flatten`](Flatten::flatten) method is marked safe, +/// care must be taken when implementing it. However, the given trait bounds +/// should be sufficient to ensure safety. +pub unsafe trait Flatten: GenericSequence, Length = M> +where + N: ArrayLength + Mul, + Prod: ArrayLength, +{ + /// Flattened sequence type + type Output: GenericSequence>; + + /// Flattens the sequence into a single `GenericArray`. + /// + /// # Example + /// + /// ```rust + /// # use generic_array::{arr, sequence::Flatten}; + /// assert_eq!( + /// arr![arr![1, 2], arr![3, 4], arr![5, 6]].flatten(), + /// arr![1, 2, 3, 4, 5, 6] + /// ); + /// ``` + fn flatten(self) -> Self::Output; +} + +/// Defines a `GenericSequence` of `T` which can be split evenly into a sequence of `GenericArray`s, +/// +/// # Safety +/// While the [`unflatten`](Unflatten::unflatten) method is marked safe, +/// care must be taken when implementing it. However, the given trait bounds +/// should be sufficient to ensure safety. +pub unsafe trait Unflatten: GenericSequence +where + NM: ArrayLength + Div, + N: ArrayLength, + Quot: ArrayLength, +{ + /// Unflattened sequence type + type Output: GenericSequence, Length = Quot>; + + /// Unflattens the sequence into a sequence of `GenericArray`s. + /// + /// # Example + /// + /// ```rust + /// # use generic_array::{arr, sequence::Unflatten}; + /// assert_eq!( + /// arr![1, 2, 3, 4, 5, 6].unflatten(), + /// arr![arr![1, 2], arr![3, 4], arr![5, 6]] + /// ); + /// ``` + fn unflatten(self) -> Self::Output; +} + +unsafe impl Flatten for GenericArray, M> +where + N: ArrayLength + Mul, + M: ArrayLength, + Prod: ArrayLength, +{ + type Output = GenericArray>; + + #[inline(always)] + fn flatten(self) -> Self::Output { + unsafe { crate::const_transmute(self) } + } +} + +unsafe impl<'a, T, N, M> Flatten for &'a GenericArray, M> +where + N: ArrayLength + Mul, + M: ArrayLength, + Prod: ArrayLength, +{ + type Output = &'a GenericArray>; + + #[inline(always)] + fn flatten(self) -> Self::Output { + unsafe { mem::transmute(self) } + } +} + +unsafe impl<'a, T, N, M> Flatten for &'a mut GenericArray, M> +where + N: ArrayLength + Mul, + M: ArrayLength, + Prod: ArrayLength, +{ + type Output = &'a mut GenericArray>; + + #[inline(always)] + fn flatten(self) -> Self::Output { + unsafe { mem::transmute(self) } + } +} + +unsafe impl Unflatten for GenericArray +where + NM: ArrayLength + Div, + N: ArrayLength, + Quot: ArrayLength, +{ + type Output = GenericArray, Quot>; + + #[inline(always)] + fn unflatten(self) -> Self::Output { + unsafe { crate::const_transmute(self) } + } +} + +unsafe impl<'a, T, NM, N> Unflatten for &'a GenericArray +where + NM: ArrayLength + Div, + N: ArrayLength, + Quot: ArrayLength, +{ + type Output = &'a GenericArray, Quot>; + + #[inline(always)] + fn unflatten(self) -> Self::Output { + unsafe { mem::transmute(self) } + } +} + +unsafe impl<'a, T, NM, N> Unflatten for &'a mut GenericArray +where + NM: ArrayLength + Div, + N: ArrayLength, + Quot: ArrayLength, +{ + type Output = &'a mut GenericArray, Quot>; + + #[inline(always)] + fn unflatten(self) -> Self::Output { + unsafe { mem::transmute(self) } + } +}