1use std::{borrow::Cow, ffi::OsString, hash::{Hash, Hasher}};
2
3use hashbrown::Equivalent;
4
5use crate::{path::{AsPath, Component, PathDyn, PathDynError, PathKind, SetNameError}, strand::AsStrand, wtf8::FromWtf8Vec};
6
7#[derive(Clone, Debug, Eq)]
9pub enum PathBufDyn {
10 Os(std::path::PathBuf),
11 Unix(typed_path::UnixPathBuf),
12}
13
14impl From<&std::path::Path> for PathBufDyn {
15 fn from(value: &std::path::Path) -> Self { Self::Os(value.into()) }
16}
17
18impl From<std::path::PathBuf> for PathBufDyn {
19 fn from(value: std::path::PathBuf) -> Self { Self::Os(value) }
20}
21
22impl From<typed_path::UnixPathBuf> for PathBufDyn {
23 fn from(value: typed_path::UnixPathBuf) -> Self { Self::Unix(value) }
24}
25
26impl From<PathDyn<'_>> for PathBufDyn {
27 fn from(value: PathDyn<'_>) -> Self { value.to_owned() }
28}
29
30impl From<Cow<'_, std::path::Path>> for PathBufDyn {
31 fn from(value: Cow<'_, std::path::Path>) -> Self { Self::Os(value.into_owned()) }
32}
33
34impl TryFrom<PathBufDyn> for std::path::PathBuf {
35 type Error = PathDynError;
36
37 fn try_from(value: PathBufDyn) -> Result<Self, Self::Error> { value.into_os() }
38}
39
40impl TryFrom<PathBufDyn> for typed_path::UnixPathBuf {
41 type Error = PathDynError;
42
43 fn try_from(value: PathBufDyn) -> Result<Self, Self::Error> { value.into_unix() }
44}
45
46impl Hash for PathBufDyn {
48 fn hash<H: Hasher>(&self, state: &mut H) { self.as_path().hash(state) }
49}
50
51impl PartialEq for PathBufDyn {
53 fn eq(&self, other: &Self) -> bool { self.as_path() == other.as_path() }
54}
55
56impl PartialEq<PathDyn<'_>> for PathBufDyn {
57 fn eq(&self, other: &PathDyn<'_>) -> bool { self.as_path() == *other }
58}
59
60impl PartialEq<PathDyn<'_>> for &PathBufDyn {
61 fn eq(&self, other: &PathDyn<'_>) -> bool { self.as_path() == *other }
62}
63
64impl Equivalent<PathDyn<'_>> for PathBufDyn {
65 fn equivalent(&self, key: &PathDyn<'_>) -> bool { self.as_path() == *key }
66}
67
68impl PathBufDyn {
69 #[inline]
70 pub unsafe fn from_encoded_bytes<K>(kind: K, bytes: Vec<u8>) -> Self
71 where
72 K: Into<PathKind>,
73 {
74 match kind.into() {
75 PathKind::Os => Self::Os(unsafe { OsString::from_encoded_bytes_unchecked(bytes) }.into()),
76 PathKind::Unix => Self::Unix(bytes.into()),
77 }
78 }
79
80 #[inline]
81 pub fn from_components<'a, K, I>(kind: K, iter: I) -> Result<Self, PathDynError>
82 where
83 K: Into<PathKind>,
84 I: IntoIterator<Item = Component<'a>>,
85 {
86 Ok(match kind.into() {
87 PathKind::Os => Self::Os(iter.into_iter().collect::<Result<_, PathDynError>>()?),
88 PathKind::Unix => Self::Unix(iter.into_iter().collect::<Result<_, PathDynError>>()?),
89 })
90 }
91
92 pub fn into_encoded_bytes(self) -> Vec<u8> {
93 match self {
94 Self::Os(p) => p.into_os_string().into_encoded_bytes(),
95 Self::Unix(p) => p.into_vec(),
96 }
97 }
98
99 #[inline]
100 pub fn into_os(self) -> Result<std::path::PathBuf, PathDynError> {
101 Ok(match self {
102 Self::Os(p) => p,
103 Self::Unix(_) => Err(PathDynError::AsOs)?,
104 })
105 }
106
107 #[inline]
108 pub fn into_unix(self) -> Result<typed_path::UnixPathBuf, PathDynError> {
109 Ok(match self {
110 Self::Os(_) => Err(PathDynError::AsUnix)?,
111 Self::Unix(p) => p,
112 })
113 }
114
115 #[inline]
116 pub fn new(kind: PathKind) -> Self {
117 match kind {
118 PathKind::Os => Self::Os(std::path::PathBuf::new()),
119 PathKind::Unix => Self::Unix(typed_path::UnixPathBuf::new()),
120 }
121 }
122
123 pub fn try_extend<T>(&mut self, paths: T) -> Result<(), PathDynError>
124 where
125 T: IntoIterator,
126 T::Item: AsPath,
127 {
128 for p in paths {
129 self.try_push(p)?;
130 }
131 Ok(())
132 }
133
134 pub fn try_push<T>(&mut self, path: T) -> Result<(), PathDynError>
135 where
136 T: AsPath,
137 {
138 let path = path.as_path();
139 Ok(match self {
140 Self::Os(p) => p.push(path.as_os()?),
141 Self::Unix(p) => p.push(path.encoded_bytes()),
142 })
143 }
144
145 pub fn try_set_name<T>(&mut self, name: T) -> Result<(), SetNameError>
146 where
147 T: AsStrand,
148 {
149 let s = name.as_strand();
150 Ok(match self {
151 Self::Os(p) => p.set_file_name(s.as_os()?),
152 Self::Unix(p) => p.set_file_name(s.encoded_bytes()),
153 })
154 }
155
156 pub fn with<K>(kind: K, bytes: Vec<u8>) -> Result<Self, PathDynError>
157 where
158 K: Into<PathKind>,
159 {
160 Ok(match kind.into() {
161 PathKind::Os => {
162 Self::Os(std::path::PathBuf::from_wtf8_vec(bytes).map_err(|_| PathDynError::AsOs)?)
163 }
164 PathKind::Unix => Self::Unix(bytes.into()),
165 })
166 }
167
168 pub fn with_capacity<K>(kind: K, capacity: usize) -> Self
169 where
170 K: Into<PathKind>,
171 {
172 match kind.into() {
173 PathKind::Os => Self::Os(std::path::PathBuf::with_capacity(capacity)),
174 PathKind::Unix => Self::Unix(typed_path::UnixPathBuf::with_capacity(capacity)),
175 }
176 }
177
178 pub fn with_str<K, S>(kind: K, s: S) -> Self
179 where
180 K: Into<PathKind>,
181 S: Into<String>,
182 {
183 let s = s.into();
184 match kind.into() {
185 PathKind::Os => Self::Os(s.into()),
186 PathKind::Unix => Self::Unix(s.into()),
187 }
188 }
189}