standard_lib/fs/path/
path.rs1use std::borrow::Borrow;
2use std::cmp::Ordering;
3use std::ffi::{CString, OsStr, OsString};
4use std::fmt::{self, Debug, Formatter};
5use std::marker::PhantomData;
6use std::mem;
7use std::ops::Deref;
8use std::os::unix::ffi::{OsStrExt, OsStringExt};
9
10use super::{DisplayPath, Rel};
11use crate::collections::contiguous::Vector;
12use crate::fs::path::{Ancestors, Components};
13use crate::util::{self, sealed::Sealed};
14
15use derive_more::IsVariant;
16
17pub trait PathState: Sealed + Debug {}
18
19#[derive(Clone)]
20pub struct OwnedPath<State: PathState> {
21 pub(crate) _state: PhantomData<fn() -> State>,
22 pub(crate) inner: OsString,
23}
24
25#[repr(transparent)]
26pub struct Path<State: PathState> {
27 pub(crate) _state: PhantomData<fn() -> State>,
28 pub(crate) inner: OsStr,
29}
30
31impl<S: PathState> OwnedPath<S> {
32 pub(crate) fn from_os_str_sanitized(value: &OsStr) -> Self {
33 Self {
34 _state: PhantomData,
35 inner: sanitize_os_str(value),
36 }
37 }
38
39 pub const unsafe fn from_unchecked(inner: OsString) -> Self {
40 Self {
41 _state: PhantomData,
42 inner,
43 }
44 }
45
46 pub fn as_path(&self) -> &Path<S> {
47 self
48 }
49
50 pub fn push<P: AsRef<Path<Rel>>>(&mut self, other: P) {
51 let other_path = other.as_ref();
52 let mut vec: Vector<u8> = mem::take(&mut self.inner).into_vec().into();
53 vec.reserve(other_path.len());
54 vec.extend(other_path.inner.as_bytes().iter().cloned());
55 let _ = mem::replace(
56 &mut self.inner,
57 OsString::from_vec(vec.into())
58 );
59 }
60}
61
62impl<S: PathState> Path<S> {
63 pub unsafe fn from_unchecked<O: AsRef<OsStr> + ?Sized>(value: &O) -> &Self {
64 unsafe { &*(value.as_ref() as *const OsStr as *const Self) }
66 }
67
68 pub unsafe fn from_unchecked_mut<O: AsMut<OsStr> + ?Sized>(value: &mut O) -> &mut Self {
69 unsafe { &mut *(value.as_mut() as *mut OsStr as *mut Self) }
71 }
72
73 pub const fn display<'a>(&'a self) -> DisplayPath<'a, S> {
74 DisplayPath::<S> {
75 _phantom: PhantomData,
76 inner: self,
77 }
78 }
79
80 pub fn len(&self) -> usize {
81 self.inner.len()
82 }
83
84 pub fn is_empty(&self) -> bool {
85 self.len() == 0
86 }
87
88 pub const fn as_os_str(&self) -> &OsStr {
89 &self.inner
90 }
91
92 pub fn as_os_str_no_lead(&self) -> &OsStr {
93 OsStr::from_bytes(&self.as_bytes()[1..])
94 }
95
96 pub fn as_bytes(&self) -> &[u8] {
97 self.inner.as_bytes()
98 }
99
100 pub fn join<P: AsRef<Path<Rel>>>(&self, other: P) -> OwnedPath<S> {
107 unsafe {
108 OwnedPath::<S>::from_unchecked(
109 [self.as_os_str(), other.as_ref().as_os_str()].into_iter().collect()
110 )
111 }
112 }
113
114 pub fn relative(&self, other: &Self) -> Option<&Path<Rel>> {
115 match self.inner.as_bytes().strip_prefix(other.inner.as_bytes()) {
120 None => None,
121 Some(replaced) if !replaced.starts_with(b"/") => None,
124 Some(replaced) => unsafe {
126 Some(Path::<Rel>::from_unchecked(OsStr::from_bytes(replaced)))
127 },
128 }
129 }
130
131 pub fn components<'a>(&'a self) -> Components<'a, S> {
132 Components {
133 _state: PhantomData,
134 path: self.as_bytes(),
135 head: 0,
136 }
137 }
138
139 pub fn ancestors<'a>(&'a self) -> Ancestors<'a, S> {
140 Ancestors {
141 _state: PhantomData,
142 path: self.as_bytes(),
143 index: 0,
144 }
145 }
146}
147
148#[derive(Debug, Clone, Copy, IsVariant)]
149enum Seq {
150 Slash,
151 SlashDot,
152 Other,
153}
154
155pub(crate) fn sanitize_os_str(value: &OsStr) -> OsString {
158 let mut last_seq = Seq::Other;
159 let mut valid = Vector::with_cap(value.len() + 1);
160
161 for ch in b"/".iter().chain(value.as_bytes().iter()).cloned() {
162 match (ch, last_seq) {
163 (b'\0', _) => (),
164 (b'/', Seq::Slash) => (),
165 (b'/', Seq::SlashDot) => {
166 last_seq = Seq::Slash;
167 },
168 (b'/', Seq::Other) => {
169 last_seq = Seq::Slash;
170 valid.push(ch);
171 },
172 (b'.', Seq::Slash) => {
173 last_seq = Seq::SlashDot;
174 },
175 (_, Seq::Slash) => {
176 last_seq = Seq::Other;
177 valid.push(ch);
178 },
179 (_, Seq::SlashDot) => {
180 last_seq = Seq::Other;
181 valid.push(b'.');
182 valid.push(ch);
183 },
184 (_, Seq::Other) => {
185 valid.push(ch);
186 },
187 }
188 }
189
190 if last_seq.is_slash() && valid.len() > 1 {
191 valid.pop();
192 }
193
194 OsString::from_vec(valid.into())
195}
196
197impl<S: PathState> From<OwnedPath<S>> for CString {
198 fn from(value: OwnedPath<S>) -> Self {
199 let mut bytes = value.inner.into_vec();
200 bytes.push(b'\0');
201 unsafe { CString::from_vec_with_nul_unchecked(bytes) }
203 }
204}
205
206impl<S: PathState> Deref for OwnedPath<S> {
207 type Target = Path<S>;
208
209 fn deref(&self) -> &Self::Target {
210 unsafe { Path::<S>::from_unchecked(&self.inner) }
212 }
213}
214
215impl<S: PathState> AsRef<Path<S>> for OwnedPath<S> {
216 fn as_ref(&self) -> &Path<S> {
217 self.deref()
218 }
219}
220
221impl<S: PathState> AsRef<Path<S>> for Path<S> {
223 fn as_ref(&self) -> &Path<S> {
224 self
225 }
226}
227
228impl<S: PathState> Borrow<Path<S>> for OwnedPath<S> {
229 fn borrow(&self) -> &Path<S> {
230 self.as_ref()
231 }
232}
233
234impl<S: PathState> AsRef<OsStr> for Path<S> {
235 fn as_ref(&self) -> &OsStr {
236 &self.inner
237 }
238}
239
240impl<S: PathState> ToOwned for Path<S> {
241 type Owned = OwnedPath<S>;
242
243 fn to_owned(&self) -> Self::Owned {
244 OwnedPath::<S>::from_os_str_sanitized(self.as_os_str())
245 }
246}
247
248impl<S: PathState> PartialEq for OwnedPath<S> {
249 fn eq(&self, other: &Self) -> bool {
250 self.as_ref().inner == other.as_ref().inner
251 }
252}
253
254impl<S: PathState> PartialEq for Path<S> {
255 fn eq(&self, other: &Self) -> bool {
256 self.inner == other.inner
257 }
258}
259
260impl<S: PathState> PartialEq<Path<S>> for OwnedPath<S> {
261 fn eq(&self, other: &Path<S>) -> bool {
262 self.as_ref().inner == other.inner
263 }
264}
265
266impl<S: PathState> PartialEq<OwnedPath<S>> for Path<S> {
267 fn eq(&self, other: &OwnedPath<S>) -> bool {
268 self.inner == other.as_ref().inner
269 }
270}
271
272impl<S: PathState> Eq for OwnedPath<S> {}
273
274impl<S: PathState> Eq for Path<S> {}
275
276impl<S: PathState> PartialOrd for OwnedPath<S> {
277 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
278 Some(self.cmp(other))
279 }
280}
281
282impl<S: PathState> Ord for OwnedPath<S> {
283 fn cmp(&self, other: &Self) -> Ordering {
284 self.as_ref().inner.cmp(&other.as_ref().inner)
285 }
286}
287
288impl<S: PathState> PartialOrd for Path<S> {
289 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
290 Some(self.cmp(other))
291 }
292}
293
294impl<S: PathState> Ord for Path<S> {
295 fn cmp(&self, other: &Self) -> Ordering {
296 self.inner.cmp(&other.inner)
297 }
298}
299
300impl<S: PathState> PartialOrd<Path<S>> for OwnedPath<S> {
301 fn partial_cmp(&self, other: &Path<S>) -> Option<Ordering> {
302 Some(self.as_ref().cmp(other))
303 }
304}
305
306impl<S: PathState> PartialOrd<OwnedPath<S>> for Path<S> {
307 fn partial_cmp(&self, other: &OwnedPath<S>) -> Option<Ordering> {
308 Some(self.cmp(other.as_ref()))
309 }
310}
311
312impl<S: PathState> Debug for OwnedPath<S> {
313 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
314 f.debug_struct("OwnedPath")
315 .field("<state>", &util::fmt::raw_type_name::<S>())
316 .field("value", &self.inner)
317 .finish()
318 }
319}
320
321impl<S: PathState> Debug for Path<S> {
322 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
323 f.debug_struct("Path")
324 .field("<state>", &util::fmt::raw_type_name::<S>())
325 .field("value", &&self.inner)
326 .finish()
327 }
328}