Skip to content

Commit 840f11b

Browse files
rpiasetskyiRuslan Piasetskyi
andauthored
hybrid-array: implement concat and split methods (#958)
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. Co-authored-by: Ruslan Piasetskyi <ruslan.piasetskyi0@gmail.com>
1 parent eb03093 commit 840f11b

File tree

1 file changed

+116
-3
lines changed

1 file changed

+116
-3
lines changed

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)