use std::path::PathBuf;
use std::time::SystemTime;
use crate::formats::detect::ArchiveType;
#[derive(Debug, Clone)]
pub struct ArchiveManifest {
pub entries: Vec<ArchiveEntry>,
pub total_entries: usize,
pub total_size: u64,
pub format: ArchiveType,
}
impl ArchiveManifest {
#[must_use]
pub fn new(format: ArchiveType) -> Self {
Self {
entries: Vec::new(),
total_entries: 0,
total_size: 0,
format,
}
}
pub fn add_entry(&mut self, entry: ArchiveEntry) {
self.total_size += entry.size;
self.total_entries += 1;
self.entries.push(entry);
}
}
#[derive(Debug, Clone)]
pub struct ArchiveEntry {
pub path: PathBuf,
pub entry_type: ManifestEntryType,
pub size: u64,
pub compressed_size: Option<u64>,
pub mode: Option<u32>,
pub modified: Option<SystemTime>,
pub symlink_target: Option<PathBuf>,
pub hardlink_target: Option<PathBuf>,
}
impl ArchiveEntry {
#[must_use]
pub fn compression_ratio(&self) -> Option<f64> {
self.compressed_size
.filter(|&c| c > 0)
.map(|c| self.size as f64 / c as f64)
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum ManifestEntryType {
File,
Directory,
Symlink,
Hardlink,
}
impl std::fmt::Display for ManifestEntryType {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Self::File => write!(f, "File"),
Self::Directory => write!(f, "Directory"),
Self::Symlink => write!(f, "Symlink"),
Self::Hardlink => write!(f, "Hardlink"),
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_manifest_new() {
let manifest = ArchiveManifest::new(ArchiveType::TarGz);
assert_eq!(manifest.total_entries, 0);
assert_eq!(manifest.total_size, 0);
assert_eq!(manifest.entries.len(), 0);
}
#[test]
fn test_manifest_add_entry() {
let mut manifest = ArchiveManifest::new(ArchiveType::TarGz);
let entry = ArchiveEntry {
path: PathBuf::from("file.txt"),
entry_type: ManifestEntryType::File,
size: 1024,
compressed_size: Some(512),
mode: Some(0o644),
modified: None,
symlink_target: None,
hardlink_target: None,
};
manifest.add_entry(entry);
assert_eq!(manifest.total_entries, 1);
assert_eq!(manifest.total_size, 1024);
assert_eq!(manifest.entries.len(), 1);
}
#[test]
fn test_compression_ratio() {
let entry = ArchiveEntry {
path: PathBuf::from("file.txt"),
entry_type: ManifestEntryType::File,
size: 1000,
compressed_size: Some(100),
mode: None,
modified: None,
symlink_target: None,
hardlink_target: None,
};
assert_eq!(entry.compression_ratio(), Some(10.0));
}
#[test]
fn test_compression_ratio_no_compressed() {
let entry = ArchiveEntry {
path: PathBuf::from("file.txt"),
entry_type: ManifestEntryType::File,
size: 1000,
compressed_size: None,
mode: None,
modified: None,
symlink_target: None,
hardlink_target: None,
};
assert_eq!(entry.compression_ratio(), None);
}
#[test]
fn test_manifest_entry_type_display() {
assert_eq!(ManifestEntryType::File.to_string(), "File");
assert_eq!(ManifestEntryType::Directory.to_string(), "Directory");
assert_eq!(ManifestEntryType::Symlink.to_string(), "Symlink");
assert_eq!(ManifestEntryType::Hardlink.to_string(), "Hardlink");
}
}