#![deny(missing_docs)]
#![cfg_attr(docsrs, feature(doc_cfg))]
use std::{path::Path, str::Utf8Error};
#[cfg(feature = "diagnostics")]
use miette::Diagnostic;
use non_empty_str::{EmptyStr, NonEmptyStr, NonEmptyString};
use thiserror::Error;
mod sealed {
pub trait Sealed {}
}
#[derive(Debug, Error)]
#[cfg_attr(feature = "diagnostics", derive(Diagnostic))]
pub enum Error {
#[error("path name not found")]
#[cfg_attr(
feature = "diagnostics",
diagnostic(code(path_name::not_found), help("make sure the path name is present"))
)]
NotFound,
#[error("empty path name encountered")]
#[cfg_attr(
feature = "diagnostics",
diagnostic(code(path_name::empty), help("make sure the path name is non-empty"))
)]
Empty(#[from] EmptyStr),
#[error("invalid utf-8 in path name")]
#[cfg_attr(
feature = "diagnostics",
diagnostic(code(path_name::utf8), help("make sure the path name is valid utf-8"))
)]
Utf8(#[from] Utf8Error),
}
pub trait PathName: sealed::Sealed {
fn path_name(&self) -> Result<&NonEmptyStr, Error>;
fn path_name_owned(&self) -> Result<NonEmptyString, Error> {
self.path_name().map(ToOwned::to_owned)
}
}
impl<P: AsRef<Path>> sealed::Sealed for P {}
impl<P: AsRef<Path>> PathName for P {
fn path_name(&self) -> Result<&NonEmptyStr, Error> {
let path = self.as_ref();
let string: &str = path.file_name().ok_or(Error::NotFound)?.try_into()?;
let name = string.try_into()?;
Ok(name)
}
}