use crate::{
path::{Component, Path},
Error, DELIMITER,
};
use alloc::{borrow::ToOwned, str::FromStr, vec::Vec};
use core::fmt::{self, Debug};
use core::{borrow::Borrow, ops::Deref};
use zeroize::Zeroize;
#[derive(Clone, Default, Eq, Hash, PartialEq, PartialOrd, Ord, Zeroize)]
#[repr(transparent)]
#[zeroize(drop)]
pub struct PathBuf(Vec<u8>);
impl PathBuf {
pub fn from_bytes<B>(bytes: B) -> Result<Self, Error>
where
B: AsRef<[u8]>,
{
Path::new(bytes.as_ref())?;
Ok(PathBuf(bytes.as_ref().into()))
}
pub fn new() -> Self {
Self::default()
}
pub fn as_path(&self) -> &Path {
Path::new(&self.0).unwrap()
}
pub fn extend<'a, I, C>(&mut self, components: I)
where
I: IntoIterator<Item = C>,
C: AsRef<Component<'a>>,
{
for component in components {
self.push(component);
}
}
pub fn push<'a, C: AsRef<Component<'a>>>(&mut self, component: C) {
self.0.append(&mut component.as_ref().to_bytes());
}
}
impl AsRef<Path> for PathBuf {
fn as_ref(&self) -> &Path {
self.as_path()
}
}
impl Borrow<Path> for PathBuf {
fn borrow(&self) -> &Path {
self.as_path()
}
}
impl Debug for PathBuf {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "hkd32::PathBuf")?;
self.debug_components(f)
}
}
impl Deref for PathBuf {
type Target = Path;
fn deref(&self) -> &Path {
self.as_path()
}
}
impl FromStr for PathBuf {
type Err = Error;
fn from_str(s: &str) -> Result<Self, Error> {
let mut result = Self::new();
if s.len() == 1 && s.starts_with(DELIMITER) {
return Ok(result);
}
let mut components = s.split(DELIMITER);
if components.next() != Some("") {
return Err(Error);
}
for component in components {
if !component.is_ascii() {
return Err(Error);
}
result.push(Component::new(component.as_bytes())?);
}
Ok(result)
}
}
impl ToOwned for Path {
type Owned = PathBuf;
fn to_owned(&self) -> PathBuf {
PathBuf::from_bytes(self.as_bytes()).unwrap()
}
}
#[cfg(all(test, feature = "alloc"))]
mod tests {
use super::*;
#[test]
fn test_root() {
let root_path = PathBuf::new();
assert_eq!(root_path.components().count(), 0);
assert_eq!(root_path.stringify().unwrap(), "/");
assert_eq!(&format!("{:?}", root_path), "hkd32::PathBuf(\"/\")");
}
}