use crate::io::{Error, Read};
use super::buffer_backend::{BufferBackend, WILDCOPY_OVERLENGTH};
pub(crate) struct UserSliceBackend<'a> {
slice: &'a mut [u8],
head: usize,
tail: usize,
}
impl<'a> UserSliceBackend<'a> {
pub(crate) fn from_slice(slice: &'a mut [u8]) -> Self {
Self {
slice,
head: 0,
tail: 0,
}
}
}
impl<'a> BufferBackend for UserSliceBackend<'a> {
const SUPPORTS_INLINE_SEQUENCE_EXEC: bool = cfg!(target_arch = "x86_64");
#[cfg(target_arch = "x86_64")]
#[inline(always)]
unsafe fn exec_sequence_inline(
&mut self,
lit_src: *const u8,
lit_length: usize,
offset: usize,
match_length: usize,
) -> Result<(), super::errors::ExecuteSequencesError> {
use super::errors::ExecuteSequencesError;
use super::exec_sequence_inline::x86::{
copy16, overlap_copy8, wildcopy_no_overlap, wildcopy_overlap_8byte_stride,
};
const MAX_WILDCOPY_OVERSHOOT: usize = 15;
let cap = self.slice.len();
let total = match lit_length.checked_add(match_length) {
Some(v) => v,
None => {
return Err(ExecuteSequencesError::OutputBufferOverflow {
tail: self.tail,
requested: usize::MAX,
capacity: cap,
});
}
};
let cap_required = self
.tail
.checked_add(total)
.and_then(|new_tail| new_tail.checked_add(MAX_WILDCOPY_OVERSHOOT));
let cap_required = match cap_required {
Some(v) if v <= cap => v,
_ => {
return Err(ExecuteSequencesError::OutputBufferOverflow {
tail: self.tail,
requested: total,
capacity: cap,
});
}
};
let _ = cap_required;
let new_tail = self.tail + total;
debug_assert!(offset >= 1);
debug_assert!(match_length >= 1);
let live_len = self.tail - self.head;
debug_assert!(
live_len
.checked_add(lit_length)
.is_some_and(|end| offset <= end),
"exec_sequence_inline: offset ({}) exceeds live window (len={} + lit={}, head={}, tail={})",
offset,
live_len,
lit_length,
self.head,
self.tail,
);
unsafe {
let base_mut = self.slice.as_mut_ptr();
let op_lit = base_mut.add(self.tail);
copy16(op_lit, lit_src);
if lit_length > 16 {
wildcopy_no_overlap(op_lit.add(16), lit_src.add(16), lit_length - 16);
}
let op_match = base_mut.add(self.tail + lit_length);
let match_src = base_mut.cast_const().add(self.tail + lit_length - offset);
if offset >= 16 {
wildcopy_no_overlap(op_match, match_src, match_length);
} else {
let (op2, ip2) = overlap_copy8(op_match, match_src, offset);
if match_length > 8 {
wildcopy_overlap_8byte_stride(op2, ip2, match_length - 8);
}
}
}
self.tail = new_tail;
Ok(())
}
fn new() -> Self {
Self {
slice: &mut [],
head: 0,
tail: 0,
}
}
#[inline]
fn clear(&mut self) {
self.head = 0;
self.tail = 0;
}
#[inline(always)]
fn try_reserve(&mut self, n: usize) -> Result<(), super::buffer_backend::BackendOverflow> {
match self.tail.checked_add(n) {
Some(new_tail) if new_tail <= self.slice.len() => Ok(()),
_ => Err(super::buffer_backend::BackendOverflow {
tail: self.tail,
requested: n,
capacity: self.slice.len(),
}),
}
}
#[inline]
fn reserve(&mut self, _n: usize) {
}
#[inline]
fn len(&self) -> usize {
self.tail - self.head
}
#[inline]
fn cap(&self) -> usize {
self.slice.len()
}
#[inline]
fn tail(&self) -> usize {
self.tail
}
#[inline]
unsafe fn set_tail(&mut self, new_tail: usize) {
debug_assert!(new_tail >= self.head);
debug_assert!(new_tail <= self.slice.len());
self.tail = new_tail;
}
#[inline(always)]
fn extend(&mut self, data: &[u8]) {
let len = data.len();
let new_tail = self.tail + len;
assert!(
new_tail <= self.slice.len(),
"UserSliceBackend::extend overflows slice (tail+={}, cap={}) — corrupt frame",
len,
self.slice.len()
);
let total_writable = self.slice.len() - self.tail;
unsafe {
super::simd_copy::copy_bytes_overshooting(
(data.as_ptr(), len),
(self.slice.as_mut_ptr().add(self.tail), total_writable),
len,
);
}
self.tail = new_tail;
}
#[inline]
fn extend_and_fill(&mut self, fill_with: u8, fill_length: usize) {
let new_tail = self.tail + fill_length;
assert!(
new_tail <= self.slice.len(),
"UserSliceBackend::extend_and_fill overflows slice (tail+={}, cap={}) — corrupt frame",
fill_length,
self.slice.len()
);
self.slice[self.tail..new_tail].fill(fill_with);
self.tail = new_tail;
}
fn extend_from_reader<R: Read>(
&mut self,
mut read: R,
fill_length: usize,
) -> Result<(), Error> {
let old = self.tail;
let new_tail = old + fill_length;
if new_tail > self.slice.len() {
return Err(Error::other(
"UserSliceBackend: raw block exceeds caller-provided output capacity",
));
}
match read.read_exact(&mut self.slice[old..new_tail]) {
Ok(()) => {
self.tail = new_tail;
Ok(())
}
Err(e) => Err(e),
}
}
#[inline]
unsafe fn extend_from_within_unchecked(&mut self, start: usize, len: usize) {
let dst_off = self.tail;
let src_off = self.head + start;
debug_assert!(src_off + len <= dst_off);
assert!(
dst_off + len <= self.slice.len(),
"UserSliceBackend: match write past slice capacity (corrupt frame)"
);
let total_readable = self.tail - src_off;
let total_writable = self.slice.len() - dst_off;
unsafe {
let base = self.slice.as_mut_ptr();
super::simd_copy::copy_bytes_overshooting(
(base.add(src_off), total_readable),
(base.add(dst_off), total_writable),
len,
);
}
self.tail = dst_off + len;
}
#[inline]
unsafe fn extend_from_within_unchecked_branchless(&mut self, start: usize, len: usize) {
unsafe { self.extend_from_within_unchecked(start, len) }
}
#[inline]
fn as_slices(&self) -> (&[u8], &[u8]) {
(&self.slice[self.head..self.tail], &[])
}
#[inline]
fn drop_first_n(&mut self, n: usize) {
self.head += n;
debug_assert!(self.head <= self.tail);
}
#[inline(always)]
fn try_extend(&mut self, data: &[u8]) -> Result<(), super::buffer_backend::BackendOverflow> {
let len = data.len();
let new_tail =
self.tail
.checked_add(len)
.ok_or(super::buffer_backend::BackendOverflow {
tail: self.tail,
requested: len,
capacity: self.slice.len(),
})?;
if new_tail > self.slice.len() {
return Err(super::buffer_backend::BackendOverflow {
tail: self.tail,
requested: len,
capacity: self.slice.len(),
});
}
let total_writable = self.slice.len() - self.tail;
unsafe {
super::simd_copy::copy_bytes_overshooting(
(data.as_ptr(), len),
(self.slice.as_mut_ptr().add(self.tail), total_writable),
len,
);
}
self.tail = new_tail;
Ok(())
}
#[inline(always)]
fn try_extend_and_fill(
&mut self,
fill_with: u8,
fill_length: usize,
) -> Result<(), super::buffer_backend::BackendOverflow> {
let new_tail =
self.tail
.checked_add(fill_length)
.ok_or(super::buffer_backend::BackendOverflow {
tail: self.tail,
requested: fill_length,
capacity: self.slice.len(),
})?;
if new_tail > self.slice.len() {
return Err(super::buffer_backend::BackendOverflow {
tail: self.tail,
requested: fill_length,
capacity: self.slice.len(),
});
}
self.slice[self.tail..new_tail].fill(fill_with);
self.tail = new_tail;
Ok(())
}
#[inline(always)]
fn try_extend_from_within(
&mut self,
start: usize,
len: usize,
) -> Result<(), super::buffer_backend::BackendOverflow> {
let abs_start =
self.head
.checked_add(start)
.ok_or(super::buffer_backend::BackendOverflow {
tail: self.tail,
requested: len,
capacity: self.slice.len(),
})?;
let abs_end = abs_start
.checked_add(len)
.ok_or(super::buffer_backend::BackendOverflow {
tail: self.tail,
requested: len,
capacity: self.slice.len(),
})?;
if abs_end > self.tail {
return Err(super::buffer_backend::BackendOverflow {
tail: self.tail,
requested: len,
capacity: self.slice.len(),
});
}
let new_tail =
self.tail
.checked_add(len)
.ok_or(super::buffer_backend::BackendOverflow {
tail: self.tail,
requested: len,
capacity: self.slice.len(),
})?;
if new_tail > self.slice.len() {
return Err(super::buffer_backend::BackendOverflow {
tail: self.tail,
requested: len,
capacity: self.slice.len(),
});
}
unsafe { self.extend_from_within_unchecked(start, len) };
Ok(())
}
}
const _: () = {
let _: usize = WILDCOPY_OVERLENGTH;
};
#[cfg(test)]
mod tests {
extern crate alloc;
use super::*;
use alloc::vec;
#[cfg(target_arch = "x86_64")]
use alloc::vec::Vec;
#[test]
fn extend_writes_at_tail() {
let mut buf = vec![0u8; 32];
let mut b = UserSliceBackend::from_slice(&mut buf);
b.extend(&[1, 2, 3, 4]);
assert_eq!(b.len(), 4);
assert_eq!(b.tail(), 4);
b.extend(&[5, 6]);
let (s, t) = b.as_slices();
assert_eq!(s, &[1, 2, 3, 4, 5, 6]);
assert!(t.is_empty());
}
#[test]
fn extend_and_fill_repeats_byte() {
let mut buf = vec![0u8; 16];
let mut b = UserSliceBackend::from_slice(&mut buf);
b.extend(&[0xAA]);
b.extend_and_fill(0xBB, 4);
let (s, _) = b.as_slices();
assert_eq!(s, &[0xAA, 0xBB, 0xBB, 0xBB, 0xBB]);
}
#[test]
fn extend_from_within_unchecked_copies_non_overlapping() {
let mut buf = vec![0u8; 32];
let mut b = UserSliceBackend::from_slice(&mut buf);
b.extend(&[10, 20, 30, 40, 50]);
unsafe { b.extend_from_within_unchecked(0, 3) };
let (s, _) = b.as_slices();
assert_eq!(s, &[10, 20, 30, 40, 50, 10, 20, 30]);
}
#[test]
fn drop_first_n_advances_head_keeps_history() {
let mut buf = vec![0u8; 32];
let mut b = UserSliceBackend::from_slice(&mut buf);
b.extend(&[1, 2, 3, 4, 5]);
b.drop_first_n(2);
assert_eq!(b.len(), 3);
let (s, _) = b.as_slices();
assert_eq!(s, &[3, 4, 5]);
unsafe { b.extend_from_within_unchecked(0, 3) };
let (s, _) = b.as_slices();
assert_eq!(s, &[3, 4, 5, 3, 4, 5]);
}
#[test]
fn set_tail_rollback() {
let mut buf = vec![0u8; 32];
let mut b = UserSliceBackend::from_slice(&mut buf);
b.extend(&[1, 2, 3]);
let saved = b.tail();
b.extend(&[4, 5, 6, 7]);
assert_eq!(b.len(), 7);
unsafe { b.set_tail(saved) };
assert_eq!(b.len(), 3);
let (s, _) = b.as_slices();
assert_eq!(s, &[1, 2, 3]);
}
#[test]
fn clear_resets_cursors() {
let mut buf = vec![0u8; 32];
let mut b = UserSliceBackend::from_slice(&mut buf);
b.extend(&[1, 2, 3]);
b.drop_first_n(1);
b.clear();
assert_eq!(b.len(), 0);
assert_eq!(b.tail(), 0);
}
#[test]
fn extend_from_reader_into_slice() {
let mut buf = vec![0u8; 16];
let mut b = UserSliceBackend::from_slice(&mut buf);
let src = [9u8, 8, 7, 6, 5];
b.extend_from_reader(&src[..], 5).unwrap();
let (s, _) = b.as_slices();
assert_eq!(s, &[9, 8, 7, 6, 5]);
}
#[test]
fn extend_from_reader_over_capacity_errors() {
let mut buf = vec![0u8; 4];
let mut b = UserSliceBackend::from_slice(&mut buf);
let src = [9u8, 8, 7, 6, 5];
assert!(b.extend_from_reader(&src[..], 5).is_err());
assert_eq!(b.tail(), 0);
}
use super::super::buffer_backend::BufferBackend;
#[test]
fn try_extend_exact_fit_succeeds_and_advances_tail() {
let mut buf = vec![0u8; 4];
let mut b = UserSliceBackend::from_slice(&mut buf);
assert!(b.try_extend(&[1, 2, 3, 4]).is_ok());
assert_eq!(b.tail(), 4);
let (s, _) = b.as_slices();
assert_eq!(s, &[1, 2, 3, 4]);
}
#[test]
fn try_extend_over_capacity_returns_overflow_and_keeps_tail() {
let mut buf = vec![0u8; 4];
let mut b = UserSliceBackend::from_slice(&mut buf);
let err = b.try_extend(&[1, 2, 3, 4, 5]).unwrap_err();
assert_eq!(err.tail, 0);
assert_eq!(err.requested, 5);
assert_eq!(err.capacity, 4);
assert_eq!(b.tail(), 0);
}
#[test]
fn try_extend_partially_full_overshoot_reports_current_tail() {
let mut buf = vec![0u8; 4];
let mut b = UserSliceBackend::from_slice(&mut buf);
b.extend(&[1, 2]);
let err = b.try_extend(&[3, 4, 5]).unwrap_err();
assert_eq!(err.tail, 2);
assert_eq!(err.requested, 3);
assert_eq!(err.capacity, 4);
assert_eq!(b.tail(), 2);
}
#[test]
fn try_extend_zero_length_succeeds_and_leaves_tail_unchanged() {
let mut buf = vec![0u8; 8];
let mut b = UserSliceBackend::from_slice(&mut buf);
assert!(b.try_extend(&[]).is_ok());
assert_eq!(b.tail(), 0);
b.extend(&[1, 2, 3]);
assert!(b.try_extend(&[]).is_ok());
assert_eq!(b.tail(), 3);
}
#[test]
fn try_extend_and_fill_exact_fit_writes_pattern() {
let mut buf = vec![0u8; 4];
let mut b = UserSliceBackend::from_slice(&mut buf);
assert!(b.try_extend_and_fill(0xAB, 4).is_ok());
assert_eq!(b.tail(), 4);
let (s, _) = b.as_slices();
assert_eq!(s, &[0xAB, 0xAB, 0xAB, 0xAB]);
}
#[test]
fn try_extend_and_fill_over_capacity_returns_overflow() {
let mut buf = vec![0u8; 4];
let mut b = UserSliceBackend::from_slice(&mut buf);
b.extend(&[1, 2]);
let err = b.try_extend_and_fill(0xCD, 5).unwrap_err();
assert_eq!(err.tail, 2);
assert_eq!(err.requested, 5);
assert_eq!(err.capacity, 4);
assert_eq!(b.tail(), 2);
}
#[test]
fn try_extend_from_within_within_bounds_repeats_history() {
let mut buf = vec![0u8; 8];
let mut b = UserSliceBackend::from_slice(&mut buf);
b.extend(&[1, 2, 3]);
assert!(b.try_extend_from_within(0, 3).is_ok());
let (s, _) = b.as_slices();
assert_eq!(s, &[1, 2, 3, 1, 2, 3]);
assert_eq!(b.tail(), 6);
}
#[test]
fn try_extend_from_within_source_past_tail_returns_overflow() {
let mut buf = vec![0u8; 8];
let mut b = UserSliceBackend::from_slice(&mut buf);
b.extend(&[1, 2]);
let err = b.try_extend_from_within(0, 5).unwrap_err();
assert_eq!(err.tail, 2);
assert_eq!(err.requested, 5);
assert_eq!(b.tail(), 2);
}
#[test]
fn try_extend_from_within_destination_overflow_returns_err() {
let mut buf = vec![0u8; 4];
let mut b = UserSliceBackend::from_slice(&mut buf);
b.extend(&[1, 2, 3]);
let err = b.try_extend_from_within(0, 2).unwrap_err();
assert_eq!(err.tail, 3);
assert_eq!(err.requested, 2);
assert_eq!(err.capacity, 4);
assert_eq!(b.tail(), 3);
}
#[cfg(target_arch = "x86_64")]
#[test]
fn exec_sequence_inline_short_literal_plus_long_offset_match() {
const WILDCOPY: usize = super::super::buffer_backend::WILDCOPY_OVERLENGTH;
let mut buf = vec![0u8; 256 + WILDCOPY];
for (i, slot) in buf.iter_mut().take(32).enumerate() {
*slot = i as u8;
}
let mut b = UserSliceBackend::from_slice(&mut buf);
b.tail = 32;
let lits: [u8; 16] = [
0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF, 0x11, 0x22, 0xA1, 0xB1, 0xC1, 0xD1, 0xE1, 0xF1,
0x10, 0x20,
];
unsafe {
b.exec_sequence_inline(lits.as_ptr(), 8, 16, 8).unwrap();
}
assert_eq!(b.tail, 48);
assert_eq!(&buf[32..40], &lits[..8]);
assert_eq!(&buf[40..48], &[24u8, 25, 26, 27, 28, 29, 30, 31]);
}
#[cfg(target_arch = "x86_64")]
#[test]
fn exec_sequence_inline_long_literal_uses_wildcopy_tail() {
const WILDCOPY: usize = super::super::buffer_backend::WILDCOPY_OVERLENGTH;
let mut buf = vec![0u8; 256 + WILDCOPY];
for (i, slot) in buf.iter_mut().take(32).enumerate() {
*slot = i as u8;
}
let mut b = UserSliceBackend::from_slice(&mut buf);
b.tail = 32;
let lits: Vec<u8> = (0..40 + 16).map(|i| 0x80 + i as u8).collect();
unsafe {
b.exec_sequence_inline(lits.as_ptr(), 40, 16, 8).unwrap();
}
assert_eq!(b.tail, 80);
assert_eq!(&buf[32..72], &lits[..40]);
assert_eq!(&buf[72..80], &lits[24..32]);
}
#[cfg(target_arch = "x86_64")]
#[test]
fn exec_sequence_inline_short_offset_match_uses_overlap_copy() {
const WILDCOPY: usize = super::super::buffer_backend::WILDCOPY_OVERLENGTH;
let mut buf = vec![0u8; 256 + WILDCOPY];
let seed = [0xC0, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7];
buf[24..32].copy_from_slice(&seed);
let mut b = UserSliceBackend::from_slice(&mut buf);
b.tail = 32;
let lits: [u8; 16] = [0xFF; 16];
unsafe {
b.exec_sequence_inline(lits.as_ptr(), 4, 8, 12).unwrap();
}
assert_eq!(b.tail, 48);
assert_eq!(&buf[32..36], &lits[..4]);
assert_eq!(&buf[36..40], &seed[4..8]);
}
}