Skip to content

Commit 026d7fa

Browse files
author
Ruslan Piasetskyi
committed
hybrid-array: implement Concat and Split
These traits add 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 relevant traits.
1 parent eb03093 commit 026d7fa

1 file changed

Lines changed: 129 additions & 4 deletions

File tree

hybrid-array/src/lib.rs

Lines changed: 129 additions & 4 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
///
@@ -613,6 +615,110 @@ macro_rules! impl_array_size {
613615
};
614616
}
615617

618+
/// Defines trait for concatenation.
619+
pub trait Concat<T, M: ArraySize> {
620+
/// Part to be appended to `self`
621+
type Suffix;
622+
623+
/// Result of the concatenation.
624+
type Output;
625+
626+
/// Concatenates `self` with `suffix`.
627+
fn concat(self, suffix: Self::Suffix) -> Self::Output;
628+
}
629+
630+
impl<T, M, N> Concat<T, M> for Array<T, N>
631+
where
632+
N: ArraySize + Add<M>,
633+
M: ArraySize,
634+
Sum<N, M>: ArraySize,
635+
{
636+
type Suffix = Array<T, M>;
637+
type Output = Array<T, Sum<N, M>>;
638+
639+
fn concat(self, suffix: Self::Suffix) -> Self::Output {
640+
let mut output: MaybeUninit<Self::Output> = MaybeUninit::uninit();
641+
let out_ptr = output.as_mut_ptr() as *mut Self;
642+
643+
unsafe {
644+
ptr::write(out_ptr, self);
645+
ptr::write(out_ptr.add(1) as *mut _, suffix);
646+
output.assume_init()
647+
}
648+
}
649+
}
650+
651+
/// Defines trait for splitting.
652+
pub trait Split<T, K: ArraySize> {
653+
/// First part of the split.
654+
type Head;
655+
/// Second part of the split.
656+
type Tail;
657+
658+
/// Splits `self` in two parts.
659+
fn split(self) -> (Self::Head, Self::Tail);
660+
}
661+
662+
impl<T, N, K> Split<T, K> for Array<T, N>
663+
where
664+
N: ArraySize,
665+
K: ArraySize,
666+
N: Sub<K>,
667+
Diff<N, K>: ArraySize,
668+
{
669+
type Head = Array<T, K>;
670+
type Tail = Array<T, Diff<N, K>>;
671+
672+
fn split(self) -> (Self::Head, Self::Tail) {
673+
unsafe {
674+
let array = ManuallyDrop::new(self);
675+
let head = ptr::read(array.as_ptr() as *const _);
676+
let tail = ptr::read(array.as_ptr().add(K::USIZE) as *const _);
677+
(head, tail)
678+
}
679+
}
680+
}
681+
682+
impl<'a, T, N, K> Split<T, K> for &'a Array<T, N>
683+
where
684+
N: ArraySize,
685+
K: ArraySize,
686+
N: Sub<K>,
687+
Diff<N, K>: ArraySize,
688+
{
689+
type Head = &'a Array<T, K>;
690+
type Tail = &'a Array<T, Diff<N, K>>;
691+
692+
fn split(self) -> (Self::Head, Self::Tail) {
693+
unsafe {
694+
let array_ptr: *const T = self.as_ptr();
695+
let head = &*(array_ptr as *const _);
696+
let tail = &*(array_ptr.add(K::USIZE) as *const _);
697+
(head, tail)
698+
}
699+
}
700+
}
701+
702+
impl<'a, T, N, K> Split<T, K> for &'a mut Array<T, N>
703+
where
704+
N: ArraySize,
705+
K: ArraySize,
706+
N: Sub<K>,
707+
Diff<N, K>: ArraySize,
708+
{
709+
type Head = &'a mut Array<T, K>;
710+
type Tail = &'a mut Array<T, Diff<N, K>>;
711+
712+
fn split(self) -> (Self::Head, Self::Tail) {
713+
unsafe {
714+
let array_ptr: *mut T = self.as_mut_ptr();
715+
let head = &mut *(array_ptr as *mut _);
716+
let tail = &mut *(array_ptr.add(K::USIZE) as *mut _);
717+
(head, tail)
718+
}
719+
}
720+
}
721+
616722
impl_array_size! {
617723
0 => U0,
618724
1 => U1,
@@ -696,9 +802,9 @@ impl_array_size! {
696802

697803
#[cfg(test)]
698804
mod tests {
699-
use super::ByteArray;
805+
use super::{ByteArray, Concat, Split};
700806
use crate::Array;
701-
use typenum::{U0, U3, U6, U7};
807+
use typenum::{U0, U2, U3, U4, U6, U7};
702808

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

@@ -729,4 +835,23 @@ mod tests {
729835

730836
assert!(<&ByteArray::<U7>>::try_from(EXAMPLE_SLICE).is_err());
731837
}
838+
839+
#[test]
840+
fn concat() {
841+
let prefix = ByteArray::<U2>::clone_from_slice(&EXAMPLE_SLICE[..2]);
842+
let suffix = ByteArray::<U4>::clone_from_slice(&EXAMPLE_SLICE[2..]);
843+
844+
let array = prefix.concat(suffix);
845+
assert_eq!(array.as_slice(), EXAMPLE_SLICE);
846+
}
847+
848+
#[test]
849+
fn split() {
850+
let array = ByteArray::<U6>::clone_from_slice(EXAMPLE_SLICE);
851+
852+
let (prefix, suffix) = Split::<_, U2>::split(array);
853+
854+
assert_eq!(prefix.as_slice(), &EXAMPLE_SLICE[..2]);
855+
assert_eq!(suffix.as_slice(), &EXAMPLE_SLICE[2..]);
856+
}
732857
}

0 commit comments

Comments
 (0)