standard_lib/fs/path/
path.rs1use std::borrow::{Borrow, Cow};
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::num::NonZero;
8use std::ops::Deref;
9use std::os::unix::ffi::{OsStrExt, OsStringExt};
10
11use super::{DisplayPath, Rel};
12use crate::collections::contiguous::Vector;
13use crate::fs::path::{Ancestors, Components, validity};
14use crate::util::{self, sealed::Sealed};
15
16pub trait PathState: Sealed + Debug {}
17
18pub struct OwnedPath<State: PathState> {
19 pub(crate) _state: PhantomData<fn() -> State>,
20 pub(crate) inner: OsString,
21}
22
23#[repr(transparent)]
24pub struct Path<State: PathState> {
25 pub(crate) _state: PhantomData<fn() -> State>,
26 pub(crate) inner: OsStr,
27}
28
29impl<T: AsRef<OsStr>, S: PathState> From<T> for OwnedPath<S> {
30 fn from(value: T) -> Self {
31 Self {
32 _state: PhantomData,
33 inner: validity::sanitize(value.as_ref()),
34 }
35 }
36}
37
38impl<S: PathState> OwnedPath<S> {
39 pub unsafe fn from_unchecked<O: Into<OsString>>(inner: O) -> Self {
40 Self {
41 _state: PhantomData,
42 inner: inner.into(),
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().get());
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 pub fn pop(&mut self) -> Option<OwnedPath<Rel>> {
62 let mut bytes = mem::take(&mut self.inner).into_vec();
69
70 let mut index = bytes.len().checked_sub(1)?;
71
72 while let Some(ch) = bytes.get(index) && *ch != b'/' {
73 index = index.checked_sub(1)?;
74 }
75
76 let split = bytes.split_off(index);
77
78 drop(mem::replace(&mut self.inner, OsString::from_vec(bytes)));
79
80 Some(OwnedPath::<Rel> {
81 _state: PhantomData,
82 inner: OsString::from_vec(split),
83 })
84 }
85}
86
87impl<S: PathState> Path<S> {
88 pub fn new<'a, O: AsRef<OsStr> + ?Sized>(value: &'a O) -> Cow<'a, Path<S>> {
89 match validity::validate(value.as_ref()) {
90 Some(_) => Cow::Borrowed(unsafe { Path::from_unchecked(value) }),
91 None => Cow::Owned(OwnedPath::from(value)),
92 }
93 }
94
95 pub fn from_checked<O: AsRef<OsStr> + ?Sized>(value: &O) -> Option<&Path<S>> {
96 validity::validate(value.as_ref())?;
97 Some(unsafe { Path::from_unchecked(value) })
98 }
99
100 pub unsafe fn from_unchecked<O: AsRef<OsStr> + ?Sized>(value: &O) -> &Self {
101 unsafe { &*(value.as_ref() as *const OsStr as *const Self) }
103 }
104
105 pub unsafe fn from_unchecked_mut<O: AsMut<OsStr> + ?Sized>(value: &mut O) -> &mut Self {
106 unsafe { &mut *(value.as_mut() as *mut OsStr as *mut Self) }
108 }
109
110 pub const fn display<'a>(&'a self) -> DisplayPath<'a, S> {
111 DisplayPath::<S> {
112 _phantom: PhantomData,
113 inner: self,
114 }
115 }
116
117 pub fn len(&self) -> NonZero<usize> {
118 unsafe { NonZero::new(self.inner.len()).unwrap_unchecked() }
119 }
120
121 pub const fn as_os_str(&self) -> &OsStr {
122 &self.inner
123 }
124
125 pub fn as_os_str_no_lead(&self) -> &OsStr {
126 OsStr::from_bytes(&self.as_bytes()[1..])
127 }
128
129 pub fn as_bytes(&self) -> &[u8] {
130 self.inner.as_bytes()
131 }
132
133 pub fn basename(&self) -> &OsStr {
140 let bytes = self.as_bytes();
141
142 let mut index = bytes.len() - 1;
143
144 while let Some(ch) = bytes.get(index) && *ch != b'/' {
145 index -= 1;
146 }
147
148 OsStr::from_bytes(&bytes[(index + 1)..])
149 }
150
151 pub fn parent(&self) -> &Self {
174 let bytes = self.as_bytes();
175
176 let mut index = bytes.len() - 1;
177
178 while let Some(ch) = bytes.get(index) && *ch != b'/' {
179 index -= 1;
180 }
181
182 if index == 0 {
185 index = 1;
186 }
187
188 unsafe { Path::from_unchecked(OsStr::from_bytes(&bytes[..index])) }
189 }
190
191 pub fn join<P: AsRef<Path<Rel>>>(&self, other: P) -> OwnedPath<S> {
192 unsafe {
193 OwnedPath::<S>::from_unchecked(
194 [self.as_os_str(), other.as_ref().as_os_str()].into_iter().collect::<OsString>()
195 )
196 }
197 }
198
199 pub fn relative_to(&self, other: &Self) -> Option<&Path<Rel>> {
200 match self.inner.as_bytes().strip_prefix(other.inner.as_bytes()) {
205 None => None,
206 Some(replaced) if !replaced.starts_with(b"/") => None,
209 Some(replaced) => unsafe {
211 Some(Path::<Rel>::from_unchecked(OsStr::from_bytes(replaced)))
212 },
213 }
214 }
215
216 pub fn components<'a>(&'a self) -> Components<'a, S> {
219 Components {
220 _state: PhantomData,
221 path: self.as_bytes(),
222 head: 0,
223 }
224 }
225
226 pub fn ancestors<'a>(&'a self) -> Ancestors<'a, S> {
230 Ancestors {
231 _state: PhantomData,
232 path: self.as_bytes(),
233 index: 0,
234 }
235 }
236}
237
238impl<S: PathState> From<OwnedPath<S>> for CString {
239 fn from(value: OwnedPath<S>) -> Self {
240 unsafe { CString::from_vec_unchecked(value.inner.into_vec()) }
242 }
243}
244
245impl<S: PathState> Deref for OwnedPath<S> {
246 type Target = Path<S>;
247
248 fn deref(&self) -> &Self::Target {
249 unsafe { Path::<S>::from_unchecked(&self.inner) }
251 }
252}
253
254impl<S: PathState> From<&Path<S>> for OwnedPath<S> {
255 fn from(value: &Path<S>) -> Self {
256 value.to_owned()
257 }
258}
259
260impl<S: PathState> AsRef<Path<S>> for OwnedPath<S> {
261 fn as_ref(&self) -> &Path<S> {
262 self.deref()
263 }
264}
265
266impl<S: PathState> AsRef<Path<S>> for Path<S> {
268 fn as_ref(&self) -> &Path<S> {
269 self
270 }
271}
272
273impl<S: PathState> Borrow<Path<S>> for OwnedPath<S> {
274 fn borrow(&self) -> &Path<S> {
275 self.as_ref()
276 }
277}
278
279impl<S: PathState> ToOwned for Path<S> {
289 type Owned = OwnedPath<S>;
290
291 fn to_owned(&self) -> Self::Owned {
292 OwnedPath::<S> {
293 _state: PhantomData,
294 inner: self.as_os_str().to_owned(),
295 }
296 }
297}
298
299impl<S: PathState> Clone for OwnedPath<S> {
300 fn clone(&self) -> Self {
301 Self {
302 _state: PhantomData,
303 inner: self.inner.clone()
304 }
305 }
306}
307
308impl<S: PathState> PartialEq for OwnedPath<S> {
309 fn eq(&self, other: &Self) -> bool {
310 self.as_ref().inner == other.as_ref().inner
311 }
312}
313
314impl<S: PathState> PartialEq for Path<S> {
315 fn eq(&self, other: &Self) -> bool {
316 self.inner == other.inner
317 }
318}
319
320impl<S: PathState> PartialEq<Path<S>> for OwnedPath<S> {
321 fn eq(&self, other: &Path<S>) -> bool {
322 self.as_ref().inner == other.inner
323 }
324}
325
326impl<S: PathState> PartialEq<OwnedPath<S>> for Path<S> {
327 fn eq(&self, other: &OwnedPath<S>) -> bool {
328 self.inner == other.as_ref().inner
329 }
330}
331
332impl<S: PathState> Eq for OwnedPath<S> {}
333
334impl<S: PathState> Eq for Path<S> {}
335
336impl<S: PathState> PartialOrd for OwnedPath<S> {
337 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
338 Some(self.cmp(other))
339 }
340}
341
342impl<S: PathState> Ord for OwnedPath<S> {
343 fn cmp(&self, other: &Self) -> Ordering {
344 self.as_ref().inner.cmp(&other.as_ref().inner)
345 }
346}
347
348impl<S: PathState> PartialOrd for Path<S> {
349 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
350 Some(self.cmp(other))
351 }
352}
353
354impl<S: PathState> Ord for Path<S> {
355 fn cmp(&self, other: &Self) -> Ordering {
356 self.inner.cmp(&other.inner)
357 }
358}
359
360impl<S: PathState> PartialOrd<Path<S>> for OwnedPath<S> {
361 fn partial_cmp(&self, other: &Path<S>) -> Option<Ordering> {
362 Some(self.as_ref().cmp(other))
363 }
364}
365
366impl<S: PathState> PartialOrd<OwnedPath<S>> for Path<S> {
367 fn partial_cmp(&self, other: &OwnedPath<S>) -> Option<Ordering> {
368 Some(self.cmp(other.as_ref()))
369 }
370}
371
372impl<S: PathState> Debug for OwnedPath<S> {
373 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
374 f.debug_struct("OwnedPath")
375 .field("<state>", &util::fmt::raw_type_name::<S>())
376 .field("value", &self.inner)
377 .finish()
378 }
379}
380
381impl<S: PathState> Debug for Path<S> {
382 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
383 f.debug_struct("Path")
384 .field("<state>", &util::fmt::raw_type_name::<S>())
385 .field("value", &&self.inner)
386 .finish()
387 }
388}