use std::fmt;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum OperationType {
Pack,
Unpack,
}
impl fmt::Display for OperationType {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
OperationType::Pack => write!(f, "Pack"),
OperationType::Unpack => write!(f, "Unpack"),
}
}
}
#[derive(Debug, Clone)]
pub struct ProgressInfo {
pub processed_bytes: u64,
pub total_bytes: Option<u64>,
pub processed_files: usize,
pub total_files: Option<usize>,
pub current_file: String,
}
impl ProgressInfo {
pub fn overall_progress(&self) -> Option<f64> {
self.total_bytes.map(|total| {
if total == 0 {
0.0
} else {
(self.processed_bytes as f64 / total as f64) * 100.0
}
})
}
pub fn file_progress(&self) -> Option<f64> {
self.total_files.map(|total| {
if total == 0 {
0.0
} else {
(self.processed_files as f64 / total as f64) * 100.0
}
})
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum ControlAction {
Continue,
Abort,
}
#[derive(Debug, Clone)]
pub enum ArchiveError {
IoError(String),
FormatError(String),
NotFound(String),
CompressionError(String),
PermissionDenied(String),
Other(String),
}
impl fmt::Display for ArchiveError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
ArchiveError::IoError(msg) => write!(f, "I/O Error: {}", msg),
ArchiveError::FormatError(msg) => write!(f, "Format Error: {}", msg),
ArchiveError::NotFound(msg) => write!(f, "Not Found: {}", msg),
ArchiveError::CompressionError(msg) => write!(f, "Compression Error: {}", msg),
ArchiveError::PermissionDenied(msg) => write!(f, "Permission Denied: {}", msg),
ArchiveError::Other(msg) => write!(f, "Error: {}", msg),
}
}
}
impl std::error::Error for ArchiveError {}
#[derive(Debug, Clone)]
pub enum ArchiveEvent {
Started(OperationType),
EntryStarted(String),
Progress(ProgressInfo),
EntryFinished(String),
Warning(String),
Finished,
}
impl fmt::Display for ArchiveEvent {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
ArchiveEvent::Started(op) => write!(f, "Started: {}", op),
ArchiveEvent::EntryStarted(name) => write!(f, "Entry Started: {}", name),
ArchiveEvent::Progress(info) => {
write!(
f,
"Progress: {} ({}/",
info.current_file, info.processed_files
)?;
if let Some(total) = info.total_files {
write!(f, "{}", total)?;
} else {
write!(f, "?")?;
}
write!(f, " files, {} bytes", info.processed_bytes)?;
if let Some(total) = info.total_bytes {
write!(f, "/{} bytes", total)?;
}
write!(f, ")")
}
ArchiveEvent::EntryFinished(name) => write!(f, "Entry Finished: {}", name),
ArchiveEvent::Warning(msg) => write!(f, "Warning: {}", msg),
ArchiveEvent::Finished => write!(f, "Finished"),
}
}
}
pub trait ArchiveHandler: Send {
#[allow(unused_variables)]
fn on_started(&mut self, op_type: OperationType) -> ControlAction {
ControlAction::Continue
}
#[allow(unused_variables)]
fn on_entry_started(&mut self, name: &str) -> ControlAction {
ControlAction::Continue
}
#[allow(unused_variables)]
fn on_progress(&mut self, info: &ProgressInfo) -> ControlAction {
ControlAction::Continue
}
#[allow(unused_variables)]
fn on_entry_finished(&mut self, name: &str) -> ControlAction {
ControlAction::Continue
}
#[allow(unused_variables)]
fn on_warning(&mut self, message: &str) -> ControlAction {
ControlAction::Continue
}
fn on_finished(&mut self) -> ControlAction {
ControlAction::Continue
}
#[doc(hidden)]
fn on_event(&mut self, event: &ArchiveEvent) -> ControlAction {
match event {
ArchiveEvent::Started(op_type) => self.on_started(*op_type),
ArchiveEvent::EntryStarted(name) => self.on_entry_started(name),
ArchiveEvent::Progress(info) => self.on_progress(info),
ArchiveEvent::EntryFinished(name) => self.on_entry_finished(name),
ArchiveEvent::Warning(msg) => self.on_warning(msg),
ArchiveEvent::Finished => self.on_finished(),
}
}
}
pub struct NoOpHandler;
impl ArchiveHandler for NoOpHandler {
fn on_event(&mut self, _event: &ArchiveEvent) -> ControlAction {
ControlAction::Continue
}
}