#[cfg(feature = "alloc")]
use super::{check_pair, check_width};
#[cfg(feature = "alloc")]
use crate::Frobenius;
#[cfg(feature = "alloc")]
use crate::bits;
#[cfg(feature = "alloc")]
use crate::field::{Elem, FieldBuffer};
#[cfg(feature = "alloc")]
use crate::{PreparedEmbedding, PreparedIsomorphism};
#[cfg(feature = "alloc")]
#[inline]
pub fn frobenius_into_with<F: FieldBuffer>(dst: &mut [u8], map: &Frobenius<F>, src: &[u8]) {
check_pair::<F>("frobenius_into_with", "dst", dst.len(), "src", src.len());
for (d, s) in dst
.chunks_exact_mut(F::BYTES)
.zip(src.chunks_exact(F::BYTES))
{
F::encode(d, F::decode(s).frobenius_with(map));
}
}
#[cfg(feature = "alloc")]
#[inline]
pub fn frobenius_assign_with<F: FieldBuffer>(row: &mut [u8], map: &Frobenius<F>) {
check_width::<F>("frobenius_assign_with", row.len());
for lane in row.chunks_exact_mut(F::BYTES) {
let image = F::decode(lane).frobenius_with(map);
F::encode(lane, image);
}
}
#[cfg(feature = "alloc")]
#[inline]
fn check_row<S: FieldBuffer, T: FieldBuffer>(name: &str, dst_len: usize, src_len: usize) {
assert!(
src_len.is_multiple_of(S::BYTES),
"{name}: src is {src_len} bytes, not a whole number of {} elements",
S::NAME
);
let count = src_len / S::BYTES;
let Some(expected) = count.checked_mul(T::BYTES) else {
panic!("{name}: dst is {dst_len} bytes but count {count} overflows `usize`");
};
assert_eq!(
dst_len,
expected,
"{name}: dst is {dst_len} bytes but src holds {count} {} elements needing {expected}",
S::NAME
);
}
#[cfg(feature = "alloc")]
#[inline]
pub fn embed_into_with<S, T>(dst: &mut [u8], map: &PreparedEmbedding<S, T>, src: &[u8])
where
S: FieldBuffer,
T: FieldBuffer<Characteristic = S::Characteristic>,
{
check_row::<S, T>("embed_into_with", dst.len(), src.len());
for (d, s) in dst
.chunks_exact_mut(T::BYTES)
.zip(src.chunks_exact(S::BYTES))
{
T::encode(d, map.embed(S::decode(s)));
}
}
#[cfg(feature = "alloc")]
#[inline]
pub fn trace_into_with<S, T>(dst: &mut [u8], map: &PreparedEmbedding<S, T>, src: &[u8])
where
S: FieldBuffer,
T: FieldBuffer<Characteristic = S::Characteristic>,
{
check_row::<T, S>("trace_into_with", dst.len(), src.len());
for (d, s) in dst
.chunks_exact_mut(S::BYTES)
.zip(src.chunks_exact(T::BYTES))
{
S::encode(d, map.trace(T::decode(s)));
}
}
#[cfg(feature = "alloc")]
#[inline]
pub fn norm_into_with<S, T>(dst: &mut [u8], map: &PreparedEmbedding<S, T>, src: &[u8])
where
S: FieldBuffer,
T: FieldBuffer<Characteristic = S::Characteristic>,
{
check_row::<T, S>("norm_into_with", dst.len(), src.len());
for (d, s) in dst
.chunks_exact_mut(S::BYTES)
.zip(src.chunks_exact(T::BYTES))
{
S::encode(d, map.norm(T::decode(s)));
}
}
#[cfg(feature = "alloc")]
#[inline]
fn check_restrict_row<S: FieldBuffer, T: FieldBuffer>(
name: &str,
dst_len: usize,
valid_len: usize,
src_len: usize,
) {
check_row::<T, S>(name, dst_len, src_len);
let count = src_len / T::BYTES;
let expected_valid = bits::bytes_for(count);
assert_eq!(
valid_len, expected_valid,
"{name}: valid is {valid_len} bytes but {count} elements need {expected_valid}"
);
}
#[cfg(feature = "alloc")]
#[inline]
pub fn restrict_into_with<S, T>(
dst: &mut [u8],
valid: &mut [u8],
map: &PreparedEmbedding<S, T>,
src: &[u8],
) where
S: FieldBuffer,
T: FieldBuffer<Characteristic = S::Characteristic>,
{
check_restrict_row::<S, T>("restrict_into_with", dst.len(), valid.len(), src.len());
valid.fill(0);
for (i, (d, s)) in dst
.chunks_exact_mut(S::BYTES)
.zip(src.chunks_exact(T::BYTES))
.enumerate()
{
match map.restrict(T::decode(s)) {
Some(preimage) => {
S::encode(d, preimage);
valid[i / 8] |= 1 << (i % 8);
}
None => {
S::encode(d, Elem::<S>::ZERO);
}
}
}
}
#[cfg(feature = "alloc")]
#[inline]
pub fn contains_into_with<S, T>(valid: &mut [u8], map: &PreparedEmbedding<S, T>, src: &[u8])
where
S: FieldBuffer,
T: FieldBuffer<Characteristic = S::Characteristic>,
{
assert!(
src.len().is_multiple_of(T::BYTES),
"contains_into_with: src is {} bytes, not a whole number of {} elements",
src.len(),
T::NAME
);
let count = src.len() / T::BYTES;
let expected_valid = bits::bytes_for(count);
assert_eq!(
valid.len(),
expected_valid,
"contains_into_with: valid is {} bytes but {count} elements need {expected_valid}",
valid.len()
);
valid.fill(0);
for (i, s) in src.chunks_exact(T::BYTES).enumerate() {
if map.contains(T::decode(s)) {
valid[i / 8] |= 1 << (i % 8);
}
}
}
#[cfg(feature = "alloc")]
#[inline]
pub fn apply_into_with<S, T>(dst: &mut [u8], map: &PreparedIsomorphism<S, T>, src: &[u8])
where
S: FieldBuffer,
T: FieldBuffer<Characteristic = S::Characteristic>,
{
check_row::<S, T>("apply_into_with", dst.len(), src.len());
for (d, s) in dst
.chunks_exact_mut(T::BYTES)
.zip(src.chunks_exact(S::BYTES))
{
T::encode(d, map.apply(S::decode(s)));
}
}
#[cfg(feature = "alloc")]
#[inline]
pub fn unapply_into_with<S, T>(dst: &mut [u8], map: &PreparedIsomorphism<S, T>, src: &[u8])
where
S: FieldBuffer,
T: FieldBuffer<Characteristic = S::Characteristic>,
{
check_row::<T, S>("unapply_into_with", dst.len(), src.len());
for (d, s) in dst
.chunks_exact_mut(S::BYTES)
.zip(src.chunks_exact(T::BYTES))
{
S::encode(d, map.unapply(T::decode(s)));
}
}