use std::{ fmt, hash::{DefaultHasher, Hasher}, marker::PhantomData, }; use crate::{ alloc_aligned, layouts::{ Backend, Data, DataMut, DataRef, DataView, DataViewMut, DigestU64, ReaderFrom, WriterTo, ZnxInfos, ZnxSliceSize, ZnxView, }, oep::SvpPPolAllocBytesImpl, }; #[repr(C)] #[derive(PartialEq, Eq, Hash)] pub struct SvpPPol { pub data: D, pub n: usize, pub cols: usize, pub _phantom: PhantomData, } impl DigestU64 for SvpPPol { fn digest_u64(&self) -> u64 { let mut h: DefaultHasher = DefaultHasher::new(); h.write(self.data.as_ref()); h.write_usize(self.n); h.write_usize(self.cols); h.finish() } } impl ZnxSliceSize for SvpPPol { fn sl(&self) -> usize { B::layout_prep_word_count() * self.n() } } impl ZnxView for SvpPPol { type Scalar = B::ScalarPrep; } impl ZnxInfos for SvpPPol { fn cols(&self) -> usize { self.cols } fn rows(&self) -> usize { 1 } fn n(&self) -> usize { self.n } fn size(&self) -> usize { 1 } } impl DataView for SvpPPol { type D = D; fn data(&self) -> &Self::D { &self.data } } impl DataViewMut for SvpPPol { fn data_mut(&mut self) -> &mut Self::D { &mut self.data } } impl>, B: Backend> SvpPPol where B: SvpPPolAllocBytesImpl, { pub fn alloc(n: usize, cols: usize) -> Self { let data: Vec = alloc_aligned::(B::svp_ppol_bytes_of_impl(n, cols)); Self { data: data.into(), n, cols, _phantom: PhantomData, } } pub fn from_bytes(n: usize, cols: usize, bytes: impl Into>) -> Self { let data: Vec = bytes.into(); assert!(data.len() == B::svp_ppol_bytes_of_impl(n, cols)); Self { data: data.into(), n, cols, _phantom: PhantomData, } } } pub type SvpPPolOwned = SvpPPol, B>; pub trait SvpPPolToRef { fn to_ref(&self) -> SvpPPol<&[u8], B>; } impl SvpPPolToRef for SvpPPol { fn to_ref(&self) -> SvpPPol<&[u8], B> { SvpPPol { data: self.data.as_ref(), n: self.n, cols: self.cols, _phantom: PhantomData, } } } pub trait SvpPPolToMut { fn to_mut(&mut self) -> SvpPPol<&mut [u8], B>; } impl SvpPPolToMut for SvpPPol { fn to_mut(&mut self) -> SvpPPol<&mut [u8], B> { SvpPPol { data: self.data.as_mut(), n: self.n, cols: self.cols, _phantom: PhantomData, } } } impl SvpPPol { pub fn from_data(data: D, n: usize, cols: usize) -> Self { Self { data, n, cols, _phantom: PhantomData, } } } use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt}; impl ReaderFrom for SvpPPol { fn read_from(&mut self, reader: &mut R) -> std::io::Result<()> { self.n = reader.read_u64::()? as usize; self.cols = reader.read_u64::()? as usize; let len: usize = reader.read_u64::()? as usize; let buf: &mut [u8] = self.data.as_mut(); if buf.len() != len { return Err(std::io::Error::new( std::io::ErrorKind::UnexpectedEof, format!("self.data.len()={} != read len={}", buf.len(), len), )); } reader.read_exact(&mut buf[..len])?; Ok(()) } } impl WriterTo for SvpPPol { fn write_to(&self, writer: &mut W) -> std::io::Result<()> { writer.write_u64::(self.n as u64)?; writer.write_u64::(self.cols as u64)?; let buf: &[u8] = self.data.as_ref(); writer.write_u64::(buf.len() as u64)?; writer.write_all(buf)?; Ok(()) } } impl fmt::Display for SvpPPol { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { writeln!(f, "SvpPPol(n={}, cols={})", self.n, self.cols)?; for col in 0..self.cols { writeln!(f, "Column {col}:")?; let coeffs = self.at(col, 0); write!(f, "[")?; let max_show = 100; let show_count = coeffs.len().min(max_show); for (i, &coeff) in coeffs.iter().take(show_count).enumerate() { if i > 0 { write!(f, ", ")?; } write!(f, "{coeff}")?; } if coeffs.len() > max_show { write!(f, ", ... ({} more)", coeffs.len() - max_show)?; } writeln!(f, "]")?; } Ok(()) } }