Skip to content

Commit ac7f14d

Browse files
author
Ruslan Piasetskyi
committed
hybrid-array: implement concat and split methods
Convenient methods for concatenation and splitting. The size of the result is calculated in the compile time. This implementation was inspired by GenericArray implementation of Concat and Split traits.
1 parent eb03093 commit ac7f14d

1 file changed

Lines changed: 116 additions & 3 deletions

File tree

hybrid-array/src/lib.rs

Lines changed: 116 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -32,10 +32,12 @@ use core::{
3232
cmp::Ordering,
3333
fmt::{self, Debug},
3434
hash::{Hash, Hasher},
35-
ops::{Deref, DerefMut, Index, IndexMut, Range},
35+
mem::{ManuallyDrop, MaybeUninit},
36+
ops::{Add, Deref, DerefMut, Index, IndexMut, Range, Sub},
37+
ptr,
3638
slice::{Iter, IterMut},
3739
};
38-
use typenum::Unsigned;
40+
use typenum::{Diff, Sum, Unsigned};
3941

4042
/// Hybrid typenum-based and const generic array type.
4143
///
@@ -44,6 +46,10 @@ use typenum::Unsigned;
4446
#[repr(transparent)]
4547
pub struct Array<T, U: ArraySize>(pub U::ArrayType<T>);
4648

49+
type SplitResult<T, U, N> = (Array<T, N>, Array<T, Diff<U, N>>);
50+
type SplitRefResult<'a, T, U, N> = (&'a Array<T, N>, &'a Array<T, Diff<U, N>>);
51+
type SplitRefMutResult<'a, T, U, N> = (&'a mut Array<T, N>, &'a mut Array<T, Diff<U, N>>);
52+
4753
impl<T, U> Array<T, U>
4854
where
4955
U: ArraySize,
@@ -126,6 +132,74 @@ where
126132
{
127133
Self::ref_from_slice(slice).clone()
128134
}
135+
136+
/// Concatenates `self` with `other`.
137+
#[inline]
138+
pub fn concat<N>(self, other: Array<T, N>) -> Array<T, Sum<U, N>>
139+
where
140+
N: ArraySize,
141+
U: Add<N>,
142+
Sum<U, N>: ArraySize,
143+
{
144+
let mut result = MaybeUninit::uninit();
145+
let result_ptr = result.as_mut_ptr() as *mut Self;
146+
147+
unsafe {
148+
ptr::write(result_ptr, self);
149+
ptr::write(result_ptr.add(1) as *mut _, other);
150+
result.assume_init()
151+
}
152+
}
153+
154+
/// Splits `self` at index `N` in two arrays.
155+
///
156+
/// New arrays hold the original memory from `self`.
157+
#[inline]
158+
pub fn split<N>(self) -> SplitResult<T, U, N>
159+
where
160+
U: Sub<N>,
161+
N: ArraySize,
162+
Diff<U, N>: ArraySize,
163+
{
164+
unsafe {
165+
let array = ManuallyDrop::new(self);
166+
let head = ptr::read(array.as_ptr() as *const _);
167+
let tail = ptr::read(array.as_ptr().add(N::USIZE) as *const _);
168+
(head, tail)
169+
}
170+
}
171+
172+
/// Splits `&self` at index `N` in two array references.
173+
#[inline]
174+
pub fn split_ref<N>(&self) -> SplitRefResult<'_, T, U, N>
175+
where
176+
U: Sub<N>,
177+
N: ArraySize,
178+
Diff<U, N>: ArraySize,
179+
{
180+
unsafe {
181+
let array_ptr = self.as_ptr();
182+
let head = &*(array_ptr as *const _);
183+
let tail = &*(array_ptr.add(N::USIZE) as *const _);
184+
(head, tail)
185+
}
186+
}
187+
188+
/// Splits `&mut self` at index `N` in two mutable array references.
189+
#[inline]
190+
pub fn split_ref_mut<N>(&mut self) -> SplitRefMutResult<'_, T, U, N>
191+
where
192+
U: Sub<N>,
193+
N: ArraySize,
194+
Diff<U, N>: ArraySize,
195+
{
196+
unsafe {
197+
let array_ptr = self.as_mut_ptr();
198+
let head = &mut *(array_ptr as *mut _);
199+
let tail = &mut *(array_ptr.add(N::USIZE) as *mut _);
200+
(head, tail)
201+
}
202+
}
129203
}
130204

131205
impl<T, U, const N: usize> AsRef<[T; N]> for Array<T, U>
@@ -698,7 +772,7 @@ impl_array_size! {
698772
mod tests {
699773
use super::ByteArray;
700774
use crate::Array;
701-
use typenum::{U0, U3, U6, U7};
775+
use typenum::{U0, U2, U3, U4, U6, U7};
702776

703777
const EXAMPLE_SLICE: &[u8] = &[1, 2, 3, 4, 5, 6];
704778

@@ -729,4 +803,43 @@ mod tests {
729803

730804
assert!(<&ByteArray::<U7>>::try_from(EXAMPLE_SLICE).is_err());
731805
}
806+
807+
#[test]
808+
fn concat() {
809+
let prefix = ByteArray::<U2>::clone_from_slice(&EXAMPLE_SLICE[..2]);
810+
let suffix = ByteArray::<U4>::clone_from_slice(&EXAMPLE_SLICE[2..]);
811+
812+
let array = prefix.concat(suffix);
813+
assert_eq!(array.as_slice(), EXAMPLE_SLICE);
814+
}
815+
816+
#[test]
817+
fn split() {
818+
let array = ByteArray::<U6>::clone_from_slice(EXAMPLE_SLICE);
819+
820+
let (prefix, suffix) = array.split::<U2>();
821+
822+
assert_eq!(prefix.as_slice(), &EXAMPLE_SLICE[..2]);
823+
assert_eq!(suffix.as_slice(), &EXAMPLE_SLICE[2..]);
824+
}
825+
826+
#[test]
827+
fn split_ref() {
828+
let array = ByteArray::<U6>::clone_from_slice(EXAMPLE_SLICE);
829+
830+
let (prefix, suffix) = array.split_ref::<U3>();
831+
832+
assert_eq!(prefix.as_slice(), &EXAMPLE_SLICE[..3]);
833+
assert_eq!(suffix.as_slice(), &EXAMPLE_SLICE[3..]);
834+
}
835+
836+
#[test]
837+
fn split_ref_mut() {
838+
let array = &mut ByteArray::<U6>::clone_from_slice(EXAMPLE_SLICE);
839+
840+
let (prefix, suffix) = array.split_ref_mut::<U4>();
841+
842+
assert_eq!(prefix.as_slice(), &EXAMPLE_SLICE[..4]);
843+
assert_eq!(suffix.as_slice(), &EXAMPLE_SLICE[4..]);
844+
}
732845
}

0 commit comments

Comments
 (0)