use std::fmt::{self, Debug, Display, LowerHex};
use std::ops::Add;
use bytemuck::{Pod, Zeroable};
use rand_distr::num_traits::Zero;
use crate::layouts::DftWord;
mod sealed {
pub trait Sealed {}
impl Sealed for u32 {}
impl Sealed for u64 {}
}
pub trait LaneElem: sealed::Sealed + Copy + Debug + Display + LowerHex + PartialEq + Eq + Send + Sync + Pod + 'static {
const ZERO: Self;
fn wrapping_add(self, rhs: Self) -> Self;
}
impl LaneElem for u32 {
const ZERO: Self = 0;
fn wrapping_add(self, rhs: Self) -> Self {
u32::wrapping_add(self, rhs)
}
}
impl LaneElem for u64 {
const ZERO: Self = 0;
fn wrapping_add(self, rhs: Self) -> Self {
u64::wrapping_add(self, rhs)
}
}
pub trait LaneArray<T: LaneElem>: Copy + Debug + PartialEq + Eq + Send + Sync + Pod + 'static {
const LEN: usize;
fn as_slice(&self) -> &[T];
fn as_mut_slice(&mut self) -> &mut [T];
fn lanes_zeroed() -> Self;
fn lanes_from_fn(f: impl FnMut(usize) -> T) -> Self;
}
impl<T: LaneElem, const N: usize> LaneArray<T> for [T; N] {
const LEN: usize = N;
fn as_slice(&self) -> &[T] {
self
}
fn as_mut_slice(&mut self) -> &mut [T] {
self
}
fn lanes_zeroed() -> Self {
[T::ZERO; N]
}
fn lanes_from_fn(f: impl FnMut(usize) -> T) -> Self {
std::array::from_fn(f)
}
}
pub trait PrimeSet: Sized + Sync + Send + 'static {
type PrimeElem: LaneElem;
type Lanes<T: LaneElem>: LaneArray<T>;
const Q: Self::Lanes<Self::PrimeElem>;
const OMEGA: Self::Lanes<Self::PrimeElem>;
const LOG_Q: u64;
}
#[repr(transparent)]
pub struct CrtWord<P: PrimeSet, T: LaneElem>(pub P::Lanes<T>);
impl<P: PrimeSet, T: LaneElem> Clone for CrtWord<P, T> {
fn clone(&self) -> Self {
*self
}
}
impl<P: PrimeSet, T: LaneElem> Copy for CrtWord<P, T> {}
impl<P: PrimeSet, T: LaneElem> Default for CrtWord<P, T> {
fn default() -> Self {
Self(P::Lanes::<T>::lanes_zeroed())
}
}
impl<P: PrimeSet, T: LaneElem> PartialEq for CrtWord<P, T> {
fn eq(&self, other: &Self) -> bool {
self.0 == other.0
}
}
impl<P: PrimeSet, T: LaneElem> Eq for CrtWord<P, T> {}
impl<P: PrimeSet, T: LaneElem> fmt::Debug for CrtWord<P, T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_tuple("CrtWord").field(&self.0.as_slice()).finish()
}
}
impl<P: PrimeSet, T: LaneElem> fmt::Display for CrtWord<P, T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "[")?;
for (i, lane) in self.0.as_slice().iter().enumerate() {
if i > 0 {
write!(f, ", ")?;
}
write!(f, "{lane:#x}")?;
}
write!(f, "]")
}
}
unsafe impl<P: PrimeSet, T: LaneElem> Zeroable for CrtWord<P, T> {}
unsafe impl<P: PrimeSet, T: LaneElem> Pod for CrtWord<P, T> {}
impl<P: PrimeSet, T: LaneElem> DftWord for CrtWord<P, T> {}
impl<P: PrimeSet, T: LaneElem> Add for CrtWord<P, T> {
type Output = Self;
fn add(self, rhs: Self) -> Self {
Self(P::Lanes::<T>::lanes_from_fn(|k| {
self.0.as_slice()[k].wrapping_add(rhs.0.as_slice()[k])
}))
}
}
impl<P: PrimeSet, T: LaneElem> Zero for CrtWord<P, T> {
fn zero() -> Self {
Self(P::Lanes::<T>::lanes_zeroed())
}
fn is_zero(&self) -> bool {
self.0.as_slice().iter().all(|x| *x == T::ZERO)
}
}