use std::ffi::{OsStr, OsString}; use hashbrown::Equivalent; use crate::{FromWtf8, FromWtf8Vec, path::{AsPath, Component, PathDyn, PathDynError, PathKind, SetNameError}, strand::{AsStrand, Strand}}; // --- PathBufDyn #[derive(Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)] pub enum PathBufDyn { Os(std::path::PathBuf), Unix(typed_path::UnixPathBuf), } impl From for PathBufDyn { fn from(value: std::path::PathBuf) -> Self { Self::Os(value) } } impl From for PathBufDyn { fn from(value: typed_path::UnixPathBuf) -> Self { Self::Unix(value) } } impl From> for PathBufDyn { fn from(value: PathDyn<'_>) -> Self { value.to_owned() } } impl TryFrom for std::path::PathBuf { type Error = PathDynError; fn try_from(value: PathBufDyn) -> Result { value.into_os() } } impl TryFrom for typed_path::UnixPathBuf { type Error = PathDynError; fn try_from(value: PathBufDyn) -> Result { value.into_unix() } } impl PartialEq> for PathBufDyn { fn eq(&self, other: &PathDyn<'_>) -> bool { self.as_path() == *other } } impl PartialEq> for &PathBufDyn { fn eq(&self, other: &PathDyn<'_>) -> bool { self.as_path() == *other } } impl Equivalent> for PathBufDyn { fn equivalent(&self, key: &PathDyn<'_>) -> bool { self.as_path() == *key } } impl PathBufDyn { #[inline] pub unsafe fn from_encoded_bytes(kind: K, bytes: Vec) -> Self where K: Into, { match kind.into() { PathKind::Os => Self::Os(unsafe { OsString::from_encoded_bytes_unchecked(bytes) }.into()), PathKind::Unix => Self::Unix(bytes.into()), } } #[inline] pub fn from_components<'a, K, I>(kind: K, iter: I) -> Result where K: Into, I: IntoIterator>, { Ok(match kind.into() { PathKind::Os => Self::Os(iter.into_iter().collect::>()?), PathKind::Unix => Self::Unix(iter.into_iter().collect::>()?), }) } pub fn into_encoded_bytes(self) -> Vec { match self { Self::Os(p) => p.into_os_string().into_encoded_bytes(), Self::Unix(p) => p.into_vec(), } } #[inline] pub fn into_os(self) -> Result { Ok(match self { Self::Os(p) => p, Self::Unix(_) => Err(PathDynError::AsOs)?, }) } #[inline] pub fn into_unix(self) -> Result { Ok(match self { Self::Os(_) => Err(PathDynError::AsUnix)?, Self::Unix(p) => p, }) } #[inline] pub fn new(kind: PathKind) -> Self { match kind { PathKind::Os => Self::Os(std::path::PathBuf::new()), PathKind::Unix => Self::Unix(typed_path::UnixPathBuf::new()), } } pub fn try_extend(&mut self, paths: T) -> Result<(), PathDynError> where T: IntoIterator, T::Item: AsPath, { for p in paths { self.try_push(p)?; } Ok(()) } pub fn try_push(&mut self, path: T) -> Result<(), PathDynError> where T: AsPath, { let path = path.as_path(); Ok(match self { Self::Os(p) => p.push(path.as_os()?), Self::Unix(p) => p.push(path.encoded_bytes()), }) } pub fn try_set_name(&mut self, name: T) -> Result<(), SetNameError> where T: AsStrand, { Ok(match (self, name.as_strand()) { (Self::Os(p), Strand::Os(s)) => p.set_file_name(s), (Self::Os(p), Strand::Utf8(s)) => p.set_file_name(s), (Self::Os(p), Strand::Bytes(b)) => { p.set_file_name(OsStr::from_wtf8(b).map_err(|_| SetNameError::FromWtf8)?) } (Self::Unix(p), s) => p.set_file_name(s.encoded_bytes()), }) } pub fn with(kind: K, bytes: Vec) -> Result where K: Into, { Ok(match kind.into() { PathKind::Os => { Self::Os(std::path::PathBuf::from_wtf8_vec(bytes).map_err(|_| PathDynError::AsOs)?) } PathKind::Unix => Self::Unix(bytes.into()), }) } pub fn with_capacity(kind: K, capacity: usize) -> Self where K: Into, { match kind.into() { PathKind::Os => Self::Os(std::path::PathBuf::with_capacity(capacity)), PathKind::Unix => Self::Unix(typed_path::UnixPathBuf::with_capacity(capacity)), } } pub fn with_str(kind: K, s: S) -> Self where K: Into, S: Into, { let s = s.into(); match kind.into() { PathKind::Os => Self::Os(s.into()), PathKind::Unix => Self::Unix(s.into()), } } }