Created
May 9, 2024 07:00
-
-
Save herabit/ede9eec370fe506164f0992b7f0506c0 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
mod sealed; | |
// mod util; | |
pub trait Split<Scalar>: sealed::Sealed { | |
type Array: AsRef<[Scalar]> + AsMut<[Scalar]>; | |
#[must_use] | |
fn split(self) -> Self::Array; | |
#[must_use] | |
#[inline] | |
fn rsplit(self) -> Self::Array { | |
let mut split = self.split(); | |
split.as_mut().reverse(); | |
split | |
} | |
#[must_use] | |
fn from_split(split: Self::Array) -> Self; | |
#[must_use] | |
#[inline] | |
fn from_rsplit(mut split: Self::Array) -> Self { | |
split.as_mut().reverse(); | |
Self::from_split(split) | |
} | |
} | |
pub trait SplitInto: sealed::Sealed { | |
#[must_use] | |
#[inline] | |
fn split_into<T>(self) -> <Self as Split<T>>::Array | |
where | |
Self: Split<T>, | |
{ | |
self.split() | |
} | |
#[must_use] | |
#[inline] | |
fn rsplit_into<T>(self) -> <Self as Split<T>>::Array | |
where | |
Self: Split<T>, | |
{ | |
self.rsplit() | |
} | |
} | |
impl<T: sealed::Sealed> SplitInto for T {} | |
#[inline(always)] | |
fn init_array<T, const N: usize, I>(iter: I) -> [T; N] | |
where | |
I: IntoIterator<Item = T>, | |
I::IntoIter: ExactSizeIterator, | |
{ | |
let mut iter = iter.into_iter(); | |
core::array::from_fn(move |_| iter.next().unwrap()) | |
} | |
macro_rules! impl_unsigned { | |
($( | |
$prim:ident: ( | |
$([$scalar:ident, $signed_scalar:ident; $length:tt]),* $(,)? | |
) | |
),* $(,)?) => { | |
$( | |
$( | |
impl Split<$scalar> for $prim { | |
type Array = [$scalar; $length]; | |
#[inline] | |
#[must_use] | |
fn split(self) -> Self::Array { | |
init_array( | |
(0u32..$length) | |
.rev() | |
.map(|index| index * $scalar::BITS) | |
.map(|shift| self >> shift) | |
.map(|shifted| shifted as $scalar) | |
) | |
} | |
#[inline] | |
#[must_use] | |
fn from_split(split: Self::Array) -> Self { | |
split | |
.into_iter() | |
.rev() | |
.enumerate() | |
.map(|(index, value)| (index as u32 * $scalar::BITS, value)) | |
.map(|(shift, value)| (value as $prim) << shift) | |
.fold(0, |result, bits| result | bits) | |
} | |
#[inline] | |
#[must_use] | |
fn rsplit(self) -> Self::Array { | |
init_array( | |
(0u32..$length) | |
.map(|index| index * $scalar::BITS) | |
.map(|shift| self >> shift) | |
.map(|shifted| shifted as $scalar) | |
) | |
} | |
#[inline] | |
#[must_use] | |
fn from_rsplit(split: Self::Array) -> Self { | |
split | |
.into_iter() | |
.enumerate() | |
.map(|(index, value)| (index as u32 * $scalar::BITS, value)) | |
.map(|(shift, value)| (value as $prim) << shift) | |
.fold(0, |result, bits| result | bits) | |
} | |
} | |
impl Split<$signed_scalar> for $prim { | |
type Array = [$signed_scalar; $length]; | |
#[inline] | |
#[must_use] | |
fn split(self) -> Self::Array { | |
<Self as Split<$scalar>>::split(self) | |
.map(|v| v as $signed_scalar) | |
} | |
#[inline] | |
#[must_use] | |
fn from_split(split: Self::Array) -> Self { | |
<Self as Split<$scalar>>::from_split( | |
split.map(|v| v as $scalar) | |
) | |
} | |
#[inline] | |
#[must_use] | |
fn rsplit(self) -> Self::Array { | |
<Self as Split<$scalar>>::rsplit(self) | |
.map(|v| v as $signed_scalar) | |
} | |
#[inline] | |
#[must_use] | |
fn from_rsplit(split: Self::Array) -> Self { | |
<Self as Split<$scalar>>::from_rsplit( | |
split.map(|v| v as $scalar) | |
) | |
} | |
} | |
)* | |
)* | |
}; | |
} | |
impl_unsigned! { | |
u128: ( | |
[u128, i128; 1], | |
[u64, i64; 2], | |
[u32, i32; 4], | |
[u16, i16; 8], | |
[u8, i8; 16], | |
), | |
u64: ( | |
[u64, i64; 1], | |
[u32, i32; 2], | |
[u16, i16; 4], | |
[u8, i8; 8], | |
), | |
u32: ( | |
[u32, i32; 1], | |
[u16, i16; 2], | |
[u8, i8; 4], | |
), | |
u16: ( | |
[u16, i16; 1], | |
[u8, i8; 2], | |
), | |
u8: ( | |
[u8, i8; 1], | |
), | |
} | |
macro_rules! impl_signed { | |
( | |
$($prim:ident: $unsigned:ident),* $(,)? | |
) => { | |
$( | |
impl<T> Split<T> for $prim | |
where | |
$unsigned: Split<T>, | |
{ | |
type Array = <$unsigned as Split<T>>::Array; | |
#[inline] | |
#[must_use] | |
fn split(self) -> Self::Array { | |
Split::<T>::split(self as $unsigned) | |
} | |
#[inline] | |
#[must_use] | |
fn from_split(split: Self::Array) -> Self { | |
<$unsigned as Split<T>>::from_split(split) as $prim | |
} | |
#[inline] | |
#[must_use] | |
fn rsplit(self) -> Self::Array { | |
Split::<T>::rsplit(self as $unsigned) | |
} | |
#[inline] | |
#[must_use] | |
fn from_rsplit(split: Self::Array) -> Self { | |
<$unsigned as Split<T>>::from_rsplit(split) as $prim | |
} | |
} | |
)* | |
}; | |
} | |
impl_signed! { | |
i128: u128, | |
i64: u64, | |
i32: u32, | |
i16: u16, | |
i8: u8, | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment