#![forbid(unsafe_code)]
#![doc = include_str!("../README.md")]
use core::fmt;
pub const BZIP2_EXTENSION: &str = "bz2";
pub const TBZ_EXTENSION: &str = "tbz";
pub const TBZ2_EXTENSION: &str = "tbz2";
pub const TAR_BZIP2_EXTENSION: &str = "tar.bz2";
pub const BZIP2_EXTENSIONS: &[&str] = &["bz2", "bzip2", "tbz", "tbz2", "tar.bz2"];
#[derive(Clone, Copy, Debug, Default, Eq, Hash, Ord, PartialEq, PartialOrd)]
pub enum Bzip2Extension {
Bz2,
Tbz,
Tbz2,
TarBz2,
#[default]
Unknown,
}
impl Bzip2Extension {
#[must_use]
pub const fn as_str(self) -> &'static str {
match self {
Self::Bz2 => "bz2",
Self::Tbz => "tbz",
Self::Tbz2 => "tbz2",
Self::TarBz2 => "tar.bz2",
Self::Unknown => "unknown",
}
}
#[must_use]
pub fn from_extension(extension: &str) -> Self {
match normalize_extension(extension).as_str() {
"bz2" | "bzip2" => Self::Bz2,
"tbz" => Self::Tbz,
"tbz2" => Self::Tbz2,
"tar.bz2" | "tar.bzip2" => Self::TarBz2,
_ => Self::Unknown,
}
}
}
impl fmt::Display for Bzip2Extension {
fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
formatter.write_str(self.as_str())
}
}
#[derive(Clone, Copy, Debug, Default, Eq, Hash, Ord, PartialEq, PartialOrd)]
pub enum Bzip2Level {
Fastest,
#[default]
Balanced,
Best,
Numeric(u32),
Unknown,
}
impl Bzip2Level {
#[must_use]
pub const fn as_str(self) -> &'static str {
match self {
Self::Fastest => "fastest",
Self::Balanced => "balanced",
Self::Best => "best",
Self::Numeric(_) => "numeric",
Self::Unknown => "unknown",
}
}
#[must_use]
pub const fn numeric(self) -> Option<u32> {
match self {
Self::Numeric(level) => Some(level),
Self::Fastest | Self::Balanced | Self::Best | Self::Unknown => None,
}
}
}
#[derive(Clone, Copy, Debug, Default, Eq, Hash, Ord, PartialEq, PartialOrd)]
pub enum Bzip2Profile {
Speed,
Size,
#[default]
Balanced,
Compatibility,
Unknown,
}
impl Bzip2Profile {
#[must_use]
pub const fn as_str(self) -> &'static str {
match self {
Self::Speed => "speed",
Self::Size => "size",
Self::Balanced => "balanced",
Self::Compatibility => "compatibility",
Self::Unknown => "unknown",
}
}
}
#[must_use]
pub fn is_bzip2_extension(extension: &str) -> bool {
!matches!(
Bzip2Extension::from_extension(extension),
Bzip2Extension::Unknown
)
}
#[must_use]
pub fn is_bzip2_filename(name: &str) -> bool {
let parts = filename_parts(name);
match parts.as_slice() {
[.., last] if matches!(last.as_str(), "bz2" | "bzip2" | "tbz" | "tbz2") => true,
[.., previous, last] if previous == "tar" && matches!(last.as_str(), "bz2" | "bzip2") => {
true
},
_ => false,
}
}
fn normalize_extension(extension: &str) -> String {
extension
.trim()
.trim_start_matches('.')
.to_ascii_lowercase()
}
fn filename_parts(name: &str) -> Vec<String> {
name.trim()
.to_ascii_lowercase()
.rsplit(['/', '\\'])
.next()
.unwrap_or_default()
.trim_start_matches('.')
.split('.')
.filter(|part| !part.is_empty())
.map(str::to_owned)
.collect()
}
#[cfg(test)]
mod tests {
use super::{
BZIP2_EXTENSIONS, Bzip2Extension, Bzip2Level, Bzip2Profile, is_bzip2_extension,
is_bzip2_filename,
};
#[test]
fn detects_bzip2_extensions() {
assert!(is_bzip2_extension(".bz2"));
assert!(is_bzip2_extension("tar.bz2"));
assert_eq!(Bzip2Extension::from_extension("tbz2"), Bzip2Extension::Tbz2);
assert_eq!(BZIP2_EXTENSIONS[0], "bz2");
}
#[test]
fn detects_bzip2_filenames() {
assert!(is_bzip2_filename("release.tar.bz2"));
assert!(is_bzip2_filename("bundle.TBZ2"));
assert!(!is_bzip2_filename("bundle.zip"));
}
#[test]
fn exposes_default_and_unknown_labels() {
assert_eq!(Bzip2Extension::default(), Bzip2Extension::Unknown);
assert_eq!(Bzip2Level::default().as_str(), "balanced");
assert_eq!(Bzip2Level::Numeric(9).numeric(), Some(9));
assert_eq!(Bzip2Profile::Unknown.as_str(), "unknown");
}
}