use std::{
fmt::{self, Display},
str::FromStr,
};
use typed_path::{Utf8UnixComponent, Utf8UnixPath, Utf8UnixPathBuf};
use crate::filesystem::FsError;
#[derive(Clone, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)]
pub struct Utf8UnixPathSegment(String);
impl Utf8UnixPathSegment {
pub fn as_str(&self) -> &str {
&self.0
}
pub fn as_bytes(&self) -> &[u8] {
self.0.as_bytes()
}
pub fn len(&self) -> usize {
self.0.len()
}
pub fn is_empty(&self) -> bool {
self.0.is_empty()
}
}
impl FromStr for Utf8UnixPathSegment {
type Err = FsError;
fn from_str(s: &str) -> Result<Self, Self::Err> {
Utf8UnixPathSegment::try_from(s)
}
}
impl Display for Utf8UnixPathSegment {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}", self.0)
}
}
impl TryFrom<&str> for Utf8UnixPathSegment {
type Error = FsError;
fn try_from(value: &str) -> Result<Self, Self::Error> {
if value.is_empty() {
return Err(FsError::InvalidPathComponent(value.to_string()));
}
let component = Utf8UnixComponent::try_from(value)
.map_err(|_| FsError::InvalidPathComponent(value.to_string()))?;
match component {
Utf8UnixComponent::Normal(component) => Ok(Utf8UnixPathSegment(component.to_string())),
_ => Err(FsError::InvalidPathComponent(value.to_string())),
}
}
}
impl<'a> TryFrom<Utf8UnixComponent<'a>> for Utf8UnixPathSegment {
type Error = FsError;
fn try_from(component: Utf8UnixComponent<'a>) -> Result<Self, Self::Error> {
Utf8UnixPathSegment::try_from(&component)
}
}
impl<'a> TryFrom<&Utf8UnixComponent<'a>> for Utf8UnixPathSegment {
type Error = FsError;
fn try_from(component: &Utf8UnixComponent<'a>) -> Result<Self, Self::Error> {
match component {
Utf8UnixComponent::Normal(component) => Ok(Utf8UnixPathSegment(component.to_string())),
_ => Err(FsError::InvalidPathComponent(component.to_string())),
}
}
}
impl<'a> From<&'a Utf8UnixPathSegment> for Utf8UnixComponent<'a> {
fn from(segment: &'a Utf8UnixPathSegment) -> Self {
Utf8UnixComponent::Normal(&segment.0)
}
}
impl From<Utf8UnixPathSegment> for Utf8UnixPathBuf {
#[inline]
fn from(segment: Utf8UnixPathSegment) -> Self {
Utf8UnixPathBuf::from(segment.0)
}
}
impl AsRef<[u8]> for Utf8UnixPathSegment {
#[inline]
fn as_ref(&self) -> &[u8] {
self.as_bytes()
}
}
impl AsRef<str> for Utf8UnixPathSegment {
#[inline]
fn as_ref(&self) -> &str {
self.as_str()
}
}
impl AsRef<Utf8UnixPath> for Utf8UnixPathSegment {
#[inline]
fn as_ref(&self) -> &Utf8UnixPath {
Utf8UnixPath::new(self)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_segment_as_str() {
let segment = Utf8UnixPathSegment::from_str("example").unwrap();
assert_eq!(segment.as_str(), "example");
}
#[test]
fn test_segment_as_bytes() {
let segment = Utf8UnixPathSegment::from_str("example").unwrap();
assert_eq!(segment.as_bytes(), b"example");
}
#[test]
fn test_segment_len() {
let segment = Utf8UnixPathSegment::from_str("example").unwrap();
assert_eq!(segment.len(), 7);
}
#[test]
fn test_segment_display() {
let segment = Utf8UnixPathSegment::from_str("example").unwrap();
assert_eq!(format!("{}", segment), "example");
}
#[test]
fn test_segment_try_from_str() {
assert!(Utf8UnixPathSegment::try_from("example").is_ok());
assert!(Utf8UnixPathSegment::from_str("example").is_ok());
assert!("example".parse::<Utf8UnixPathSegment>().is_ok());
assert!(Utf8UnixPathSegment::from_str("").is_err());
assert!(Utf8UnixPathSegment::from_str(".").is_err());
assert!(Utf8UnixPathSegment::from_str("..").is_err());
assert!(Utf8UnixPathSegment::from_str("/").is_err());
assert!(".".parse::<Utf8UnixPathSegment>().is_err());
assert!("..".parse::<Utf8UnixPathSegment>().is_err());
assert!("/".parse::<Utf8UnixPathSegment>().is_err());
assert!("".parse::<Utf8UnixPathSegment>().is_err());
assert!("///".parse::<Utf8UnixPathSegment>().is_err());
assert!("a/b".parse::<Utf8UnixPathSegment>().is_err());
assert!(Utf8UnixPathSegment::try_from(".").is_err());
assert!(Utf8UnixPathSegment::try_from("..").is_err());
assert!(Utf8UnixPathSegment::try_from("/").is_err());
assert!(Utf8UnixPathSegment::try_from("").is_err());
assert!(Utf8UnixPathSegment::try_from("///").is_err());
assert!(Utf8UnixPathSegment::try_from("a/b").is_err());
}
#[test]
fn test_segment_utf8_characters() {
assert!(Utf8UnixPathSegment::try_from("файл").is_ok());
assert!(Utf8UnixPathSegment::try_from("文件").is_ok());
assert!(Utf8UnixPathSegment::try_from("🚀").is_ok());
assert!(Utf8UnixPathSegment::try_from("файл/имя").is_err());
assert!(Utf8UnixPathSegment::try_from("文件/名称").is_err());
}
#[test]
fn test_segment_from_utf8_unix_path_segment_to_utf8_unix_component() {
let segment = Utf8UnixPathSegment::from_str("example").unwrap();
assert_eq!(
Utf8UnixComponent::from(&segment),
Utf8UnixComponent::Normal("example")
);
}
#[test]
fn test_segment_from_utf8_unix_path_segment_to_utf8_unix_path_buf() {
let segment = Utf8UnixPathSegment::from_str("example").unwrap();
assert_eq!(
Utf8UnixPathBuf::from(segment),
Utf8UnixPathBuf::from("example")
);
}
#[test]
fn test_segment_normal_with_special_characters() {
assert!(Utf8UnixPathSegment::try_from("file.txt").is_ok());
assert!(Utf8UnixPathSegment::try_from("file-name").is_ok());
assert!(Utf8UnixPathSegment::try_from("file_name").is_ok());
assert!(Utf8UnixPathSegment::try_from("file name").is_ok());
assert!(Utf8UnixPathSegment::try_from("file\\name").is_ok());
assert!(Utf8UnixPathSegment::try_from("file:name").is_ok());
assert!(Utf8UnixPathSegment::try_from("file*name").is_ok());
assert!(Utf8UnixPathSegment::try_from("file?name").is_ok());
assert!(Utf8UnixPathSegment::try_from("file/name").is_err());
}
}