#![forbid(unsafe_code)]
#![doc = include_str!("../README.md")]
use core::fmt;
pub const AR_STATIC_LIBRARY_EXTENSION: &str = "a";
pub const AR_EXTENSION: &str = "ar";
pub const DEBIAN_PACKAGE_EXTENSION: &str = "deb";
pub const AR_EXTENSIONS: &[&str] = &["a", "ar", "deb"];
#[derive(Clone, Copy, Debug, Default, Eq, Hash, Ord, PartialEq, PartialOrd)]
pub enum ArFormat {
Gnu,
Bsd,
Common,
#[default]
Unknown,
}
impl ArFormat {
#[must_use]
pub const fn as_str(self) -> &'static str {
match self {
Self::Gnu => "gnu",
Self::Bsd => "bsd",
Self::Common => "common",
Self::Unknown => "unknown",
}
}
}
impl fmt::Display for ArFormat {
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 ArEntryKind {
Member,
SymbolTable,
StringTable,
#[default]
Unknown,
}
impl ArEntryKind {
#[must_use]
pub const fn as_str(self) -> &'static str {
match self {
Self::Member => "member",
Self::SymbolTable => "symbol-table",
Self::StringTable => "string-table",
Self::Unknown => "unknown",
}
}
}
impl fmt::Display for ArEntryKind {
fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
formatter.write_str(self.as_str())
}
}
#[must_use]
pub fn is_ar_extension(extension: &str) -> bool {
matches!(normalize_extension(extension).as_str(), "a" | "ar" | "deb")
}
#[must_use]
pub fn is_ar_filename(name: &str) -> bool {
let parts = filename_parts(name);
matches!(parts.as_slice(), [.., last] if matches!(last.as_str(), "a" | "ar" | "deb"))
}
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::{AR_EXTENSIONS, ArEntryKind, ArFormat, is_ar_extension, is_ar_filename};
#[test]
fn detects_ar_extensions() {
assert!(is_ar_extension(".a"));
assert!(is_ar_extension("ar"));
assert!(is_ar_extension("deb"));
assert_eq!(AR_EXTENSIONS[0], "a");
}
#[test]
fn detects_ar_filenames() {
assert!(is_ar_filename("libexample.a"));
assert!(is_ar_filename("package.DEB"));
assert!(!is_ar_filename("bundle.zip"));
}
#[test]
fn exposes_default_and_unknown_labels() {
assert_eq!(ArFormat::default(), ArFormat::Unknown);
assert_eq!(ArFormat::Bsd.as_str(), "bsd");
assert_eq!(ArEntryKind::default(), ArEntryKind::Unknown);
assert_eq!(ArEntryKind::StringTable.as_str(), "string-table");
}
}