1use std::{
2 borrow::{Borrow, Cow},
3 cmp,
4 convert::Infallible,
5 ffi::{OsStr, OsString},
6 fmt::{self, Debug, Display},
7 hash::{Hash, Hasher},
8 ops::Deref,
9 path::{Path, PathBuf},
10 ptr,
11 rc::Rc,
12 sync::Arc,
13};
14
15#[derive(Debug, Copy, Clone, PartialEq, Eq)]
28pub enum Error {
29 NotAbsolute,
31 NotCanonical,
33 ContainsParent,
35}
36
37impl From<Infallible> for Error {
38 fn from(_: Infallible) -> Self {
39 unreachable!()
40 }
41}
42
43impl Display for Error {
44 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
45 const PARENT_ERR: &str = if cfg!(windows) {
46 "path contains a '..' component that points outside of base directory"
47 } else {
48 "path contains a '..' component"
49 };
50
51 use Error::*;
52 match self {
53 NotAbsolute => f.write_str("path is not absolute"),
54 NotCanonical => f.write_str("path is not canonical"),
55 ContainsParent => f.write_str(PARENT_ERR),
56 }
57 }
58}
59
60impl std::error::Error for Error {}
61
62#[derive(Debug, Copy, Clone, PartialEq, Eq)]
67pub struct ConvertError<T> {
68 pub error: Error,
70 pub value: T,
72}
73
74impl<T> ConvertError<T> {
75 #[must_use]
77 #[inline]
78 pub const fn new(error: Error, value: T) -> Self {
79 Self { error, value }
80 }
81
82 #[inline]
85 pub fn map<F, U>(self, f: F) -> ConvertError<U>
86 where
87 F: FnOnce(T) -> U,
88 {
89 ConvertError {
90 error: self.error,
91 value: f(self.value),
92 }
93 }
94}
95
96impl<T: ?Sized> ConvertError<&T> {
97 #[inline]
99 pub fn cloned(&self) -> ConvertError<T>
100 where
101 T: Clone,
102 {
103 ConvertError {
104 error: self.error,
105 value: self.value.clone(),
106 }
107 }
108
109 #[inline]
112 pub fn to_owned(&self) -> ConvertError<T::Owned>
113 where
114 T: ToOwned,
115 {
116 ConvertError {
117 error: self.error,
118 value: self.value.to_owned(),
119 }
120 }
121}
122
123impl<T> From<ConvertError<T>> for Error {
124 #[inline]
126 fn from(value: ConvertError<T>) -> Self {
127 value.error
128 }
129}
130
131impl<T> From<Infallible> for ConvertError<T> {
132 fn from(_: Infallible) -> Self {
133 unreachable!()
134 }
135}
136
137impl<T: Debug> Display for ConvertError<T> {
138 #[inline]
139 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
140 write!(f, "{}: {:?}", self.error, self.value)
141 }
142}
143
144impl<T: Debug> std::error::Error for ConvertError<T> {}
145
146#[repr(transparent)]
158pub struct Normpath(pub(crate) Path);
159
160#[inline]
161pub(crate) unsafe fn cast_ref_unchecked(path: &Path) -> &Normpath {
162 unsafe { &*(ptr::from_ref(path) as *const _) }
164}
165
166#[inline]
167pub(crate) unsafe fn cast_box_unchecked(path: Box<Path>) -> Box<Normpath> {
168 unsafe { Box::from_raw(Box::into_raw(path) as *mut Normpath) }
170}
171
172#[inline]
173unsafe fn cast_arc_unchecked(path: Arc<Path>) -> Arc<Normpath> {
174 unsafe { Arc::from_raw(Arc::into_raw(path) as *const Normpath) }
176}
177
178#[inline]
179unsafe fn cast_rc_unchecked(path: Rc<Path>) -> Rc<Normpath> {
180 unsafe { Rc::from_raw(Rc::into_raw(path) as *const Normpath) }
182}
183
184#[inline]
185fn backcast_box(path: Box<Normpath>) -> Box<Path> {
186 unsafe { Box::from_raw(Box::into_raw(path) as *mut Path) }
188}
189
190impl AsRef<Path> for Normpath {
191 #[inline]
192 fn as_ref(&self) -> &Path {
193 &self.0
194 }
195}
196
197impl AsRef<Normpath> for Normpath {
198 #[inline]
199 fn as_ref(&self) -> &Normpath {
200 self
201 }
202}
203
204impl AsRef<OsStr> for Normpath {
205 #[inline]
206 fn as_ref(&self) -> &OsStr {
207 self.0.as_os_str()
208 }
209}
210
211impl Borrow<Path> for Normpath {
212 #[inline]
213 fn borrow(&self) -> &Path {
214 &self.0
215 }
216}
217
218impl Deref for Normpath {
219 type Target = Path;
220
221 #[inline]
222 fn deref(&self) -> &Self::Target {
223 &self.0
224 }
225}
226
227impl Clone for Box<Normpath> {
228 #[inline]
229 fn clone(&self) -> Self {
230 let path = unsafe { &*(ptr::from_ref(self) as *const Box<Path>) };
232
233 unsafe { cast_box_unchecked(path.clone()) }
235 }
236}
237
238#[derive(Clone)]
250pub struct NormpathBuf(pub(crate) PathBuf);
251
252impl AsRef<Normpath> for NormpathBuf {
253 #[inline]
254 fn as_ref(&self) -> &Normpath {
255 let p = self.0.as_path();
256
257 unsafe { cast_ref_unchecked(p) }
259 }
260}
261
262impl AsRef<Path> for NormpathBuf {
263 #[inline]
264 fn as_ref(&self) -> &Path {
265 &self.0
266 }
267}
268
269impl AsRef<OsStr> for NormpathBuf {
270 #[inline]
271 fn as_ref(&self) -> &OsStr {
272 self.0.as_os_str()
273 }
274}
275
276impl Borrow<Normpath> for NormpathBuf {
277 #[inline]
278 fn borrow(&self) -> &Normpath {
279 self.as_ref()
280 }
281}
282
283impl Borrow<Path> for NormpathBuf {
284 #[inline]
285 fn borrow(&self) -> &Path {
286 self.0.as_path()
287 }
288}
289
290impl Deref for NormpathBuf {
291 type Target = Normpath;
292
293 #[inline]
294 fn deref(&self) -> &Self::Target {
295 self.as_ref()
296 }
297}
298
299impl ToOwned for Normpath {
300 type Owned = NormpathBuf;
301
302 #[inline]
303 fn to_owned(&self) -> Self::Owned {
304 NormpathBuf(self.to_path_buf())
305 }
306}
307
308impl From<&Normpath> for NormpathBuf {
309 #[inline]
313 fn from(value: &Normpath) -> Self {
314 Self(value.to_path_buf())
315 }
316}
317
318impl From<&Normpath> for Box<Normpath> {
319 #[inline]
323 fn from(value: &Normpath) -> Self {
324 let value = Box::from(&value.0);
325 unsafe { cast_box_unchecked(value) }
327 }
328}
329
330impl<'a> From<&'a Normpath> for Cow<'a, Normpath> {
331 #[inline]
335 fn from(value: &'a Normpath) -> Self {
336 Cow::Borrowed(value)
337 }
338}
339
340impl From<&Normpath> for Arc<Normpath> {
341 #[inline]
345 fn from(value: &Normpath) -> Self {
346 let value = Arc::<Path>::from(&value.0);
347 unsafe { cast_arc_unchecked(value) }
349 }
350}
351
352impl From<&Normpath> for Rc<Normpath> {
353 #[inline]
357 fn from(value: &Normpath) -> Self {
358 let value = Rc::<Path>::from(&value.0);
359 unsafe { cast_rc_unchecked(value) }
361 }
362}
363
364impl From<Box<Normpath>> for NormpathBuf {
365 #[inline]
369 fn from(value: Box<Normpath>) -> Self {
370 let value = backcast_box(value);
371 Self(value.into_path_buf())
372 }
373}
374
375impl From<Box<Normpath>> for PathBuf {
376 #[inline]
380 fn from(value: Box<Normpath>) -> Self {
381 let value = backcast_box(value);
382 value.into_path_buf()
383 }
384}
385
386impl From<Box<Normpath>> for Box<Path> {
387 #[inline]
391 fn from(value: Box<Normpath>) -> Self {
392 backcast_box(value)
393 }
394}
395
396impl From<NormpathBuf> for Box<Normpath> {
397 #[inline]
402 fn from(value: NormpathBuf) -> Self {
403 let path = value.0.into_boxed_path();
404 unsafe { cast_box_unchecked(path) }
406 }
407}
408
409impl From<NormpathBuf> for Cow<'_, Normpath> {
410 #[inline]
414 fn from(value: NormpathBuf) -> Self {
415 Cow::Owned(value)
416 }
417}
418
419impl From<NormpathBuf> for Arc<Normpath> {
420 #[inline]
424 fn from(value: NormpathBuf) -> Self {
425 let path = Arc::<Path>::from(value.0);
426 unsafe { cast_arc_unchecked(path) }
428 }
429}
430
431impl From<NormpathBuf> for Rc<Normpath> {
432 #[inline]
436 fn from(value: NormpathBuf) -> Self {
437 let path = Rc::<Path>::from(value.0);
438 unsafe { cast_rc_unchecked(path) }
440 }
441}
442
443impl From<NormpathBuf> for PathBuf {
444 #[inline]
448 fn from(value: NormpathBuf) -> Self {
449 value.0
450 }
451}
452
453impl From<NormpathBuf> for OsString {
454 #[inline]
458 fn from(value: NormpathBuf) -> Self {
459 value.0.into_os_string()
460 }
461}
462
463impl<'a> From<&'a NormpathBuf> for Cow<'a, Normpath> {
464 #[inline]
468 fn from(value: &'a NormpathBuf) -> Self {
469 Cow::Borrowed(value.as_ref())
470 }
471}
472
473impl From<&NormpathBuf> for NormpathBuf {
474 #[inline]
476 fn from(value: &NormpathBuf) -> Self {
477 value.clone()
478 }
479}
480
481impl From<Cow<'_, Normpath>> for NormpathBuf {
482 #[inline]
486 fn from(value: Cow<'_, Normpath>) -> Self {
487 use Cow::*;
488 match value {
489 Borrowed(value) => Self(value.to_path_buf()),
490 Owned(value) => value,
491 }
492 }
493}
494
495impl<'a> From<Cow<'a, Normpath>> for Box<Normpath> {
496 #[inline]
503 fn from(value: Cow<'a, Normpath>) -> Self {
504 let path = match value {
505 Cow::Borrowed(value) => Box::from(&value.0),
506 Cow::Owned(value) => value.0.into_boxed_path(),
507 };
508
509 unsafe { cast_box_unchecked(path) }
512 }
513}
514
515impl PartialEq for Normpath {
516 #[inline]
517 fn eq(&self, other: &Self) -> bool {
518 self.0.as_os_str() == other.0.as_os_str()
519 }
520}
521
522impl Eq for Normpath {}
523
524impl Hash for Normpath {
525 #[inline]
526 fn hash<H: Hasher>(&self, state: &mut H) {
527 self.0.as_os_str().hash(state);
528 }
529}
530
531impl Ord for Normpath {
532 #[inline]
533 fn cmp(&self, other: &Self) -> cmp::Ordering {
534 self.0.as_os_str().cmp(other.0.as_os_str())
535 }
536}
537
538impl PartialOrd for Normpath {
539 #[inline]
540 fn partial_cmp(&self, other: &Self) -> Option<cmp::Ordering> {
541 Some(self.cmp(other))
542 }
543}
544
545impl PartialEq for NormpathBuf {
546 #[inline]
547 fn eq(&self, other: &Self) -> bool {
548 self.0.as_os_str() == other.0.as_os_str()
549 }
550}
551
552impl Eq for NormpathBuf {}
553
554impl Hash for NormpathBuf {
555 #[inline]
556 fn hash<H: Hasher>(&self, state: &mut H) {
557 self.0.as_os_str().hash(state);
558 }
559}
560
561impl Ord for NormpathBuf {
562 #[inline]
563 fn cmp(&self, other: &Self) -> cmp::Ordering {
564 self.0.as_os_str().cmp(other.0.as_os_str())
565 }
566}
567
568impl PartialOrd for NormpathBuf {
569 #[inline]
570 fn partial_cmp(&self, other: &Self) -> Option<cmp::Ordering> {
571 Some(self.cmp(other))
572 }
573}
574
575impl PartialEq<Normpath> for NormpathBuf {
576 #[inline]
577 fn eq(&self, other: &Normpath) -> bool {
578 self.0.as_os_str() == other.0.as_os_str()
579 }
580}
581
582impl PartialEq<NormpathBuf> for Normpath {
583 #[inline]
584 fn eq(&self, other: &NormpathBuf) -> bool {
585 self.0.as_os_str() == other.0.as_os_str()
586 }
587}
588
589impl PartialOrd<Normpath> for NormpathBuf {
590 #[inline]
591 fn partial_cmp(&self, other: &Normpath) -> Option<cmp::Ordering> {
592 Some(self.0.as_os_str().cmp(other.0.as_os_str()))
593 }
594}
595
596impl PartialOrd<NormpathBuf> for Normpath {
597 #[inline]
598 fn partial_cmp(&self, other: &NormpathBuf) -> Option<cmp::Ordering> {
599 Some(self.0.as_os_str().cmp(other.0.as_os_str()))
600 }
601}
602
603macro_rules! impl_cmp {
604 (<$($life:lifetime),*> $lhs:ty, $rhs:ty) => {
605 impl<$($life),*> PartialEq<$rhs> for $lhs {
606 #[inline]
607 fn eq(&self, other: &$rhs) -> bool {
608 <Path as PartialEq>::eq(self.as_ref(), other.as_ref())
609 }
610 }
611
612 impl<$($life),*> PartialEq<$lhs> for $rhs {
613 #[inline]
614 fn eq(&self, other: &$lhs) -> bool {
615 <Path as PartialEq>::eq(other.as_ref(), self.as_ref())
616 }
617 }
618
619 impl<$($life),*> PartialOrd<$rhs> for $lhs {
620 #[inline]
621 fn partial_cmp(&self, other: &$rhs) -> Option<std::cmp::Ordering> {
622 <Path as PartialOrd>::partial_cmp(self.as_ref(), other.as_ref())
623 }
624 }
625
626 impl<$($life),*> PartialOrd<$lhs> for $rhs {
627 #[inline]
628 fn partial_cmp(&self, other: &$lhs) -> Option<std::cmp::Ordering> {
629 <Path as PartialOrd>::partial_cmp(other.as_ref(), self.as_ref())
630 }
631 }
632 };
633}
634
635impl_cmp!(<> Normpath, Path);
636impl_cmp!(<'a> Normpath, &'a Path);
637impl_cmp!(<> Normpath, PathBuf);
638impl_cmp!(<'a> Normpath, Cow<'a, Path>);
639impl_cmp!(<> Normpath, OsStr);
640impl_cmp!(<'a> Normpath, &'a OsStr);
641impl_cmp!(<> Normpath, OsString);
642impl_cmp!(<'a> Normpath, Cow<'a, OsStr>);
643
644impl_cmp!(<> NormpathBuf, Path);
645impl_cmp!(<'a> NormpathBuf, &'a Path);
646impl_cmp!(<> NormpathBuf, PathBuf);
647impl_cmp!(<'a> NormpathBuf, Cow<'a, Path>);
648impl_cmp!(<> NormpathBuf, OsStr);
649impl_cmp!(<'a> NormpathBuf, &'a OsStr);
650impl_cmp!(<> NormpathBuf, OsString);
651impl_cmp!(<'a> NormpathBuf, Cow<'a, OsStr>);
652
653impl_cmp!(<'a> &'a Normpath, Path);
654impl_cmp!(<'a> &'a Normpath, PathBuf);
655impl_cmp!(<'a, 'b> &'a Normpath, Cow<'b, Path>);
656impl_cmp!(<'a> &'a Normpath, OsStr);
657impl_cmp!(<'a> &'a Normpath, OsString);
658impl_cmp!(<'a, 'b> &'a Normpath, Cow<'b, OsStr>);
659
660macro_rules! impl_eq_literal {
661 ($lhs:ty, $rhs:ty) => {
662 impl PartialEq<$rhs> for $lhs {
663 #[inline]
664 fn eq(&self, other: &$rhs) -> bool {
665 <OsStr as PartialEq>::eq(self.as_ref(), other.as_ref())
666 }
667 }
668
669 impl PartialEq<$lhs> for $rhs {
670 #[inline]
671 fn eq(&self, other: &$lhs) -> bool {
672 <OsStr as PartialEq>::eq(other.as_ref(), self.as_ref())
673 }
674 }
675 };
676}
677
678impl_eq_literal!(Normpath, str);
679impl_eq_literal!(NormpathBuf, str);
680impl_eq_literal!(Normpath, String);
681impl_eq_literal!(NormpathBuf, String);
682
683impl Debug for Normpath {
684 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
685 Debug::fmt(&self.0, f)
686 }
687}
688
689impl Debug for NormpathBuf {
690 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
691 Debug::fmt(&self.0, f)
692 }
693}