use std::io::{self, Read, Write, IoSlice, IoSliceMut};
use crate::error::{Result, ZiporaError};
use crate::memory::SecureMemoryPool;
use crate::io::simd_validation::checksum;
use std::sync::Arc;
pub trait ZeroCopyRead {
fn zc_read(&mut self, len: usize) -> Result<Option<&[u8]>>;
fn zc_advance(&mut self, len: usize) -> Result<()>;
fn zc_available(&self) -> usize;
fn zc_ensure(&mut self, len: usize) -> Result<usize>;
}
pub trait ZeroCopyWrite {
fn zc_write(&mut self, len: usize) -> Result<Option<&mut [u8]>>;
fn zc_commit(&mut self, len: usize) -> Result<()>;
fn zc_write_available(&self) -> usize;
fn zc_ensure_write(&mut self, len: usize) -> Result<usize>;
}
pub struct ZeroCopyBuffer {
buffer: Vec<u8>,
read_pos: usize,
write_pos: usize,
pool: Option<Arc<SecureMemoryPool>>,
}
impl ZeroCopyBuffer {
pub fn new(capacity: usize) -> Result<Self> {
Self::with_pool(capacity, None)
}
pub fn with_secure_pool(capacity: usize) -> Result<Self> {
let pool = SecureMemoryPool::new(
crate::memory::SecurePoolConfig::small_secure()
)?;
Self::with_pool(capacity, Some(pool))
}
fn with_pool(capacity: usize, pool: Option<Arc<SecureMemoryPool>>) -> Result<Self> {
Ok(Self {
buffer: vec![0u8; capacity],
read_pos: 0,
write_pos: 0,
pool,
})
}
#[inline]
pub fn capacity(&self) -> usize {
self.buffer.len()
}
pub fn available(&self) -> usize {
self.write_pos - self.read_pos
}
pub fn write_available(&self) -> usize {
self.buffer.len() - self.write_pos
}
pub fn read_position(&self) -> usize {
self.read_pos
}
pub fn write_position(&self) -> usize {
self.write_pos
}
#[inline]
pub fn is_empty(&self) -> bool {
self.read_pos == self.write_pos
}
#[inline]
pub fn is_full(&self) -> bool {
self.write_pos == self.buffer.len()
}
pub fn reset(&mut self) {
self.read_pos = 0;
self.write_pos = 0;
}
pub fn compact(&mut self) {
if self.read_pos > 0 {
let available = self.available();
if available > 0 {
self.buffer.copy_within(self.read_pos..self.write_pos, 0);
}
self.read_pos = 0;
self.write_pos = available;
}
}
pub fn readable_slice(&self) -> &[u8] {
&self.buffer[self.read_pos..self.write_pos]
}
pub fn writable_slice(&mut self) -> &mut [u8] {
&mut self.buffer[self.write_pos..]
}
pub fn fill_from<R: Read>(&mut self, reader: &mut R) -> Result<usize> {
if self.is_full() {
self.compact();
}
let writable = self.writable_slice();
if writable.is_empty() {
return Ok(0);
}
let bytes_read = reader.read(writable)
.map_err(|e| ZiporaError::io_error(format!("Failed to fill buffer: {}", e)))?;
self.write_pos += bytes_read;
Ok(bytes_read)
}
pub fn drain_to<W: Write>(&mut self, writer: &mut W) -> Result<usize> {
let readable = self.readable_slice();
if readable.is_empty() {
return Ok(0);
}
let bytes_written = writer.write(readable)
.map_err(|e| ZiporaError::io_error(format!("Failed to drain buffer: {}", e)))?;
self.read_pos += bytes_written;
Ok(bytes_written)
}
}
impl ZeroCopyRead for ZeroCopyBuffer {
fn zc_read(&mut self, len: usize) -> Result<Option<&[u8]>> {
if self.available() >= len {
Ok(Some(&self.buffer[self.read_pos..self.read_pos + len]))
} else {
Ok(None)
}
}
fn zc_advance(&mut self, len: usize) -> Result<()> {
if self.read_pos + len > self.write_pos {
return Err(ZiporaError::invalid_data("Cannot advance past available data"));
}
self.read_pos += len;
Ok(())
}
fn zc_available(&self) -> usize {
self.available()
}
fn zc_ensure(&mut self, len: usize) -> Result<usize> {
Ok(self.available().min(len))
}
}
impl ZeroCopyWrite for ZeroCopyBuffer {
fn zc_write(&mut self, len: usize) -> Result<Option<&mut [u8]>> {
if self.write_available() >= len {
Ok(Some(&mut self.buffer[self.write_pos..self.write_pos + len]))
} else {
Ok(None)
}
}
fn zc_commit(&mut self, len: usize) -> Result<()> {
if self.write_pos + len > self.buffer.len() {
return Err(ZiporaError::invalid_data("Cannot commit past buffer capacity"));
}
self.write_pos += len;
Ok(())
}
fn zc_write_available(&self) -> usize {
self.write_available()
}
fn zc_ensure_write(&mut self, len: usize) -> Result<usize> {
if self.write_available() < len {
self.compact();
}
Ok(self.write_available().min(len))
}
}
pub struct ZeroCopyReader<R> {
inner: R,
buffer: ZeroCopyBuffer,
eof: bool,
}
impl<R: Read> ZeroCopyReader<R> {
pub fn new(inner: R) -> Result<Self> {
Self::with_capacity(inner, 64 * 1024)
}
pub fn with_capacity(inner: R, capacity: usize) -> Result<Self> {
Ok(Self {
inner,
buffer: ZeroCopyBuffer::new(capacity)?,
eof: false,
})
}
pub fn with_secure_buffer(inner: R, capacity: usize) -> Result<Self> {
Ok(Self {
inner,
buffer: ZeroCopyBuffer::with_secure_pool(capacity)?,
eof: false,
})
}
pub fn get_ref(&self) -> &R {
&self.inner
}
pub fn get_mut(&mut self) -> &mut R {
&mut self.inner
}
pub fn into_inner(self) -> R {
self.inner
}
fn ensure_buffered(&mut self, len: usize) -> Result<()> {
while self.buffer.available() < len && !self.eof {
let bytes_read = self.buffer.fill_from(&mut self.inner)
.map_err(|e| ZiporaError::io_error(format!("Fill buffer failed: {}", e)))?;
if bytes_read == 0 {
self.eof = true;
break;
}
}
Ok(())
}
pub fn read_optimized(&mut self, buf: &mut [u8]) -> Result<usize> {
if let Some(zc_data) = self.zc_read(buf.len())? {
let len = zc_data.len();
buf[..len].copy_from_slice(zc_data);
self.zc_advance(len)?;
return Ok(len);
}
self.read(buf).map_err(|e| ZiporaError::io_error(format!("Read failed: {}", e)))
}
pub fn peek(&mut self, len: usize) -> Result<&[u8]> {
self.ensure_buffered(len)?;
let available = self.buffer.available().min(len);
Ok(&self.buffer.readable_slice()[..available])
}
pub fn skip_bytes(&mut self, mut len: usize) -> Result<()> {
let buffered = self.buffer.available().min(len);
if buffered > 0 {
self.buffer.zc_advance(buffered)?;
len -= buffered;
}
let mut temp_buf = vec![0u8; 8192];
while len > 0 {
let to_skip = len.min(temp_buf.len());
let bytes_read = self.inner.read(&mut temp_buf[..to_skip])
.map_err(|e| ZiporaError::io_error(format!("Failed to skip bytes: {}", e)))?;
if bytes_read == 0 {
return Err(ZiporaError::io_error("Unexpected end of stream while skipping"));
}
len -= bytes_read;
}
Ok(())
}
pub fn validate_utf8_buffer(&self) -> Result<bool> {
let buffered_data = self.buffer.readable_slice();
if buffered_data.is_empty() {
return Ok(true);
}
Ok(std::str::from_utf8(buffered_data).is_ok())
}
pub fn checksum_buffer_crc32c(&self) -> Result<u32> {
let buffered_data = self.buffer.readable_slice();
if buffered_data.is_empty() {
return Ok(0xFFFFFFFF); }
checksum::crc32c_hash(buffered_data)
}
pub fn validate_and_checksum(&self) -> Result<(bool, u32)> {
let buffered_data = self.buffer.readable_slice();
if buffered_data.is_empty() {
return Ok((true, 0xFFFFFFFF));
}
let is_valid = std::str::from_utf8(buffered_data).is_ok();
let crc = checksum::crc32c_hash(buffered_data)?;
Ok((is_valid, crc))
}
}
impl<R: Read> Read for ZeroCopyReader<R> {
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
if buf.is_empty() {
return Ok(0);
}
let buffered = self.buffer.available();
if buffered > 0 {
let to_copy = buffered.min(buf.len());
buf[..to_copy].copy_from_slice(&self.buffer.readable_slice()[..to_copy]);
self.buffer.read_pos += to_copy;
return Ok(to_copy);
}
if buf.len() >= self.buffer.capacity() / 2 {
return self.inner.read(buf);
}
if !self.eof {
let bytes_read = self.buffer.fill_from(&mut self.inner)
.map_err(|e| io::Error::new(io::ErrorKind::Other, e))?;
if bytes_read == 0 {
self.eof = true;
}
}
let available = self.buffer.available();
if available == 0 {
return Ok(0);
}
let to_copy = available.min(buf.len());
buf[..to_copy].copy_from_slice(&self.buffer.readable_slice()[..to_copy]);
self.buffer.read_pos += to_copy;
Ok(to_copy)
}
}
impl<R: Read> ZeroCopyRead for ZeroCopyReader<R> {
fn zc_read(&mut self, len: usize) -> Result<Option<&[u8]>> {
self.ensure_buffered(len)?;
self.buffer.zc_read(len)
}
fn zc_advance(&mut self, len: usize) -> Result<()> {
self.buffer.zc_advance(len)
}
fn zc_available(&self) -> usize {
self.buffer.zc_available()
}
fn zc_ensure(&mut self, len: usize) -> Result<usize> {
self.ensure_buffered(len)?;
Ok(self.buffer.available().min(len))
}
}
pub struct ZeroCopyWriter<W> {
inner: W,
buffer: ZeroCopyBuffer,
}
impl<W: Write> ZeroCopyWriter<W> {
pub fn new(inner: W) -> Result<Self> {
Self::with_capacity(inner, 64 * 1024)
}
pub fn with_capacity(inner: W, capacity: usize) -> Result<Self> {
Ok(Self {
inner,
buffer: ZeroCopyBuffer::new(capacity)?,
})
}
pub fn get_ref(&self) -> &W {
&self.inner
}
pub fn get_mut(&mut self) -> &mut W {
&mut self.inner
}
pub fn into_inner(mut self) -> io::Result<W> {
self.flush()?;
Ok(self.inner)
}
fn flush_buffer(&mut self) -> io::Result<()> {
while !self.buffer.is_empty() {
let bytes_written = self.buffer.drain_to(&mut self.inner)
.map_err(|e| io::Error::new(io::ErrorKind::Other, e))?;
if bytes_written == 0 {
return Err(io::Error::new(io::ErrorKind::WriteZero, "Failed to drain buffer completely"));
}
}
self.buffer.reset();
Ok(())
}
}
impl<W: Write> Write for ZeroCopyWriter<W> {
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
if buf.len() >= self.buffer.capacity() / 2 {
self.flush_buffer()?;
return self.inner.write(buf);
}
if self.buffer.write_available() < buf.len() {
self.flush_buffer()?;
}
if self.buffer.write_available() < buf.len() {
return self.inner.write(buf);
}
let writable = self.buffer.writable_slice();
let to_copy = buf.len().min(writable.len());
writable[..to_copy].copy_from_slice(&buf[..to_copy]);
self.buffer.write_pos += to_copy;
Ok(to_copy)
}
fn flush(&mut self) -> io::Result<()> {
self.flush_buffer()?;
self.inner.flush()
}
}
impl<W: Write> ZeroCopyWrite for ZeroCopyWriter<W> {
fn zc_write(&mut self, len: usize) -> Result<Option<&mut [u8]>> {
if self.buffer.write_available() < len {
self.flush_buffer()
.map_err(|e| ZiporaError::io_error(format!("Flush failed: {}", e)))?;
}
self.buffer.zc_write(len)
}
fn zc_commit(&mut self, len: usize) -> Result<()> {
self.buffer.zc_commit(len)
}
fn zc_write_available(&self) -> usize {
self.buffer.zc_write_available()
}
fn zc_ensure_write(&mut self, len: usize) -> Result<usize> {
if self.buffer.write_available() < len {
self.flush_buffer()
.map_err(|e| ZiporaError::io_error(format!("Flush failed: {}", e)))?;
}
Ok(self.buffer.write_available().min(len))
}
}
pub struct VectoredIO;
impl VectoredIO {
pub fn read_vectored<R: Read>(reader: &mut R, bufs: &mut [IoSliceMut<'_>]) -> io::Result<usize> {
let mut total = 0;
for buf in bufs {
if buf.is_empty() {
continue;
}
match reader.read(buf) {
Ok(0) => break,
Ok(n) => total += n,
Err(e) => return if total > 0 { Ok(total) } else { Err(e) },
}
}
Ok(total)
}
pub fn write_vectored<W: Write>(writer: &mut W, bufs: &[IoSlice<'_>]) -> io::Result<usize> {
let mut total = 0;
for buf in bufs {
if buf.is_empty() {
continue;
}
match writer.write(buf) {
Ok(n) => total += n,
Err(e) => return if total > 0 { Ok(total) } else { Err(e) },
}
}
Ok(total)
}
}
#[cfg(feature = "mmap")]
pub mod mmap {
use super::*;
use memmap2::Mmap;
use std::fs::File;
pub struct MmapZeroCopyReader {
mmap: Mmap,
pos: usize,
}
impl MmapZeroCopyReader {
pub fn new(file: File) -> Result<Self> {
let mmap = unsafe {
Mmap::map(&file)
.map_err(|e| ZiporaError::io_error(format!("Failed to memory map file: {}", e)))?
};
Ok(Self { mmap, pos: 0 })
}
#[inline]
pub fn len(&self) -> usize {
self.mmap.len()
}
#[inline]
pub fn is_empty(&self) -> bool {
self.mmap.is_empty()
}
pub fn position(&self) -> usize {
self.pos
}
pub fn set_position(&mut self, pos: usize) -> Result<()> {
if pos > self.mmap.len() {
return Err(ZiporaError::invalid_data("Position beyond mapped region"));
}
self.pos = pos;
Ok(())
}
#[inline]
pub fn as_slice(&self) -> &[u8] {
&self.mmap
}
pub fn remaining_slice(&self) -> &[u8] {
&self.mmap[self.pos..]
}
}
impl ZeroCopyRead for MmapZeroCopyReader {
fn zc_read(&mut self, len: usize) -> Result<Option<&[u8]>> {
if self.pos + len <= self.mmap.len() {
let slice = &self.mmap[self.pos..self.pos + len];
Ok(Some(slice))
} else {
Ok(None)
}
}
fn zc_advance(&mut self, len: usize) -> Result<()> {
if self.pos + len > self.mmap.len() {
return Err(ZiporaError::invalid_data("Cannot advance past mapped region"));
}
self.pos += len;
Ok(())
}
fn zc_available(&self) -> usize {
self.mmap.len() - self.pos
}
fn zc_ensure(&mut self, len: usize) -> Result<usize> {
Ok(self.zc_available().min(len))
}
}
impl Read for MmapZeroCopyReader {
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
let available = self.zc_available();
if available == 0 {
return Ok(0);
}
let to_copy = available.min(buf.len());
buf[..to_copy].copy_from_slice(&self.mmap[self.pos..self.pos + to_copy]);
self.pos += to_copy;
Ok(to_copy)
}
}
}
#[cfg(test)]
mod tests {
use super::*;
use std::io::Cursor;
#[test]
fn test_zero_copy_buffer_basic() {
let mut buffer = ZeroCopyBuffer::new(1024).unwrap();
assert_eq!(buffer.capacity(), 1024);
assert_eq!(buffer.available(), 0);
assert_eq!(buffer.write_available(), 1024);
assert!(buffer.is_empty());
assert!(!buffer.is_full());
}
#[test]
fn test_zero_copy_buffer_zero_capacity() {
let buffer = ZeroCopyBuffer::new(0).unwrap();
assert_eq!(buffer.capacity(), 0);
assert_eq!(buffer.available(), 0);
assert_eq!(buffer.write_available(), 0);
assert!(buffer.is_empty());
assert!(buffer.is_full());
drop(buffer);
}
#[test]
fn test_zero_copy_buffer_zero_capacity_ops() {
let mut buffer = ZeroCopyBuffer::new(0).unwrap();
assert!(buffer.zc_write(1).unwrap().is_none());
assert!(buffer.zc_read(1).unwrap().is_none());
assert_eq!(buffer.zc_advance(0).unwrap(), ());
assert_eq!(buffer.zc_commit(0).unwrap(), ());
buffer.compact(); buffer.reset(); }
#[test]
fn test_zero_copy_buffer_read_write() {
let mut buffer = ZeroCopyBuffer::new(1024).unwrap();
if let Some(write_buf) = buffer.zc_write(5).unwrap() {
write_buf.copy_from_slice(b"hello");
buffer.zc_commit(5).unwrap();
}
assert_eq!(buffer.available(), 5);
assert_eq!(buffer.write_available(), 1019);
if let Some(read_buf) = buffer.zc_read(5).unwrap() {
assert_eq!(read_buf, b"hello");
buffer.zc_advance(5).unwrap();
}
assert_eq!(buffer.available(), 0);
assert!(buffer.is_empty());
}
#[test]
fn test_zero_copy_buffer_compact() {
let mut buffer = ZeroCopyBuffer::new(10).unwrap();
if let Some(write_buf) = buffer.zc_write(10).unwrap() {
write_buf.copy_from_slice(b"0123456789");
buffer.zc_commit(10).unwrap();
}
buffer.zc_advance(5).unwrap();
assert_eq!(buffer.available(), 5);
assert_eq!(buffer.write_available(), 0);
buffer.compact();
assert_eq!(buffer.available(), 5);
assert_eq!(buffer.write_available(), 5);
assert_eq!(buffer.readable_slice(), b"56789");
}
#[test]
fn test_zero_copy_reader() {
let data = b"Hello, World! This is a test of zero-copy reading.";
let cursor = Cursor::new(data);
let mut reader = ZeroCopyReader::new(cursor).unwrap();
if let Some(zc_data) = reader.zc_read(5).unwrap() {
assert_eq!(zc_data, b"Hello");
reader.zc_advance(5).unwrap();
}
let peeked = reader.peek(7).unwrap();
assert_eq!(peeked, b", World");
let mut buf = [0u8; 7];
reader.read_exact(&mut buf).unwrap();
assert_eq!(&buf, b", World");
}
#[test]
fn test_zero_copy_writer() {
let mut buffer = Vec::new();
{
let cursor = Cursor::new(&mut buffer);
let mut writer = ZeroCopyWriter::new(cursor).unwrap();
if let Some(zc_buf) = writer.zc_write(5).unwrap() {
zc_buf.copy_from_slice(b"Hello");
writer.zc_commit(5).unwrap();
}
writer.write_all(b", World!").unwrap();
writer.flush().unwrap();
}
assert_eq!(buffer, b"Hello, World!");
}
#[test]
fn test_zero_copy_reader_skip() {
let data = b"Hello, World! This is a test.";
let cursor = Cursor::new(data);
let mut reader = ZeroCopyReader::new(cursor).unwrap();
reader.skip_bytes(7).unwrap();
let mut buf = [0u8; 5];
reader.read_exact(&mut buf).unwrap();
assert_eq!(&buf, b"World");
}
#[test]
fn test_vectored_io() {
let data = b"Hello, World!";
let mut cursor = Cursor::new(data);
let mut buf1 = [0u8; 5];
let mut buf2 = [0u8; 2];
let mut buf3 = [0u8; 6];
let mut bufs = [
IoSliceMut::new(&mut buf1),
IoSliceMut::new(&mut buf2),
IoSliceMut::new(&mut buf3),
];
let bytes_read = VectoredIO::read_vectored(&mut cursor, &mut bufs).unwrap();
assert_eq!(bytes_read, 13);
assert_eq!(&buf1, b"Hello");
assert_eq!(&buf2, b", ");
assert_eq!(&buf3, b"World!");
}
#[test]
fn test_zero_copy_round_trip() {
let original_data = b"The quick brown fox jumps over the lazy dog.";
let mut buffer = Vec::new();
{
let cursor = Cursor::new(&mut buffer);
let mut writer = ZeroCopyWriter::new(cursor).unwrap();
writer.write_all(original_data).unwrap();
writer.flush().unwrap();
}
let cursor = Cursor::new(&buffer);
let mut reader = ZeroCopyReader::new(cursor).unwrap();
let mut read_data = Vec::new();
reader.read_to_end(&mut read_data).unwrap();
assert_eq!(read_data, original_data);
}
#[test]
fn test_zero_copy_reader_utf8_validation_valid() {
let data = "Hello, World! Valid UTF-8 text with unicode: δΈη π¦";
let cursor = Cursor::new(data.as_bytes());
let mut reader = ZeroCopyReader::new(cursor).unwrap();
let _ = reader.peek(10).unwrap();
let is_valid = reader.validate_utf8_buffer().unwrap();
assert!(is_valid, "Valid UTF-8 should pass validation");
}
#[test]
fn test_zero_copy_reader_utf8_validation_invalid() {
let mut data = Vec::from(b"Hello, ".as_ref());
data.push(0xFF); data.extend_from_slice(b" World!");
let cursor = Cursor::new(data);
let mut reader = ZeroCopyReader::new(cursor).unwrap();
let _ = reader.peek(10).unwrap();
let is_valid = reader.validate_utf8_buffer().unwrap();
assert!(!is_valid, "Invalid UTF-8 should fail validation");
}
#[test]
fn test_zero_copy_reader_utf8_validation_empty() {
let data = b"";
let cursor = Cursor::new(data);
let reader = ZeroCopyReader::new(cursor).unwrap();
let is_valid = reader.validate_utf8_buffer().unwrap();
assert!(is_valid, "Empty buffer should be valid UTF-8");
}
#[test]
fn test_zero_copy_reader_checksum() {
let data = b"123456789"; let cursor = Cursor::new(data);
let mut reader = ZeroCopyReader::new(cursor).unwrap();
let _ = reader.peek(data.len()).unwrap();
let crc = reader.checksum_buffer_crc32c().unwrap();
assert_eq!(crc, 0xe3069283, "CRC32C checksum mismatch for test vector");
}
#[test]
fn test_zero_copy_reader_checksum_empty() {
let data = b"";
let cursor = Cursor::new(data);
let reader = ZeroCopyReader::new(cursor).unwrap();
let crc = reader.checksum_buffer_crc32c().unwrap();
assert_eq!(crc, 0xFFFFFFFF, "Empty buffer should return initial CRC value");
}
#[test]
fn test_zero_copy_reader_validate_and_checksum() {
let data = "Hello, World! δΈη π¦";
let cursor = Cursor::new(data.as_bytes());
let mut reader = ZeroCopyReader::new(cursor).unwrap();
let _ = reader.peek(10).unwrap();
let (is_valid, crc) = reader.validate_and_checksum().unwrap();
assert!(is_valid, "Valid UTF-8 should pass validation");
assert_ne!(crc, 0, "CRC should be non-zero for non-empty data");
let crc_separate = reader.checksum_buffer_crc32c().unwrap();
assert_eq!(crc, crc_separate, "Combined checksum should match separate checksum");
}
#[test]
fn test_zero_copy_reader_utf8_validation_multibyte() {
let test_cases = vec![
("cafΓ©", true), ("ζ₯ζ¬θͺ", true), ("π¦π", true), ("Hello, δΈη! π¦", true), ];
for (text, expected_valid) in test_cases {
let cursor = Cursor::new(text.as_bytes());
let mut reader = ZeroCopyReader::new(cursor).unwrap();
let _ = reader.peek(text.len()).unwrap();
let is_valid = reader.validate_utf8_buffer().unwrap();
assert_eq!(is_valid, expected_valid, "UTF-8 validation mismatch for: {}", text);
}
}
#[test]
fn test_zero_copy_reader_utf8_validation_after_read() {
let data = "Hello, World! Valid UTF-8 text.";
let cursor = Cursor::new(data.as_bytes());
let mut reader = ZeroCopyReader::new(cursor).unwrap();
let mut buf = [0u8; 7];
reader.read_exact(&mut buf).unwrap();
assert_eq!(&buf, b"Hello, ");
let is_valid = reader.validate_utf8_buffer().unwrap();
assert!(is_valid, "Remaining buffered data should be valid UTF-8");
}
#[test]
fn test_zero_copy_reader_checksum_consistency() {
let data = b"The quick brown fox jumps over the lazy dog";
let cursor = Cursor::new(data);
let mut reader = ZeroCopyReader::new(cursor).unwrap();
let _ = reader.peek(data.len()).unwrap();
let crc1 = reader.checksum_buffer_crc32c().unwrap();
let crc2 = reader.checksum_buffer_crc32c().unwrap();
let crc3 = reader.checksum_buffer_crc32c().unwrap();
assert_eq!(crc1, crc2, "CRC should be consistent");
assert_eq!(crc2, crc3, "CRC should be consistent");
}
#[test]
fn test_zero_copy_reader_large_data_validation() {
let large_text = "Hello, World! δΈη π¦ ".repeat(1000);
let cursor = Cursor::new(large_text.as_bytes());
let mut reader = ZeroCopyReader::new(cursor).unwrap();
let _ = reader.peek(large_text.len()).unwrap();
let is_valid = reader.validate_utf8_buffer().unwrap();
assert!(is_valid, "Large valid UTF-8 buffer should pass validation");
let crc = reader.checksum_buffer_crc32c().unwrap();
assert_ne!(crc, 0, "Large buffer should have non-zero CRC");
}
#[cfg(feature = "mmap")]
#[test]
fn test_mmap_zero_copy_reader() {
use std::io::Write;
use tempfile::NamedTempFile;
let mut temp_file = NamedTempFile::new().unwrap();
let data = b"Hello, memory mapped zero-copy world!";
temp_file.write_all(data).unwrap();
temp_file.flush().unwrap();
let file = temp_file.reopen().unwrap();
let mut reader = mmap::MmapZeroCopyReader::new(file).unwrap();
assert_eq!(reader.len(), data.len());
assert_eq!(reader.as_slice(), data);
if let Some(zc_data) = reader.zc_read(5).unwrap() {
assert_eq!(zc_data, b"Hello");
reader.zc_advance(5).unwrap();
}
assert_eq!(reader.position(), 5);
assert_eq!(reader.remaining_slice(), &data[5..]);
}
}