1#![deny(missing_docs)]
4#![forbid(unsafe_code)]
5#![cfg_attr(docsrs, feature(doc_cfg))]
6
7use std::{path::Path, str::Utf8Error};
8
9use non_empty_str::{EmptyStr, NonEmptyStr, NonEmptyString};
10use thiserror::Error;
11
12mod sealed {
13 pub trait Sealed {}
14}
15
16#[derive(Debug, Error)]
18pub enum Error {
19 #[error("path name not found")]
21 NotFound,
22
23 #[error("empty path name encountered")]
25 Empty(#[from] EmptyStr),
26
27 #[error("invalid utf-8 in path name")]
29 Utf8(#[from] Utf8Error),
30}
31
32pub trait PathName: sealed::Sealed {
34 fn path_name(&self) -> Result<&NonEmptyStr, Error>;
40
41 fn path_name_owned(&self) -> Result<NonEmptyString, Error> {
49 self.path_name().map(ToOwned::to_owned)
50 }
51}
52
53impl<P: AsRef<Path>> sealed::Sealed for P {}
54
55impl<P: AsRef<Path>> PathName for P {
56 fn path_name(&self) -> Result<&NonEmptyStr, Error> {
57 let path = self.as_ref();
58
59 let string: &str = path.file_name().ok_or(Error::NotFound)?.try_into()?;
60
61 let name = string.try_into()?;
62
63 Ok(name)
64 }
65}