macro_rules! from_integer_types {
($($type:ty),* $(,)? ) => {
$( paste::paste!{
fn [<from_ $type>](int: $type) -> Self {
Self::from_prime_subfield(Self::PrimeSubfield::from_int(int))
}
}
)*
};
}
pub(crate) use from_integer_types;
pub trait QuotientMap<Int>: Sized {
#[must_use]
fn from_int(int: Int) -> Self;
#[must_use]
fn from_canonical_checked(int: Int) -> Option<Self>;
#[must_use]
unsafe fn from_canonical_unchecked(int: Int) -> Self;
}
#[macro_export]
macro_rules! quotient_map_small_internals {
($field:ty, $field_size:ty, $small_int:ty) => {
#[doc = concat!("Convert a given `", stringify!($small_int), "` integer into an element of the `", stringify!($field), "` field.
\n Due to the integer type, the input value is always canonical.")]
#[inline]
fn from_int(int: $small_int) -> Self {
const { assert!(size_of::<$small_int>() < size_of::<$field_size>()); }
unsafe {
Self::from_canonical_unchecked(int as $field_size)
}
}
#[doc = concat!("Convert a given `", stringify!($small_int), "` integer into an element of the `", stringify!($field), "` field.
\n Due to the integer type, the input value is always canonical.")]
#[inline]
fn from_canonical_checked(int: $small_int) -> Option<Self> {
const { assert!(size_of::<$small_int>() < size_of::<$field_size>()); }
Some(unsafe {
Self::from_canonical_unchecked(int as $field_size)
})
}
#[doc = concat!("Convert a given `", stringify!($small_int), "` integer into an element of the `", stringify!($field), "` field.
\n Due to the integer type, the input value is always canonical.")]
#[inline]
unsafe fn from_canonical_unchecked(int: $small_int) -> Self {
const { assert!(size_of::<$small_int>() < size_of::<$field_size>()); }
unsafe {
Self::from_canonical_unchecked(int as $field_size)
}
}
};
}
#[macro_export]
macro_rules! quotient_map_small_int {
($field:ty, $field_size:ty, [$($small_int:ty),*] ) => {
$(
paste::paste!{
impl QuotientMap<$small_int> for $field {
$crate::quotient_map_small_internals!($field, $field_size, $small_int);
}
}
)*
};
($field:ty, $field_size:ty, $field_param:ty, [$($small_int:ty),*] ) => {
$(
paste::paste!{
impl<FP: $field_param> QuotientMap<$small_int> for $field<FP> {
$crate::quotient_map_small_internals!($field, $field_size, $small_int);
}
}
)*
};
}
#[macro_export]
macro_rules! quotient_map_large_uint {
($field:ty, $field_size:ty, $field_order:expr, $checked_bounds:literal, $unchecked_bounds:literal, [$($large_int:ty),*] ) => {
$(
impl QuotientMap<$large_int> for $field {
#[doc = concat!("Convert a given `", stringify!($large_int), "` integer into an element of the `", stringify!($field), "` field.
\n Uses a modular reduction to reduce to canonical form. \n This should be avoided in performance critical locations.")]
#[inline]
fn from_int(int: $large_int) -> $field {
const { assert!(size_of::<$large_int>() > size_of::<$field_size>()); }
let red = (int % ($field_order as $large_int)) as $field_size;
unsafe {
Self::from_canonical_unchecked(red)
}
}
#[doc = concat!("Convert a given `", stringify!($large_int), "` integer into an element of the `", stringify!($field), "` field.
\n Returns `None` if the input does not lie in the range:", $checked_bounds, ".")]
#[inline]
fn from_canonical_checked(int: $large_int) -> Option<$field> {
if int < $field_order as $large_int {
unsafe {
Some(Self::from_canonical_unchecked(int as $field_size))
}
} else {
None
}
}
#[doc = concat!("Convert a given `", stringify!($large_int), "` integer into an element of the `", stringify!($field), "` field.")]
#[doc = concat!("The input must lie in the range:", $unchecked_bounds, ".")]
#[inline]
unsafe fn from_canonical_unchecked(int: $large_int) -> $field {
unsafe {
Self::from_canonical_unchecked(int as $field_size)
}
}
}
)*
};
}
#[macro_export]
macro_rules! quotient_map_large_iint {
($field:ty, $field_size:ty, $checked_bounds:literal, $unchecked_bounds:literal, [$(($large_signed_int:ty, $large_int:ty)),*] ) => {
$(
impl QuotientMap<$large_signed_int> for $field {
#[doc = concat!("Convert a given `", stringify!($large_signed_int), "` integer into an element of the `", stringify!($field), "` field.
\n This checks the sign and then makes use of the equivalent method for unsigned integers. \n This should be avoided in performance critical locations.")]
#[inline]
fn from_int(int: $large_signed_int) -> $field {
if int >= 0 {
Self::from_int(int as $large_int)
} else {
-Self::from_int(-int as $large_int)
}
}
#[doc = concat!("Convert a given `", stringify!($large_int), "` integer into an element of the `", stringify!($field), "` field.
\n Returns `None` if the input does not lie in the range:", $checked_bounds, ".")]
#[inline]
fn from_canonical_checked(int: $large_signed_int) -> Option<$field> {
let int_small = TryInto::<$field_size>::try_into(int).ok();
int_small.map(Self::from_canonical_checked)?
}
#[doc = concat!("Convert a given `", stringify!($large_int), "` integer into an element of the `", stringify!($field), "` field.")]
#[doc = concat!("The input must lie in the range:", $unchecked_bounds, ".")]
#[inline]
unsafe fn from_canonical_unchecked(int: $large_signed_int) -> $field {
unsafe {
Self::from_canonical_unchecked(int as $field_size)
}
}
}
)*
};
}
macro_rules! impl_u_i_size {
($intsize:ty, $int8:ty, $int16:ty, $int32:ty, $int64:ty, $int128:ty) => {
impl<
F: QuotientMap<$int8>
+ QuotientMap<$int16>
+ QuotientMap<$int32>
+ QuotientMap<$int64>
+ QuotientMap<$int128>,
> QuotientMap<$intsize> for F
{
#[doc = concat!("We use the `from_int` method of the primitive integer type identical to `", stringify!($intsize), "` on this machine")]
fn from_int(int: $intsize) -> Self {
match size_of::<$intsize>() {
1 => Self::from_int(int as $int8),
2 => Self::from_int(int as $int16),
4 => Self::from_int(int as $int32),
8 => Self::from_int(int as $int64),
16 => Self::from_int(int as $int128),
_ => unreachable!(concat!(stringify!($intsize), "is not equivalent to any primitive integer types.")),
}
}
#[doc = concat!("We use the `from_canonical_checked` method of the primitive integer type identical to `", stringify!($intsize), "` on this machine")]
fn from_canonical_checked(int: $intsize) -> Option<Self> {
match size_of::<$intsize>() {
1 => Self::from_canonical_checked(int as $int8),
2 => Self::from_canonical_checked(int as $int16),
4 => Self::from_canonical_checked(int as $int32),
8 => Self::from_canonical_checked(int as $int64),
16 => Self::from_canonical_checked(int as $int128),
_ => unreachable!(concat!(stringify!($intsize), " is not equivalent to any primitive integer types.")),
}
}
#[doc = concat!("We use the `from_canonical_unchecked` method of the primitive integer type identical to `", stringify!($intsize), "` on this machine")]
unsafe fn from_canonical_unchecked(int: $intsize) -> Self {
unsafe {
match size_of::<$intsize>() {
1 => Self::from_canonical_unchecked(int as $int8),
2 => Self::from_canonical_unchecked(int as $int16),
4 => Self::from_canonical_unchecked(int as $int32),
8 => Self::from_canonical_unchecked(int as $int64),
16 => Self::from_canonical_unchecked(int as $int128),
_ => unreachable!(concat!(stringify!($intsize), " is not equivalent to any primitive integer types.")),
}
}
}
}
};
}
impl_u_i_size!(usize, u8, u16, u32, u64, u128);
impl_u_i_size!(isize, i8, i16, i32, i64, i128);
#[macro_export]
macro_rules! impl_raw_serializable_primefield32 {
() => {
const NUM_BYTES: usize = 4;
#[allow(refining_impl_trait)]
#[inline]
fn into_bytes(self) -> [u8; 4] {
self.to_unique_u32().to_le_bytes()
}
#[inline]
fn into_u32_stream(input: impl IntoIterator<Item = Self>) -> impl IntoIterator<Item = u32> {
input.into_iter().map(|x| x.to_unique_u32())
}
#[inline]
fn into_u64_stream(input: impl IntoIterator<Item = Self>) -> impl IntoIterator<Item = u64> {
let mut input = input.into_iter();
iter::from_fn(move || {
let a = input.next()?;
if let Some(b) = input.next() {
Some(a.to_unique_u64() | b.to_unique_u64() << 32)
} else {
Some(a.to_unique_u64())
}
})
}
#[inline]
fn into_parallel_byte_streams<const N: usize>(
input: impl IntoIterator<Item = [Self; N]>,
) -> impl IntoIterator<Item = [u8; N]> {
input.into_iter().flat_map(|vector| {
let bytes = vector.map(|elem| elem.into_bytes());
(0..Self::NUM_BYTES).map(move |i| array::from_fn(|j| bytes[j][i]))
})
}
#[inline]
fn into_parallel_u32_streams<const N: usize>(
input: impl IntoIterator<Item = [Self; N]>,
) -> impl IntoIterator<Item = [u32; N]> {
input.into_iter().map(|vec| vec.map(|x| x.to_unique_u32()))
}
#[inline]
fn into_parallel_u64_streams<const N: usize>(
input: impl IntoIterator<Item = [Self; N]>,
) -> impl IntoIterator<Item = [u64; N]> {
let mut input = input.into_iter();
iter::from_fn(move || {
let a = input.next()?;
if let Some(b) = input.next() {
let ab = array::from_fn(|i| {
let ai = a[i].to_unique_u64();
let bi = b[i].to_unique_u64();
ai | (bi << 32)
});
Some(ab)
} else {
Some(a.map(|x| x.to_unique_u64()))
}
})
}
};
}
#[macro_export]
macro_rules! impl_raw_serializable_primefield64 {
() => {
const NUM_BYTES: usize = 8;
#[allow(refining_impl_trait)]
#[inline]
fn into_bytes(self) -> [u8; 8] {
self.to_unique_u64().to_le_bytes()
}
#[inline]
fn into_u32_stream(input: impl IntoIterator<Item = Self>) -> impl IntoIterator<Item = u32> {
input.into_iter().flat_map(|x| {
let x_u64 = x.to_unique_u64();
[x_u64 as u32, (x_u64 >> 32) as u32]
})
}
#[inline]
fn into_u64_stream(input: impl IntoIterator<Item = Self>) -> impl IntoIterator<Item = u64> {
input.into_iter().map(|x| x.to_unique_u64())
}
#[inline]
fn into_parallel_byte_streams<const N: usize>(
input: impl IntoIterator<Item = [Self; N]>,
) -> impl IntoIterator<Item = [u8; N]> {
input.into_iter().flat_map(|vector| {
let bytes = vector.map(|elem| elem.into_bytes());
(0..Self::NUM_BYTES).map(move |i| array::from_fn(|j| bytes[j][i]))
})
}
#[inline]
fn into_parallel_u32_streams<const N: usize>(
input: impl IntoIterator<Item = [Self; N]>,
) -> impl IntoIterator<Item = [u32; N]> {
input.into_iter().flat_map(|vec| {
let vec_64 = vec.map(|x| x.to_unique_u64());
let vec_32_lo = vec_64.map(|x| x as u32);
let vec_32_hi = vec_64.map(|x| (x >> 32) as u32);
[vec_32_lo, vec_32_hi]
})
}
#[inline]
fn into_parallel_u64_streams<const N: usize>(
input: impl IntoIterator<Item = [Self; N]>,
) -> impl IntoIterator<Item = [u64; N]> {
input.into_iter().map(|vec| vec.map(|x| x.to_unique_u64()))
}
};
}