#![forbid(unsafe_code)]
#![doc = include_str!("../README.md")]
use core::fmt;
#[derive(Clone, Copy, Debug, Default, Eq, Hash, Ord, PartialEq, PartialOrd)]
pub enum ArchiveEntryKind {
#[default]
File,
Directory,
Symlink,
Hardlink,
Device,
Fifo,
Unknown,
}
impl ArchiveEntryKind {
#[must_use]
pub const fn as_str(self) -> &'static str {
match self {
Self::File => "file",
Self::Directory => "directory",
Self::Symlink => "symlink",
Self::Hardlink => "hardlink",
Self::Device => "device",
Self::Fifo => "fifo",
Self::Unknown => "unknown",
}
}
#[must_use]
pub const fn is_link(self) -> bool {
matches!(self, Self::Symlink | Self::Hardlink)
}
}
impl fmt::Display for ArchiveEntryKind {
fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
formatter.write_str(self.as_str())
}
}
#[derive(Clone, Debug, Eq, Hash, PartialEq)]
pub struct ArchiveEntry {
pub path: String,
pub kind: ArchiveEntryKind,
pub size: Option<u64>,
pub mode: Option<u32>,
pub modified_unix_seconds: Option<i64>,
}
impl ArchiveEntry {
#[must_use]
pub fn new(path: impl Into<String>, kind: ArchiveEntryKind) -> Self {
Self {
path: path.into(),
kind,
size: None,
mode: None,
modified_unix_seconds: None,
}
}
#[must_use]
pub fn file(path: impl Into<String>) -> Self {
Self::new(path, ArchiveEntryKind::File)
}
#[must_use]
pub fn directory(path: impl Into<String>) -> Self {
Self::new(path, ArchiveEntryKind::Directory)
}
#[must_use]
pub fn symlink(path: impl Into<String>) -> Self {
Self::new(path, ArchiveEntryKind::Symlink)
}
#[must_use]
pub const fn with_size(mut self, size: u64) -> Self {
self.size = Some(size);
self
}
#[must_use]
pub const fn with_mode(mut self, mode: u32) -> Self {
self.mode = Some(mode);
self
}
#[must_use]
pub const fn with_modified_unix_seconds(mut self, seconds: i64) -> Self {
self.modified_unix_seconds = Some(seconds);
self
}
#[must_use]
pub fn path(&self) -> &str {
&self.path
}
#[must_use]
pub const fn kind(&self) -> ArchiveEntryKind {
self.kind
}
#[must_use]
pub const fn size(&self) -> Option<u64> {
self.size
}
#[must_use]
pub const fn mode(&self) -> Option<u32> {
self.mode
}
#[must_use]
pub const fn modified_unix_seconds(&self) -> Option<i64> {
self.modified_unix_seconds
}
#[must_use]
pub const fn is_file(&self) -> bool {
matches!(self.kind, ArchiveEntryKind::File)
}
#[must_use]
pub const fn is_directory(&self) -> bool {
matches!(self.kind, ArchiveEntryKind::Directory)
}
#[must_use]
pub const fn is_symlink(&self) -> bool {
matches!(self.kind, ArchiveEntryKind::Symlink)
}
}
#[cfg(test)]
mod tests {
use super::{ArchiveEntry, ArchiveEntryKind};
#[test]
fn creates_file_entry_metadata() {
let entry = ArchiveEntry::file("docs/readme.md")
.with_size(128)
.with_mode(0o644)
.with_modified_unix_seconds(1_700_000_000);
assert_eq!(entry.path(), "docs/readme.md");
assert_eq!(entry.kind(), ArchiveEntryKind::File);
assert_eq!(entry.size(), Some(128));
assert_eq!(entry.mode(), Some(0o644));
assert!(entry.is_file());
}
#[test]
fn identifies_link_like_kinds() {
assert!(ArchiveEntryKind::Symlink.is_link());
assert!(ArchiveEntryKind::Hardlink.is_link());
assert!(!ArchiveEntryKind::Directory.is_link());
}
}