use crate::crypto::DEFAULT_CHUNK_SIZE;
use crate::error::Result;
use crate::progress::ProgressCallback;
use std::io::{self, Seek, Write};
pub struct Compressor<W: Write + Seek> {
destination: W,
#[allow(dead_code)]
filename: String,
#[allow(dead_code)]
password: Option<String>,
chunk_size: usize,
progress_callback: Option<ProgressCallback>,
finished: bool,
bytes_written: u64,
}
impl<W: Write + Seek> Compressor<W> {
pub fn new(destination: W, filename: &str, password: Option<&str>) -> Self {
Self {
destination,
filename: filename.to_string(),
password: password.map(|p| p.to_string()),
chunk_size: DEFAULT_CHUNK_SIZE,
progress_callback: None,
finished: false,
bytes_written: 0,
}
}
pub fn with_chunk_size(mut self, chunk_size: usize) -> Self {
self.chunk_size = chunk_size;
self
}
pub fn with_progress_callback<F>(mut self, callback: F) -> Self
where
F: FnMut(&crate::progress::ProgressInfo) + Send + Sync + 'static,
{
self.progress_callback = Some(Box::new(callback));
self
}
pub fn bytes_written(&self) -> u64 {
self.bytes_written
}
pub fn is_finished(&self) -> bool {
self.finished
}
pub fn finish(&mut self) -> Result<()> {
if self.finished {
return Ok(());
}
println!("Compressor::finish() not yet fully implemented");
self.finished = true;
Ok(())
}
}
impl<W: Write + Seek> Write for Compressor<W> {
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
if self.finished {
return Err(io::Error::other("Cannot write to finished compressor"));
}
println!(
"Compressor::write() not yet fully implemented - buffering {} bytes",
buf.len()
);
let bytes_written = self.destination.write(buf)?;
self.bytes_written += bytes_written as u64;
Ok(bytes_written)
}
fn flush(&mut self) -> io::Result<()> {
self.destination.flush()
}
}
#[cfg(test)]
mod tests {
use super::*;
use std::io::{Cursor, Write};
#[test]
fn test_compressor_creation() {
let cursor = Cursor::new(Vec::new());
let compressor = Compressor::new(cursor, "test.txt", None);
assert_eq!(compressor.filename, "test.txt");
assert!(compressor.password.is_none());
assert_eq!(compressor.chunk_size, DEFAULT_CHUNK_SIZE);
assert!(!compressor.is_finished());
assert_eq!(compressor.bytes_written(), 0);
}
#[test]
fn test_compressor_builder_pattern() {
let cursor = Cursor::new(Vec::new());
let compressor = Compressor::new(cursor, "test.txt", None)
.with_chunk_size(1024 * 1024)
.with_progress_callback(|_| {});
assert_eq!(compressor.chunk_size, 1024 * 1024);
assert!(compressor.progress_callback.is_some());
}
#[test]
fn test_compressor_write_operations() {
let cursor = Cursor::new(Vec::new());
let mut compressor = Compressor::new(cursor, "test.txt", None);
compressor.write_all(b"Hello, world!").unwrap();
assert_eq!(compressor.bytes_written(), 13);
}
#[test]
fn test_compressor_finish() {
let cursor = Cursor::new(Vec::new());
let mut compressor = Compressor::new(cursor, "test.txt", None);
assert!(!compressor.is_finished());
compressor.finish().unwrap();
assert!(compressor.is_finished());
}
#[test]
fn test_compressor_write_after_finish() {
let cursor = Cursor::new(Vec::new());
let mut compressor = Compressor::new(cursor, "test.txt", None);
compressor.finish().unwrap();
let result = compressor.write_all(b"more data");
assert!(result.is_err());
}
}