use super::*;
use core::{mem, ptr};
use core::ops::{Add, Sub};
use typenum::operator_aliases::*;
pub unsafe trait GenericSequence<T>: Sized {
type Length: ArrayLength<T>;
}
unsafe impl<T, N: ArrayLength<T>> GenericSequence<T> for GenericArray<T, N> {
type Length = N;
}
pub unsafe trait Lengthen<T>: GenericSequence<T> {
type Longer: Shorten<T, Shorter = Self>;
fn append(self, last: T) -> Self::Longer;
fn prepend(self, first: T) -> Self::Longer;
}
pub unsafe trait Shorten<T>: GenericSequence<T> {
type Shorter: Lengthen<T, Longer = Self>;
fn pop_back(self) -> (Self::Shorter, T);
fn pop_front(self) -> (T, Self::Shorter);
}
unsafe impl<T, N: ArrayLength<T>> Lengthen<T> for GenericArray<T, N>
where
N: Add<B1>,
Add1<N>: ArrayLength<T>,
Add1<N>: Sub<B1, Output = N>,
Sub1<Add1<N>>: ArrayLength<T>,
{
type Longer = GenericArray<T, Add1<N>>;
fn append(self, last: T) -> Self::Longer {
let mut longer: Self::Longer = unsafe { mem::uninitialized() };
unsafe {
ptr::write(longer.as_mut_ptr() as *mut _, self);
ptr::write(&mut longer[N::to_usize()], last);
}
longer
}
fn prepend(self, first: T) -> Self::Longer {
let mut longer: Self::Longer = unsafe { mem::uninitialized() };
let longer_ptr = longer.as_mut_ptr();
unsafe {
ptr::write(longer_ptr as *mut _, first);
ptr::write(longer_ptr.offset(1) as *mut _, self);
}
longer
}
}
unsafe impl<T, N: ArrayLength<T>> Shorten<T> for GenericArray<T, N>
where
N: Sub<B1>,
Sub1<N>: ArrayLength<T>,
Sub1<N>: Add<B1, Output = N>,
Add1<Sub1<N>>: ArrayLength<T>,
{
type Shorter = GenericArray<T, Sub1<N>>;
fn pop_back(self) -> (Self::Shorter, T) {
let init_ptr = self.as_ptr();
let last_ptr = unsafe { init_ptr.offset(Sub1::<N>::to_usize() as isize) };
let init = unsafe { ptr::read(init_ptr as _) };
let last = unsafe { ptr::read(last_ptr as _) };
mem::forget(self);
(init, last)
}
fn pop_front(self) -> (T, Self::Shorter) {
let head_ptr = self.as_ptr();
let tail_ptr = unsafe { head_ptr.offset(1) };
let head = unsafe { ptr::read(head_ptr as _) };
let tail = unsafe { ptr::read(tail_ptr as _) };
mem::forget(self);
(head, tail)
}
}
pub unsafe trait Split<T, K>: GenericSequence<T>
where
K: ArrayLength<T>,
{
type First: GenericSequence<T>;
type Second: GenericSequence<T>;
fn split(self) -> (Self::First, Self::Second);
}
unsafe impl<T, N, K> Split<T, K> for GenericArray<T, N>
where
N: ArrayLength<T>,
K: ArrayLength<T>,
N: Sub<K>,
Diff<N, K>: ArrayLength<T>,
{
type First = GenericArray<T, K>;
type Second = GenericArray<T, Diff<N, K>>;
fn split(self) -> (Self::First, Self::Second) {
let head_ptr = self.as_ptr();
let tail_ptr = unsafe { head_ptr.offset(K::to_usize() as isize) };
let head = unsafe { ptr::read(head_ptr as _) };
let tail = unsafe { ptr::read(tail_ptr as _) };
mem::forget(self);
(head, tail)
}
}
pub unsafe trait Concat<T, M>: GenericSequence<T>
where
M: ArrayLength<T>,
{
type Rest: GenericSequence<T, Length = M>;
type Output: GenericSequence<T>;
fn concat(self, rest: Self::Rest) -> Self::Output;
}
unsafe impl<T, N, M> Concat<T, M> for GenericArray<T, N>
where
N: ArrayLength<T> + Add<M>,
M: ArrayLength<T>,
Sum<N, M>: ArrayLength<T>,
{
type Rest = GenericArray<T, M>;
type Output = GenericArray<T, Sum<N, M>>;
fn concat(self, rest: Self::Rest) -> Self::Output {
let mut output: Self::Output = unsafe { mem::uninitialized() };
let output_ptr = output.as_mut_ptr();
unsafe {
ptr::write(output_ptr as *mut _, self);
ptr::write(output_ptr.offset(N::to_usize() as isize) as *mut _, rest);
}
output
}
}