use crate::xor_bytes::{XOR_LEN, XORBytes};
#[derive(Debug, Default, PartialEq, Eq, Clone, Copy)]
pub struct XORIndex(usize);
impl XORIndex {
#[inline]
pub fn at_offset(offset: usize) -> Self {
Self(offset & (XOR_LEN - 1))
}
#[inline]
pub(crate) fn phase(self) -> usize {
self.0
}
#[inline]
pub(crate) fn set_phase(&mut self, phase: usize) {
self.0 = phase & (XOR_LEN - 1);
}
#[inline]
pub fn add_assign(&mut self, i: usize) {
self.0 = (self.0 + i) & (XOR_LEN - 1);
}
pub fn bytes<'a>(&mut self, bytes: &'a mut [u8], xor_bytes: XORBytes) -> &'a mut [u8] {
if xor_bytes.is_identity() {
return bytes;
}
let xb = *xor_bytes;
let mut phase = self.0;
let len = bytes.len();
let mut i = 0;
while phase != 0 && i < len {
bytes[i] ^= xb[phase];
phase = (phase + 1) & (XOR_LEN - 1);
i += 1;
}
let body_len = (len - i) & !(XOR_LEN - 1);
for chunk in bytes[i..i + body_len].chunks_exact_mut(XOR_LEN) {
for (b, m) in chunk.iter_mut().zip(xb) {
*b ^= m;
}
}
i += body_len;
while i < len {
bytes[i] ^= xb[phase];
phase = (phase + 1) & (XOR_LEN - 1);
i += 1;
}
self.0 = phase;
bytes
}
#[inline]
pub fn decode_at(buffer: &mut [u8], offset: usize, xor_bytes: XORBytes) {
Self::at_offset(offset).bytes(buffer, xor_bytes);
}
}