#[derive(Clone, Copy, Debug, Eq, PartialEq)]
#[non_exhaustive]
pub enum PathForm {
AbsoluteLiteral,
UnitRelativeLiteral,
RelativeLiteral,
SystemdSpecifier,
}
#[must_use]
pub fn classify_path(value: &str) -> PathForm {
if contains_systemd_specifier(value) {
return PathForm::SystemdSpecifier;
}
if value.starts_with('/') {
PathForm::AbsoluteLiteral
} else if value == "." || value == ".." || value.starts_with("./") || value.starts_with("../") {
PathForm::UnitRelativeLiteral
} else {
PathForm::RelativeLiteral
}
}
fn contains_systemd_specifier(value: &str) -> bool {
let mut bytes = value.bytes();
while let Some(byte) = bytes.next() {
if byte == b'%' {
match bytes.next() {
Some(b'%') => {}
Some(_) | None => return true,
}
}
}
false
}
#[cfg(test)]
mod tests {
use super::{PathForm, classify_path};
#[test]
fn distinguishes_literals_unit_relative_paths_and_specifiers() {
assert_eq!(classify_path("/srv/data"), PathForm::AbsoluteLiteral);
assert_eq!(classify_path("./data"), PathForm::UnitRelativeLiteral);
assert_eq!(classify_path("../data"), PathForm::UnitRelativeLiteral);
assert_eq!(classify_path("data"), PathForm::RelativeLiteral);
assert_eq!(classify_path("~/data"), PathForm::RelativeLiteral);
assert_eq!(classify_path("%h/data"), PathForm::SystemdSpecifier);
assert_eq!(classify_path("/srv/%n/data"), PathForm::SystemdSpecifier);
assert_eq!(classify_path("%%h/data"), PathForm::RelativeLiteral);
}
}