use eyre::{eyre, Error, Result};
use std::path::Path;
use std::{ffi::OsStr, path::PathBuf};
use serde::{Deserialize, Serialize};
#[derive(Serialize, Deserialize, Debug, Clone)]
#[serde(try_from = "PathBuf")]
pub struct AbsolutePath(PathBuf);
impl TryFrom<PathBuf> for AbsolutePath {
type Error = Error;
fn try_from(path: PathBuf) -> Result<Self> {
if path.is_absolute() {
Ok(Self(path))
} else {
Err(eyre!("Path must be absolute: {:?}", path))
}
}
}
impl From<AbsolutePath> for PathBuf {
fn from(p: AbsolutePath) -> PathBuf {
p.0
}
}
impl PartialEq<AbsolutePath> for PathBuf {
fn eq(&self, other: &AbsolutePath) -> bool {
*self == *other.0
}
}
impl std::ops::Deref for AbsolutePath {
type Target = Path;
#[inline]
fn deref(&self) -> &Path {
self.0.as_path()
}
}
#[allow(dead_code)]
pub fn file_prefix(path: &Path) -> Option<&OsStr> {
let file_name = path.file_name()?;
file_name.to_str()?.split('.').next().map(OsStr::new)
}
#[cfg(test)]
mod tests {
use rstest::rstest;
use super::*;
#[rstest]
#[case("/test", "test")]
#[case("/test.log", "test")]
#[case("/test.log.zlib", "test")]
fn test_file_prefix(#[case] path: &str, #[case] expected: &str) {
assert_eq!(file_prefix(Path::new(path)), Some(OsStr::new(expected)));
}
}