use alloc::string::String;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum ErrorKind {
Empty,
CurrentDirectoryMarker,
ParentDirectoryMarker,
ContainsForwardSlash,
ContainsNullByte,
ContainsControlCharacter,
ContainsBom,
InvalidUtf8,
ContainsUnassignedChar,
#[cfg(any(target_vendor = "apple", docsrs))]
#[cfg_attr(docsrs, doc(cfg(target_vendor = "apple")))]
GetFileSystemRepresentationError,
}
impl core::fmt::Display for ErrorKind {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
match self {
Self::Empty => f.write_str("empty path element"),
Self::CurrentDirectoryMarker => f.write_str("current directory marker"),
Self::ParentDirectoryMarker => f.write_str("parent directory marker"),
Self::ContainsForwardSlash => f.write_str("contains forward slash"),
Self::ContainsNullByte => f.write_str("contains null byte"),
Self::ContainsControlCharacter => f.write_str("contains control character"),
Self::ContainsBom => f.write_str("contains BOM"),
Self::InvalidUtf8 => f.write_str("invalid UTF-8"),
Self::ContainsUnassignedChar => f.write_str("contains unassigned character"),
#[cfg(any(target_vendor = "apple", docsrs))]
Self::GetFileSystemRepresentationError => {
f.write_str("CFStringGetFileSystemRepresentation failed")
}
}
}
}
#[derive(Debug, Clone)]
pub struct Error {
pub kind: ErrorKind,
pub original: String,
}
impl Error {
#[must_use]
pub fn new(kind: ErrorKind, original: impl Into<String>) -> Self {
Self {
kind,
original: original.into(),
}
}
}
impl core::fmt::Display for Error {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
if self.original.is_empty() {
write!(f, "{}", self.kind)
} else {
write!(f, "{}: {:?}", self.kind, self.original)
}
}
}
impl core::error::Error for Error {}
pub type Result<T> = core::result::Result<T, Error>;
pub type ResultKind<T> = core::result::Result<T, ErrorKind>;
#[cfg(test)]
mod tests {
use alloc::format;
use alloc::string::ToString;
#[cfg(all(target_arch = "wasm32", any(target_os = "unknown", target_os = "none")))]
use wasm_bindgen_test::wasm_bindgen_test as test;
use super::{Error, ErrorKind};
#[test]
fn error_kind_display() {
assert_eq!(ErrorKind::Empty.to_string(), "empty path element");
assert_eq!(
ErrorKind::CurrentDirectoryMarker.to_string(),
"current directory marker"
);
assert_eq!(
ErrorKind::ParentDirectoryMarker.to_string(),
"parent directory marker"
);
assert_eq!(
ErrorKind::ContainsForwardSlash.to_string(),
"contains forward slash"
);
assert_eq!(
ErrorKind::ContainsNullByte.to_string(),
"contains null byte"
);
assert_eq!(
ErrorKind::ContainsControlCharacter.to_string(),
"contains control character"
);
assert_eq!(ErrorKind::ContainsBom.to_string(), "contains BOM");
assert_eq!(ErrorKind::InvalidUtf8.to_string(), "invalid UTF-8");
assert_eq!(
ErrorKind::ContainsUnassignedChar.to_string(),
"contains unassigned character"
);
}
#[test]
fn error_display_with_original() {
let err = Error::new(ErrorKind::ContainsForwardSlash, "a/b");
assert_eq!(format!("{err}"), "contains forward slash: \"a/b\"");
}
#[test]
fn error_display_empty_original() {
let err = Error::new(ErrorKind::Empty, "");
assert_eq!(format!("{err}"), "empty path element");
}
#[test]
fn error_debug() {
let err = Error::new(ErrorKind::Empty, ".");
let debug = format!("{err:?}");
assert!(debug.contains("Empty"));
assert!(debug.contains('.'));
}
#[test]
fn path_element_error_has_original() {
let err = crate::PathElementCS::new("a/b").unwrap_err();
assert_eq!(err.kind, ErrorKind::ContainsForwardSlash);
assert_eq!(err.original, "a/b");
}
#[test]
fn path_element_error_empty() {
let err = crate::PathElementCS::new("").unwrap_err();
assert_eq!(err.kind, ErrorKind::Empty);
assert_eq!(err.original, "");
}
#[test]
fn path_element_error_dot() {
let err = crate::PathElementCI::new(".").unwrap_err();
assert_eq!(err.kind, ErrorKind::CurrentDirectoryMarker);
assert_eq!(err.original, ".");
}
#[test]
fn path_element_error_dotdot() {
let err = crate::PathElementCS::new("..").unwrap_err();
assert_eq!(err.kind, ErrorKind::ParentDirectoryMarker);
assert_eq!(err.original, "..");
}
#[test]
fn path_element_error_null_byte() {
let err = crate::PathElementCS::new("a\0b").unwrap_err();
assert_eq!(err.kind, ErrorKind::ContainsNullByte);
assert_eq!(err.original, "a\0b");
}
#[test]
fn path_element_error_control_character() {
let err = crate::PathElementCS::new("a\x01b").unwrap_err();
assert_eq!(err.kind, ErrorKind::ContainsControlCharacter);
assert_eq!(err.original, "a\x01b");
}
#[test]
fn path_element_error_bom() {
let err = crate::PathElementCS::new("\u{FEFF}hello").unwrap_err();
assert_eq!(err.kind, ErrorKind::ContainsBom);
assert_eq!(err.original, "\u{FEFF}hello");
}
#[test]
fn path_element_error_whitespace_trimmed_to_empty() {
let err = crate::PathElementCS::new(" ").unwrap_err();
assert_eq!(err.kind, ErrorKind::Empty);
assert_eq!(err.original, " ");
}
}