mirror of
https://github.com/zerotier/ZeroTierOne.git
synced 2025-10-09 14:55:06 +02:00
380 lines
11 KiB
Rust
380 lines
11 KiB
Rust
//! Useful traits for manipulating sequences of data stored in `GenericArray`s
|
|
|
|
use super::*;
|
|
use core::ops::{Add, Sub};
|
|
use core::mem::MaybeUninit;
|
|
use core::ptr;
|
|
use typenum::operator_aliases::*;
|
|
|
|
/// Defines some sequence with an associated length and iteration capabilities.
|
|
///
|
|
/// This is useful for passing N-length generic arrays as generics.
|
|
pub unsafe trait GenericSequence<T>: Sized + IntoIterator {
|
|
/// `GenericArray` associated length
|
|
type Length: ArrayLength<T>;
|
|
|
|
/// Concrete sequence type used in conjuction with reference implementations of `GenericSequence`
|
|
type Sequence: GenericSequence<T, Length = Self::Length> + FromIterator<T>;
|
|
|
|
/// Initializes a new sequence instance using the given function.
|
|
///
|
|
/// If the generator function panics while initializing the sequence,
|
|
/// any already initialized elements will be dropped.
|
|
fn generate<F>(f: F) -> Self::Sequence
|
|
where
|
|
F: FnMut(usize) -> T;
|
|
|
|
#[doc(hidden)]
|
|
fn inverted_zip<B, U, F>(
|
|
self,
|
|
lhs: GenericArray<B, Self::Length>,
|
|
mut f: F,
|
|
) -> MappedSequence<GenericArray<B, Self::Length>, B, U>
|
|
where
|
|
GenericArray<B, Self::Length>: GenericSequence<B, Length = Self::Length>
|
|
+ MappedGenericSequence<B, U>,
|
|
Self: MappedGenericSequence<T, U>,
|
|
Self::Length: ArrayLength<B> + ArrayLength<U>,
|
|
F: FnMut(B, Self::Item) -> U,
|
|
{
|
|
unsafe {
|
|
let mut left = ArrayConsumer::new(lhs);
|
|
|
|
let (left_array_iter, left_position) = left.iter_position();
|
|
|
|
FromIterator::from_iter(left_array_iter.zip(self.into_iter()).map(
|
|
|(l, right_value)| {
|
|
let left_value = ptr::read(l);
|
|
|
|
*left_position += 1;
|
|
|
|
f(left_value, right_value)
|
|
},
|
|
))
|
|
}
|
|
}
|
|
|
|
#[doc(hidden)]
|
|
fn inverted_zip2<B, Lhs, U, F>(self, lhs: Lhs, mut f: F) -> MappedSequence<Lhs, B, U>
|
|
where
|
|
Lhs: GenericSequence<B, Length = Self::Length> + MappedGenericSequence<B, U>,
|
|
Self: MappedGenericSequence<T, U>,
|
|
Self::Length: ArrayLength<B> + ArrayLength<U>,
|
|
F: FnMut(Lhs::Item, Self::Item) -> U,
|
|
{
|
|
FromIterator::from_iter(lhs.into_iter().zip(self.into_iter()).map(|(l, r)| f(l, r)))
|
|
}
|
|
}
|
|
|
|
/// Accessor for `GenericSequence` item type, which is really `IntoIterator::Item`
|
|
///
|
|
/// For deeply nested generic mapped sequence types, like shown in `tests/generics.rs`,
|
|
/// this can be useful for keeping things organized.
|
|
pub type SequenceItem<T> = <T as IntoIterator>::Item;
|
|
|
|
unsafe impl<'a, T: 'a, S: GenericSequence<T>> GenericSequence<T> for &'a S
|
|
where
|
|
&'a S: IntoIterator,
|
|
{
|
|
type Length = S::Length;
|
|
type Sequence = S::Sequence;
|
|
|
|
#[inline]
|
|
fn generate<F>(f: F) -> Self::Sequence
|
|
where
|
|
F: FnMut(usize) -> T,
|
|
{
|
|
S::generate(f)
|
|
}
|
|
}
|
|
|
|
unsafe impl<'a, T: 'a, S: GenericSequence<T>> GenericSequence<T> for &'a mut S
|
|
where
|
|
&'a mut S: IntoIterator,
|
|
{
|
|
type Length = S::Length;
|
|
type Sequence = S::Sequence;
|
|
|
|
#[inline]
|
|
fn generate<F>(f: F) -> Self::Sequence
|
|
where
|
|
F: FnMut(usize) -> T,
|
|
{
|
|
S::generate(f)
|
|
}
|
|
}
|
|
|
|
/// Defines any `GenericSequence` which can be lengthened or extended by appending
|
|
/// or prepending an element to it.
|
|
///
|
|
/// Any lengthened sequence can be shortened back to the original using `pop_front` or `pop_back`
|
|
pub unsafe trait Lengthen<T>: Sized + GenericSequence<T> {
|
|
/// `GenericSequence` that has one more element than `Self`
|
|
type Longer: Shorten<T, Shorter = Self>;
|
|
|
|
/// Returns a new array with the given element appended to the end of it.
|
|
///
|
|
/// Example:
|
|
///
|
|
/// ```rust
|
|
/// # use generic_array::{arr, sequence::Lengthen};
|
|
/// # fn main() {
|
|
/// let a = arr![i32; 1, 2, 3];
|
|
///
|
|
/// let b = a.append(4);
|
|
///
|
|
/// assert_eq!(b, arr![i32; 1, 2, 3, 4]);
|
|
/// # }
|
|
/// ```
|
|
fn append(self, last: T) -> Self::Longer;
|
|
|
|
/// Returns a new array with the given element prepended to the front of it.
|
|
///
|
|
/// Example:
|
|
///
|
|
/// ```rust
|
|
/// # use generic_array::{arr, sequence::Lengthen};
|
|
/// # fn main() {
|
|
/// let a = arr![i32; 1, 2, 3];
|
|
///
|
|
/// let b = a.prepend(4);
|
|
///
|
|
/// assert_eq!(b, arr![i32; 4, 1, 2, 3]);
|
|
/// # }
|
|
/// ```
|
|
fn prepend(self, first: T) -> Self::Longer;
|
|
}
|
|
|
|
/// Defines a `GenericSequence` which can be shortened by removing the first or last element from it.
|
|
///
|
|
/// Additionally, any shortened sequence can be lengthened by
|
|
/// appending or prepending an element to it.
|
|
pub unsafe trait Shorten<T>: Sized + GenericSequence<T> {
|
|
/// `GenericSequence` that has one less element than `Self`
|
|
type Shorter: Lengthen<T, Longer = Self>;
|
|
|
|
/// Returns a new array without the last element, and the last element.
|
|
///
|
|
/// Example:
|
|
///
|
|
/// ```rust
|
|
/// # use generic_array::{arr, sequence::Shorten};
|
|
/// # fn main() {
|
|
/// let a = arr![i32; 1, 2, 3, 4];
|
|
///
|
|
/// let (init, last) = a.pop_back();
|
|
///
|
|
/// assert_eq!(init, arr![i32; 1, 2, 3]);
|
|
/// assert_eq!(last, 4);
|
|
/// # }
|
|
/// ```
|
|
fn pop_back(self) -> (Self::Shorter, T);
|
|
|
|
/// Returns a new array without the first element, and the first element.
|
|
/// Example:
|
|
///
|
|
/// ```rust
|
|
/// # use generic_array::{arr, sequence::Shorten};
|
|
/// # fn main() {
|
|
/// let a = arr![i32; 1, 2, 3, 4];
|
|
///
|
|
/// let (head, tail) = a.pop_front();
|
|
///
|
|
/// assert_eq!(head, 1);
|
|
/// assert_eq!(tail, arr![i32; 2, 3, 4]);
|
|
/// # }
|
|
/// ```
|
|
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: MaybeUninit<Self::Longer> = MaybeUninit::uninit();
|
|
|
|
// Note this is *mut Self, so add(1) increments by the whole array
|
|
let out_ptr = longer.as_mut_ptr() as *mut Self;
|
|
|
|
unsafe {
|
|
// write self first
|
|
ptr::write(out_ptr, self);
|
|
// increment past self, then write the last
|
|
ptr::write(out_ptr.add(1) as *mut T, last);
|
|
|
|
longer.assume_init()
|
|
}
|
|
}
|
|
|
|
fn prepend(self, first: T) -> Self::Longer {
|
|
let mut longer: MaybeUninit<Self::Longer> = MaybeUninit::uninit();
|
|
|
|
// Note this is *mut T, so add(1) increments by a single T
|
|
let out_ptr = longer.as_mut_ptr() as *mut T;
|
|
|
|
unsafe {
|
|
// write the first at the start
|
|
ptr::write(out_ptr, first);
|
|
// increment past the first, then write self
|
|
ptr::write(out_ptr.add(1) as *mut Self, self);
|
|
|
|
longer.assume_init()
|
|
}
|
|
}
|
|
}
|
|
|
|
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 whole = ManuallyDrop::new(self);
|
|
|
|
unsafe {
|
|
let init = ptr::read(whole.as_ptr() as _);
|
|
let last = ptr::read(whole.as_ptr().add(Sub1::<N>::USIZE) as _);
|
|
|
|
(init, last)
|
|
}
|
|
}
|
|
|
|
fn pop_front(self) -> (T, Self::Shorter) {
|
|
// ensure this doesn't get dropped
|
|
let whole = ManuallyDrop::new(self);
|
|
|
|
unsafe {
|
|
let head = ptr::read(whole.as_ptr() as _);
|
|
let tail = ptr::read(whole.as_ptr().offset(1) as _);
|
|
|
|
(head, tail)
|
|
}
|
|
}
|
|
}
|
|
|
|
/// Defines a `GenericSequence` that can be split into two parts at a given pivot index.
|
|
pub unsafe trait Split<T, K>: GenericSequence<T>
|
|
where
|
|
K: ArrayLength<T>,
|
|
{
|
|
/// First part of the resulting split array
|
|
type First: GenericSequence<T>;
|
|
/// Second part of the resulting split array
|
|
type Second: GenericSequence<T>;
|
|
|
|
/// Splits an array at the given index, returning the separate parts of the array.
|
|
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) {
|
|
unsafe {
|
|
// ensure this doesn't get dropped
|
|
let whole = ManuallyDrop::new(self);
|
|
|
|
let head = ptr::read(whole.as_ptr() as *const _);
|
|
let tail = ptr::read(whole.as_ptr().add(K::USIZE) as *const _);
|
|
|
|
(head, tail)
|
|
}
|
|
}
|
|
}
|
|
|
|
unsafe impl<'a, T, N, K> Split<T, K> for &'a GenericArray<T, N>
|
|
where
|
|
N: ArrayLength<T>,
|
|
K: ArrayLength<T> + 'static,
|
|
N: Sub<K>,
|
|
Diff<N, K>: ArrayLength<T>,
|
|
{
|
|
type First = &'a GenericArray<T, K>;
|
|
type Second = &'a GenericArray<T, Diff<N, K>>;
|
|
|
|
fn split(self) -> (Self::First, Self::Second) {
|
|
unsafe {
|
|
let ptr_to_first: *const T = self.as_ptr();
|
|
let head = &*(ptr_to_first as *const _);
|
|
let tail = &*(ptr_to_first.add(K::USIZE) as *const _);
|
|
(head, tail)
|
|
}
|
|
}
|
|
}
|
|
|
|
unsafe impl<'a, T, N, K> Split<T, K> for &'a mut GenericArray<T, N>
|
|
where
|
|
N: ArrayLength<T>,
|
|
K: ArrayLength<T> + 'static,
|
|
N: Sub<K>,
|
|
Diff<N, K>: ArrayLength<T>,
|
|
{
|
|
type First = &'a mut GenericArray<T, K>;
|
|
type Second = &'a mut GenericArray<T, Diff<N, K>>;
|
|
|
|
fn split(self) -> (Self::First, Self::Second) {
|
|
unsafe {
|
|
let ptr_to_first: *mut T = self.as_mut_ptr();
|
|
let head = &mut *(ptr_to_first as *mut _);
|
|
let tail = &mut *(ptr_to_first.add(K::USIZE) as *mut _);
|
|
(head, tail)
|
|
}
|
|
}
|
|
}
|
|
|
|
/// Defines `GenericSequence`s which can be joined together, forming a larger array.
|
|
pub unsafe trait Concat<T, M>: GenericSequence<T>
|
|
where
|
|
M: ArrayLength<T>,
|
|
{
|
|
/// Sequence to be concatenated with `self`
|
|
type Rest: GenericSequence<T, Length = M>;
|
|
|
|
/// Resulting sequence formed by the concatenation.
|
|
type Output: GenericSequence<T>;
|
|
|
|
/// Concatenate, or join, two sequences.
|
|
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: MaybeUninit<Self::Output> = MaybeUninit::uninit();
|
|
|
|
let out_ptr = output.as_mut_ptr() as *mut Self;
|
|
|
|
unsafe {
|
|
// write all of self to the pointer
|
|
ptr::write(out_ptr, self);
|
|
// increment past self, then write the rest
|
|
ptr::write(out_ptr.add(1) as *mut _, rest);
|
|
|
|
output.assume_init()
|
|
}
|
|
}
|
|
}
|