1#![cfg_attr(not(feature = "std"), no_std)]
64#![cfg_attr(feature = "shrink_to", feature(shrink_to))]
65
66#[cfg(feature = "alloc")]
67extern crate alloc;
68
69use unix_str::UnixStr;
70#[cfg(feature = "alloc")]
71use unix_str::UnixString;
72
73#[cfg(feature = "alloc")]
74use core::borrow::Borrow;
75use core::cmp;
76use core::fmt;
77use core::hash::{Hash, Hasher};
78#[cfg(feature = "alloc")]
79use core::iter;
80use core::iter::FusedIterator;
81#[cfg(feature = "alloc")]
82use core::ops::{self, Deref};
83
84#[cfg(feature = "alloc")]
85use alloc::{
86 borrow::{Cow, ToOwned},
87 boxed::Box,
88 rc::Rc,
89 str::FromStr,
90 string::String,
91 sync::Arc,
92 vec::Vec,
93};
94
95#[cfg(feature = "std")]
96use std::error::Error;
97
98mod lossy;
99
100pub fn is_separator(c: char) -> bool {
114 c == '/'
115}
116
117pub const MAIN_SEPARATOR: char = '/';
119
120fn iter_after<'a, 'b, I, J>(mut iter: I, mut prefix: J) -> Option<I>
128where
129 I: Iterator<Item = Component<'a>> + Clone,
130 J: Iterator<Item = Component<'b>>,
131{
132 loop {
133 let mut iter_next = iter.clone();
134 match (iter_next.next(), prefix.next()) {
135 (Some(ref x), Some(ref y)) if x == y => (),
136 (Some(_), Some(_)) => return None,
137 (Some(_), None) => return Some(iter),
138 (None, None) => return Some(iter),
139 (None, Some(_)) => return None,
140 }
141 iter = iter_next;
142 }
143}
144
145fn unix_str_as_u8_slice(s: &UnixStr) -> &[u8] {
146 unsafe { &*(s as *const UnixStr as *const [u8]) }
147}
148unsafe fn u8_slice_as_unix_str(s: &[u8]) -> &UnixStr {
149 &*(s as *const [u8] as *const UnixStr)
150}
151
152fn has_physical_root(path: &[u8]) -> bool {
158 !path.is_empty() && path[0] == b'/'
159}
160
161fn split_file_at_dot(file: &UnixStr) -> (Option<&UnixStr>, Option<&UnixStr>) {
163 unsafe {
164 if unix_str_as_u8_slice(file) == b".." {
165 return (Some(file), None);
166 }
167
168 let mut iter = unix_str_as_u8_slice(file).rsplitn(2, |b| *b == b'.');
174 let after = iter.next();
175 let before = iter.next();
176 if before == Some(b"") {
177 (Some(file), None)
178 } else {
179 (
180 before.map(|s| u8_slice_as_unix_str(s)),
181 after.map(|s| u8_slice_as_unix_str(s)),
182 )
183 }
184 }
185}
186
187#[derive(Copy, Clone, PartialEq, PartialOrd, Debug)]
198enum State {
199 Prefix = 0,
200 StartDir = 1, Body = 2, Done = 3,
203}
204
205#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
232pub enum Component<'a> {
233 RootDir,
237
238 CurDir,
240
241 ParentDir,
243
244 Normal(&'a UnixStr),
249}
250
251impl<'a> Component<'a> {
252 pub fn as_unix_str(self) -> &'a UnixStr {
264 match self {
265 Component::RootDir => UnixStr::new("/"),
266 Component::CurDir => UnixStr::new("."),
267 Component::ParentDir => UnixStr::new(".."),
268 Component::Normal(path) => path,
269 }
270 }
271}
272
273impl AsRef<UnixStr> for Component<'_> {
274 fn as_ref(&self) -> &UnixStr {
275 self.as_unix_str()
276 }
277}
278
279impl AsRef<Path> for Component<'_> {
280 fn as_ref(&self) -> &Path {
281 self.as_unix_str().as_ref()
282 }
283}
284
285#[derive(Clone)]
306pub struct Components<'a> {
307 path: &'a [u8],
309
310 has_physical_root: bool,
312
313 front: State,
316 back: State,
317}
318
319#[derive(Clone)]
328pub struct Iter<'a> {
329 inner: Components<'a>,
330}
331
332impl fmt::Debug for Components<'_> {
333 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
334 struct DebugHelper<'a>(&'a Path);
335
336 impl fmt::Debug for DebugHelper<'_> {
337 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
338 f.debug_list().entries(self.0.components()).finish()
339 }
340 }
341
342 f.debug_tuple("Components")
343 .field(&DebugHelper(self.as_path()))
344 .finish()
345 }
346}
347
348impl<'a> Components<'a> {
349 #[inline]
351 fn len_before_body(&self) -> usize {
352 let root = if self.front <= State::StartDir && self.has_physical_root {
353 1
354 } else {
355 0
356 };
357 let cur_dir = if self.front <= State::StartDir && self.include_cur_dir() {
358 1
359 } else {
360 0
361 };
362 root + cur_dir
363 }
364
365 #[inline]
367 fn finished(&self) -> bool {
368 self.front == State::Done || self.back == State::Done || self.front > self.back
369 }
370
371 #[inline]
372 fn is_sep_byte(&self, b: u8) -> bool {
373 b == b'/'
374 }
375
376 pub fn as_path(&self) -> &'a Path {
390 let mut comps = self.clone();
391 if comps.front == State::Body {
392 comps.trim_left();
393 }
394 if comps.back == State::Body {
395 comps.trim_right();
396 }
397 unsafe { Path::from_u8_slice(comps.path) }
398 }
399
400 fn has_root(&self) -> bool {
402 self.has_physical_root
403 }
404
405 fn include_cur_dir(&self) -> bool {
407 if self.has_root() {
408 return false;
409 }
410 let mut iter = self.path[..].iter();
411 match (iter.next(), iter.next()) {
412 (Some(&b'.'), None) => true,
413 (Some(&b'.'), Some(&b)) => self.is_sep_byte(b),
414 _ => false,
415 }
416 }
417
418 fn parse_single_component<'b>(&self, comp: &'b [u8]) -> Option<Component<'b>> {
420 match comp {
421 b"." => None, b".." => Some(Component::ParentDir),
425 b"" => None,
426 _ => Some(Component::Normal(unsafe { u8_slice_as_unix_str(comp) })),
427 }
428 }
429
430 fn parse_next_component(&self) -> (usize, Option<Component<'a>>) {
433 debug_assert!(self.front == State::Body);
434 let (extra, comp) = match self.path.iter().position(|b| self.is_sep_byte(*b)) {
435 None => (0, self.path),
436 Some(i) => (1, &self.path[..i]),
437 };
438 (comp.len() + extra, self.parse_single_component(comp))
439 }
440
441 fn parse_next_component_back(&self) -> (usize, Option<Component<'a>>) {
444 debug_assert!(self.back == State::Body);
445 let start = self.len_before_body();
446 let (extra, comp) = match self.path[start..]
447 .iter()
448 .rposition(|b| self.is_sep_byte(*b))
449 {
450 None => (0, &self.path[start..]),
451 Some(i) => (1, &self.path[start + i + 1..]),
452 };
453 (comp.len() + extra, self.parse_single_component(comp))
454 }
455
456 fn trim_left(&mut self) {
458 while !self.path.is_empty() {
459 let (size, comp) = self.parse_next_component();
460 if comp.is_some() {
461 return;
462 } else {
463 self.path = &self.path[size..];
464 }
465 }
466 }
467
468 fn trim_right(&mut self) {
470 while self.path.len() > self.len_before_body() {
471 let (size, comp) = self.parse_next_component_back();
472 if comp.is_some() {
473 return;
474 } else {
475 self.path = &self.path[..self.path.len() - size];
476 }
477 }
478 }
479}
480
481impl AsRef<Path> for Components<'_> {
482 fn as_ref(&self) -> &Path {
483 self.as_path()
484 }
485}
486
487impl AsRef<UnixStr> for Components<'_> {
488 fn as_ref(&self) -> &UnixStr {
489 self.as_path().as_unix_str()
490 }
491}
492
493impl fmt::Debug for Iter<'_> {
494 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
495 struct DebugHelper<'a>(&'a Path);
496
497 impl fmt::Debug for DebugHelper<'_> {
498 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
499 f.debug_list().entries(self.0.iter()).finish()
500 }
501 }
502
503 f.debug_tuple("Iter")
504 .field(&DebugHelper(self.as_path()))
505 .finish()
506 }
507}
508
509impl<'a> Iter<'a> {
510 pub fn as_path(&self) -> &'a Path {
524 self.inner.as_path()
525 }
526}
527
528impl AsRef<Path> for Iter<'_> {
529 fn as_ref(&self) -> &Path {
530 self.as_path()
531 }
532}
533
534impl AsRef<UnixStr> for Iter<'_> {
535 fn as_ref(&self) -> &UnixStr {
536 self.as_path().as_unix_str()
537 }
538}
539
540impl<'a> Iterator for Iter<'a> {
541 type Item = &'a UnixStr;
542
543 fn next(&mut self) -> Option<Self::Item> {
544 self.inner.next().map(Component::as_unix_str)
545 }
546}
547
548impl<'a> DoubleEndedIterator for Iter<'a> {
549 fn next_back(&mut self) -> Option<Self::Item> {
550 self.inner.next_back().map(Component::as_unix_str)
551 }
552}
553
554impl FusedIterator for Iter<'_> {}
555
556impl<'a> Iterator for Components<'a> {
557 type Item = Component<'a>;
558
559 fn next(&mut self) -> Option<Component<'a>> {
560 while !self.finished() {
561 match self.front {
562 State::Prefix => {
563 self.front = State::StartDir;
564 }
565 State::StartDir => {
566 self.front = State::Body;
567 if self.has_physical_root {
568 debug_assert!(!self.path.is_empty());
569 self.path = &self.path[1..];
570 return Some(Component::RootDir);
571 } else if self.include_cur_dir() {
572 debug_assert!(!self.path.is_empty());
573 self.path = &self.path[1..];
574 return Some(Component::CurDir);
575 }
576 }
577 State::Body if !self.path.is_empty() => {
578 let (size, comp) = self.parse_next_component();
579 self.path = &self.path[size..];
580 if comp.is_some() {
581 return comp;
582 }
583 }
584 State::Body => {
585 self.front = State::Done;
586 }
587 State::Done => unreachable!(),
588 }
589 }
590 None
591 }
592}
593
594impl<'a> DoubleEndedIterator for Components<'a> {
595 fn next_back(&mut self) -> Option<Component<'a>> {
596 while !self.finished() {
597 match self.back {
598 State::Body if self.path.len() > self.len_before_body() => {
599 let (size, comp) = self.parse_next_component_back();
600 self.path = &self.path[..self.path.len() - size];
601 if comp.is_some() {
602 return comp;
603 }
604 }
605 State::Body => {
606 self.back = State::StartDir;
607 }
608 State::StartDir => {
609 self.back = State::Prefix;
610 if self.has_physical_root {
611 self.path = &self.path[..self.path.len() - 1];
612 return Some(Component::RootDir);
613 } else if self.include_cur_dir() {
614 self.path = &self.path[..self.path.len() - 1];
615 return Some(Component::CurDir);
616 }
617 }
618 State::Prefix => {
619 self.back = State::Done;
620 return None;
621 }
622 State::Done => unreachable!(),
623 }
624 }
625 None
626 }
627}
628
629impl FusedIterator for Components<'_> {}
630
631impl<'a> cmp::PartialEq for Components<'a> {
632 fn eq(&self, other: &Components<'a>) -> bool {
633 Iterator::eq(self.clone(), other.clone())
634 }
635}
636
637impl cmp::Eq for Components<'_> {}
638
639impl<'a> cmp::PartialOrd for Components<'a> {
640 fn partial_cmp(&self, other: &Components<'a>) -> Option<cmp::Ordering> {
641 Iterator::partial_cmp(self.clone(), other.clone())
642 }
643}
644
645impl cmp::Ord for Components<'_> {
646 fn cmp(&self, other: &Self) -> cmp::Ordering {
647 Iterator::cmp(self.clone(), other.clone())
648 }
649}
650
651#[derive(Copy, Clone, Debug)]
671pub struct Ancestors<'a> {
672 next: Option<&'a Path>,
673}
674
675impl<'a> Iterator for Ancestors<'a> {
676 type Item = &'a Path;
677
678 fn next(&mut self) -> Option<Self::Item> {
679 let next = self.next;
680 self.next = next.and_then(Path::parent);
681 next
682 }
683}
684
685impl FusedIterator for Ancestors<'_> {}
686
687#[derive(Clone)]
741#[cfg(feature = "alloc")]
742pub struct PathBuf {
743 inner: UnixString,
744}
745
746#[cfg(feature = "alloc")]
747impl PathBuf {
748 fn as_mut_vec(&mut self) -> &mut Vec<u8> {
749 unsafe { &mut *(self as *mut PathBuf as *mut Vec<u8>) }
750 }
751
752 pub fn new() -> PathBuf {
762 PathBuf {
763 inner: UnixString::new(),
764 }
765 }
766
767 pub fn with_capacity(capacity: usize) -> PathBuf {
784 PathBuf {
785 inner: UnixString::with_capacity(capacity),
786 }
787 }
788
789 pub fn as_path(&self) -> &Path {
802 self
803 }
804
805 pub fn push<P: AsRef<Path>>(&mut self, path: P) {
831 self._push(path.as_ref())
832 }
833
834 fn _push(&mut self, path: &Path) {
835 let need_sep = self
837 .as_mut_vec()
838 .last()
839 .map(|c| *c != b'/')
840 .unwrap_or(false);
841
842 if path.is_absolute() || path.has_root() {
844 self.as_mut_vec().truncate(0);
845 } else if need_sep {
846 self.inner.push("/");
847 }
848
849 self.inner.push(path.as_unix_str());
850 }
851
852 pub fn pop(&mut self) -> bool {
872 match self.parent().map(|p| p.as_unix_str().len()) {
873 Some(len) => {
874 self.as_mut_vec().truncate(len);
875 true
876 }
877 None => false,
878 }
879 }
880
881 pub fn set_file_name<S: AsRef<UnixStr>>(&mut self, file_name: S) {
907 self._set_file_name(file_name.as_ref())
908 }
909
910 fn _set_file_name(&mut self, file_name: &UnixStr) {
911 if self.file_name().is_some() {
912 let popped = self.pop();
913 debug_assert!(popped);
914 }
915 self.push(file_name);
916 }
917
918 pub fn set_extension<S: AsRef<UnixStr>>(&mut self, extension: S) -> bool {
944 self._set_extension(extension.as_ref())
945 }
946
947 fn _set_extension(&mut self, extension: &UnixStr) -> bool {
948 let file_stem = match self.file_stem() {
949 None => return false,
950 Some(f) => unix_str_as_u8_slice(f),
951 };
952
953 let end_file_stem = file_stem[file_stem.len()..].as_ptr() as usize;
955 let start = unix_str_as_u8_slice(&self.inner).as_ptr() as usize;
956 let v = self.as_mut_vec();
957 v.truncate(end_file_stem.wrapping_sub(start));
958
959 let new = unix_str_as_u8_slice(extension);
961 if !new.is_empty() {
962 v.reserve_exact(new.len() + 1);
963 v.push(b'.');
964 v.extend_from_slice(new);
965 }
966
967 true
968 }
969
970 pub fn into_unix_string(self) -> UnixString {
981 self.inner
982 }
983
984 pub fn into_boxed_path(self) -> Box<Path> {
988 let rw = Box::into_raw(self.inner.into_boxed_unix_str()) as *mut Path;
989 unsafe { Box::from_raw(rw) }
990 }
991
992 pub fn capacity(&self) -> usize {
994 self.inner.capacity()
995 }
996
997 pub fn clear(&mut self) {
999 self.inner.clear()
1000 }
1001
1002 pub fn reserve(&mut self, additional: usize) {
1004 self.inner.reserve(additional)
1005 }
1006
1007 pub fn reserve_exact(&mut self, additional: usize) {
1009 self.inner.reserve_exact(additional)
1010 }
1011
1012 pub fn shrink_to_fit(&mut self) {
1014 self.inner.shrink_to_fit()
1015 }
1016
1017 #[cfg(feature = "shrink_to")]
1019 pub fn shrink_to(&mut self, min_capacity: usize) {
1020 self.inner.shrink_to(min_capacity)
1021 }
1022}
1023
1024#[cfg(feature = "alloc")]
1025impl From<&Path> for Box<Path> {
1026 fn from(path: &Path) -> Box<Path> {
1027 let boxed: Box<UnixStr> = path.inner.into();
1028 let rw = Box::into_raw(boxed) as *mut Path;
1029 unsafe { Box::from_raw(rw) }
1030 }
1031}
1032
1033#[cfg(feature = "alloc")]
1034impl From<Cow<'_, Path>> for Box<Path> {
1035 #[inline]
1036 fn from(cow: Cow<'_, Path>) -> Box<Path> {
1037 match cow {
1038 Cow::Borrowed(path) => Box::from(path),
1039 Cow::Owned(path) => Box::from(path),
1040 }
1041 }
1042}
1043
1044#[cfg(feature = "alloc")]
1045impl From<Box<Path>> for PathBuf {
1046 fn from(boxed: Box<Path>) -> PathBuf {
1050 boxed.into_path_buf()
1051 }
1052}
1053
1054#[cfg(feature = "alloc")]
1055impl From<PathBuf> for Box<Path> {
1056 fn from(p: PathBuf) -> Self {
1061 p.into_boxed_path()
1062 }
1063}
1064
1065#[cfg(feature = "alloc")]
1066impl Clone for Box<Path> {
1067 #[inline]
1068 fn clone(&self) -> Self {
1069 self.to_path_buf().into_boxed_path()
1070 }
1071}
1072
1073#[cfg(feature = "alloc")]
1074impl<T: ?Sized + AsRef<UnixStr>> From<&T> for PathBuf {
1075 fn from(s: &T) -> Self {
1076 PathBuf::from(s.as_ref().to_unix_string())
1077 }
1078}
1079
1080#[cfg(feature = "alloc")]
1081impl From<UnixString> for PathBuf {
1082 #[inline]
1086 fn from(s: UnixString) -> Self {
1087 PathBuf { inner: s }
1088 }
1089}
1090
1091#[cfg(feature = "alloc")]
1092impl From<PathBuf> for UnixString {
1093 fn from(path_buf: PathBuf) -> Self {
1097 path_buf.inner
1098 }
1099}
1100
1101#[cfg(feature = "alloc")]
1102impl From<String> for PathBuf {
1103 fn from(s: String) -> PathBuf {
1107 PathBuf::from(UnixString::from(s))
1108 }
1109}
1110
1111#[cfg(feature = "alloc")]
1112impl FromStr for PathBuf {
1113 type Err = core::convert::Infallible;
1114
1115 fn from_str(s: &str) -> Result<Self, Self::Err> {
1116 Ok(PathBuf::from(s))
1117 }
1118}
1119
1120#[cfg(feature = "alloc")]
1121impl<P: AsRef<Path>> iter::FromIterator<P> for PathBuf {
1122 fn from_iter<I: IntoIterator<Item = P>>(iter: I) -> PathBuf {
1123 let mut buf = PathBuf::new();
1124 buf.extend(iter);
1125 buf
1126 }
1127}
1128
1129#[cfg(feature = "alloc")]
1130impl<P: AsRef<Path>> iter::Extend<P> for PathBuf {
1131 fn extend<I: IntoIterator<Item = P>>(&mut self, iter: I) {
1132 iter.into_iter().for_each(move |p| self.push(p.as_ref()));
1133 }
1134}
1135
1136#[cfg(feature = "alloc")]
1137impl fmt::Debug for PathBuf {
1138 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
1139 fmt::Debug::fmt(&**self, formatter)
1140 }
1141}
1142
1143#[cfg(feature = "alloc")]
1144impl ops::Deref for PathBuf {
1145 type Target = Path;
1146 #[inline]
1147 fn deref(&self) -> &Path {
1148 Path::new(&self.inner)
1149 }
1150}
1151
1152#[cfg(feature = "alloc")]
1153impl Borrow<Path> for PathBuf {
1154 fn borrow(&self) -> &Path {
1155 self.deref()
1156 }
1157}
1158
1159#[cfg(feature = "alloc")]
1160impl Default for PathBuf {
1161 fn default() -> Self {
1162 PathBuf::new()
1163 }
1164}
1165
1166#[cfg(feature = "alloc")]
1167impl<'a> From<&'a Path> for Cow<'a, Path> {
1168 #[inline]
1169 fn from(s: &'a Path) -> Cow<'a, Path> {
1170 Cow::Borrowed(s)
1171 }
1172}
1173
1174#[cfg(feature = "alloc")]
1175impl<'a> From<PathBuf> for Cow<'a, Path> {
1176 #[inline]
1177 fn from(s: PathBuf) -> Cow<'a, Path> {
1178 Cow::Owned(s)
1179 }
1180}
1181
1182#[cfg(feature = "alloc")]
1183impl<'a> From<&'a PathBuf> for Cow<'a, Path> {
1184 #[inline]
1185 fn from(p: &'a PathBuf) -> Cow<'a, Path> {
1186 Cow::Borrowed(p.as_path())
1187 }
1188}
1189
1190#[cfg(feature = "alloc")]
1191impl<'a> From<Cow<'a, Path>> for PathBuf {
1192 #[inline]
1193 fn from(p: Cow<'a, Path>) -> Self {
1194 p.into_owned()
1195 }
1196}
1197
1198#[cfg(feature = "alloc")]
1199impl From<PathBuf> for Arc<Path> {
1200 #[inline]
1202 fn from(s: PathBuf) -> Arc<Path> {
1203 let arc: Arc<UnixStr> = Arc::from(s.into_unix_string());
1204 unsafe { Arc::from_raw(Arc::into_raw(arc) as *const Path) }
1205 }
1206}
1207
1208#[cfg(feature = "alloc")]
1209impl From<&Path> for Arc<Path> {
1210 #[inline]
1212 fn from(s: &Path) -> Arc<Path> {
1213 let arc: Arc<UnixStr> = Arc::from(s.as_unix_str());
1214 unsafe { Arc::from_raw(Arc::into_raw(arc) as *const Path) }
1215 }
1216}
1217
1218#[cfg(feature = "alloc")]
1219impl From<PathBuf> for Rc<Path> {
1220 #[inline]
1222 fn from(s: PathBuf) -> Rc<Path> {
1223 let rc: Rc<UnixStr> = Rc::from(s.into_unix_string());
1224 unsafe { Rc::from_raw(Rc::into_raw(rc) as *const Path) }
1225 }
1226}
1227
1228#[cfg(feature = "alloc")]
1229impl From<&Path> for Rc<Path> {
1230 #[inline]
1232 fn from(s: &Path) -> Rc<Path> {
1233 let rc: Rc<UnixStr> = Rc::from(s.as_unix_str());
1234 unsafe { Rc::from_raw(Rc::into_raw(rc) as *const Path) }
1235 }
1236}
1237
1238#[cfg(feature = "alloc")]
1239impl ToOwned for Path {
1240 type Owned = PathBuf;
1241 fn to_owned(&self) -> PathBuf {
1242 self.to_path_buf()
1243 }
1244}
1245
1246#[cfg(feature = "alloc")]
1247impl cmp::PartialEq for PathBuf {
1248 fn eq(&self, other: &PathBuf) -> bool {
1249 self.components() == other.components()
1250 }
1251}
1252
1253#[cfg(feature = "alloc")]
1254impl Hash for PathBuf {
1255 fn hash<H: Hasher>(&self, h: &mut H) {
1256 self.as_path().hash(h)
1257 }
1258}
1259
1260#[cfg(feature = "alloc")]
1261impl cmp::Eq for PathBuf {}
1262
1263#[cfg(feature = "alloc")]
1264impl cmp::PartialOrd for PathBuf {
1265 fn partial_cmp(&self, other: &PathBuf) -> Option<cmp::Ordering> {
1266 self.components().partial_cmp(other.components())
1267 }
1268}
1269
1270#[cfg(feature = "alloc")]
1271impl cmp::Ord for PathBuf {
1272 fn cmp(&self, other: &PathBuf) -> cmp::Ordering {
1273 self.components().cmp(other.components())
1274 }
1275}
1276
1277#[cfg(feature = "alloc")]
1278impl AsRef<UnixStr> for PathBuf {
1279 fn as_ref(&self) -> &UnixStr {
1280 &self.inner[..]
1281 }
1282}
1283
1284pub struct Path {
1317 inner: UnixStr,
1318}
1319
1320#[derive(Debug, Clone, PartialEq, Eq)]
1329pub struct StripPrefixError(());
1330
1331impl Path {
1332 unsafe fn from_u8_slice(s: &[u8]) -> &Path {
1335 Path::new(u8_slice_as_unix_str(s))
1336 }
1337 fn as_u8_slice(&self) -> &[u8] {
1339 unix_str_as_u8_slice(&self.inner)
1340 }
1341
1342 pub fn new<S: AsRef<UnixStr> + ?Sized>(s: &S) -> &Path {
1365 unsafe { &*(s.as_ref() as *const UnixStr as *const Path) }
1366 }
1367
1368 pub fn as_unix_str(&self) -> &UnixStr {
1380 &self.inner
1381 }
1382
1383 pub fn to_str(&self) -> Option<&str> {
1398 self.inner.to_str()
1399 }
1400
1401 #[cfg(feature = "alloc")]
1421 pub fn to_string_lossy(&self) -> Cow<'_, str> {
1422 self.inner.to_string_lossy()
1423 }
1424
1425 #[cfg(feature = "alloc")]
1438 pub fn to_path_buf(&self) -> PathBuf {
1439 PathBuf::from(&self.inner)
1440 }
1441
1442 pub fn is_absolute(&self) -> bool {
1458 self.has_root()
1459 }
1460
1461 pub fn is_relative(&self) -> bool {
1475 !self.is_absolute()
1476 }
1477
1478 pub fn has_root(&self) -> bool {
1490 self.components().has_root()
1491 }
1492
1493 pub fn parent(&self) -> Option<&Path> {
1511 let mut comps = self.components();
1512 let comp = comps.next_back();
1513 comp.and_then(|p| match p {
1514 Component::Normal(_) | Component::CurDir | Component::ParentDir => {
1515 Some(comps.as_path())
1516 }
1517 _ => None,
1518 })
1519 }
1520
1521 pub fn ancestors(&self) -> Ancestors<'_> {
1543 Ancestors { next: Some(&self) }
1544 }
1545
1546 pub fn file_name(&self) -> Option<&UnixStr> {
1567 self.components().next_back().and_then(|p| match p {
1568 Component::Normal(p) => Some(p),
1569 _ => None,
1570 })
1571 }
1572
1573 pub fn strip_prefix<P>(&self, base: P) -> Result<&Path, StripPrefixError>
1601 where
1602 P: AsRef<Path>,
1603 {
1604 self._strip_prefix(base.as_ref())
1605 }
1606
1607 fn _strip_prefix(&self, base: &Path) -> Result<&Path, StripPrefixError> {
1608 iter_after(self.components(), base.components())
1609 .map(|c| c.as_path())
1610 .ok_or(StripPrefixError(()))
1611 }
1612
1613 pub fn starts_with<P: AsRef<Path>>(&self, base: P) -> bool {
1632 self._starts_with(base.as_ref())
1633 }
1634
1635 fn _starts_with(&self, base: &Path) -> bool {
1636 iter_after(self.components(), base.components()).is_some()
1637 }
1638
1639 pub fn ends_with<P: AsRef<Path>>(&self, child: P) -> bool {
1653 self._ends_with(child.as_ref())
1654 }
1655
1656 fn _ends_with(&self, child: &Path) -> bool {
1657 iter_after(self.components().rev(), child.components().rev()).is_some()
1658 }
1659
1660 pub fn file_stem(&self) -> Option<&UnixStr> {
1681 self.file_name()
1682 .map(split_file_at_dot)
1683 .and_then(|(before, after)| before.or(after))
1684 }
1685
1686 pub fn extension(&self) -> Option<&UnixStr> {
1708 self.file_name()
1709 .map(split_file_at_dot)
1710 .and_then(|(before, after)| before.and(after))
1711 }
1712
1713 #[must_use]
1728 #[cfg(feature = "alloc")]
1729 pub fn join<P: AsRef<Path>>(&self, path: P) -> PathBuf {
1730 self._join(path.as_ref())
1731 }
1732
1733 #[cfg(feature = "alloc")]
1734 fn _join(&self, path: &Path) -> PathBuf {
1735 let mut buf = self.to_path_buf();
1736 buf.push(path);
1737 buf
1738 }
1739
1740 #[cfg(feature = "alloc")]
1759 pub fn with_file_name<S: AsRef<UnixStr>>(&self, file_name: S) -> PathBuf {
1760 self._with_file_name(file_name.as_ref())
1761 }
1762
1763 #[cfg(feature = "alloc")]
1764 fn _with_file_name(&self, file_name: &UnixStr) -> PathBuf {
1765 let mut buf = self.to_path_buf();
1766 buf.set_file_name(file_name);
1767 buf
1768 }
1769
1770 #[cfg(feature = "alloc")]
1786 pub fn with_extension<S: AsRef<UnixStr>>(&self, extension: S) -> PathBuf {
1787 self._with_extension(extension.as_ref())
1788 }
1789
1790 #[cfg(feature = "alloc")]
1791 fn _with_extension(&self, extension: &UnixStr) -> PathBuf {
1792 let mut buf = self.to_path_buf();
1793 buf.set_extension(extension);
1794 buf
1795 }
1796
1797 pub fn components(&self) -> Components<'_> {
1832 Components {
1833 path: self.as_u8_slice(),
1834 has_physical_root: has_physical_root(self.as_u8_slice()),
1835 front: State::Prefix,
1836 back: State::Body,
1837 }
1838 }
1839
1840 pub fn iter(&self) -> Iter<'_> {
1861 Iter {
1862 inner: self.components(),
1863 }
1864 }
1865
1866 #[cfg(feature = "alloc")]
1871 pub fn into_path_buf(self: Box<Path>) -> PathBuf {
1872 let rw = Box::into_raw(self) as *mut UnixStr;
1873 let inner = unsafe { Box::from_raw(rw) };
1874 PathBuf {
1875 inner: UnixString::from(inner),
1876 }
1877 }
1878
1879 pub fn display(&self) -> Display<'_> {
1882 Display { path: self }
1883 }
1884}
1885
1886impl AsRef<UnixStr> for Path {
1887 fn as_ref(&self) -> &UnixStr {
1888 &self.inner
1889 }
1890}
1891
1892impl fmt::Debug for Path {
1893 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
1894 fmt::Debug::fmt(&self.inner, formatter)
1895 }
1896}
1897
1898impl cmp::PartialEq for Path {
1899 fn eq(&self, other: &Path) -> bool {
1900 self.components().eq(other.components())
1901 }
1902}
1903
1904impl Hash for Path {
1905 fn hash<H: Hasher>(&self, h: &mut H) {
1906 for component in self.components() {
1907 component.hash(h);
1908 }
1909 }
1910}
1911
1912impl cmp::Eq for Path {}
1913
1914impl cmp::PartialOrd for Path {
1915 fn partial_cmp(&self, other: &Path) -> Option<cmp::Ordering> {
1916 self.components().partial_cmp(other.components())
1917 }
1918}
1919
1920impl cmp::Ord for Path {
1921 fn cmp(&self, other: &Path) -> cmp::Ordering {
1922 self.components().cmp(other.components())
1923 }
1924}
1925
1926impl AsRef<Path> for Path {
1927 fn as_ref(&self) -> &Path {
1928 self
1929 }
1930}
1931
1932impl AsRef<Path> for UnixStr {
1933 fn as_ref(&self) -> &Path {
1934 Path::new(self)
1935 }
1936}
1937
1938#[cfg(feature = "alloc")]
1939impl AsRef<Path> for Cow<'_, UnixStr> {
1940 fn as_ref(&self) -> &Path {
1941 Path::new(self)
1942 }
1943}
1944
1945#[cfg(feature = "alloc")]
1946impl AsRef<Path> for UnixString {
1947 fn as_ref(&self) -> &Path {
1948 Path::new(self)
1949 }
1950}
1951
1952impl AsRef<Path> for str {
1953 #[inline]
1954 fn as_ref(&self) -> &Path {
1955 Path::new(self)
1956 }
1957}
1958
1959#[cfg(feature = "alloc")]
1960impl AsRef<Path> for String {
1961 fn as_ref(&self) -> &Path {
1962 Path::new(self)
1963 }
1964}
1965
1966#[cfg(feature = "alloc")]
1967impl AsRef<Path> for PathBuf {
1968 #[inline]
1969 fn as_ref(&self) -> &Path {
1970 self
1971 }
1972}
1973
1974#[cfg(feature = "alloc")]
1975impl<'a> IntoIterator for &'a PathBuf {
1976 type Item = &'a UnixStr;
1977 type IntoIter = Iter<'a>;
1978 fn into_iter(self) -> Iter<'a> {
1979 self.iter()
1980 }
1981}
1982
1983impl<'a> IntoIterator for &'a Path {
1984 type Item = &'a UnixStr;
1985 type IntoIter = Iter<'a>;
1986 fn into_iter(self) -> Iter<'a> {
1987 self.iter()
1988 }
1989}
1990
1991#[cfg(feature = "serde")]
1992use serde::{
1993 de::{self, Deserialize, Deserializer, Unexpected, Visitor},
1994 ser::{self, Serialize, Serializer},
1995};
1996
1997#[cfg(feature = "serde")]
1998impl Serialize for Path {
1999 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
2000 where
2001 S: Serializer,
2002 {
2003 match self.to_str() {
2004 Some(s) => s.serialize(serializer),
2005 None => Err(ser::Error::custom("path contains invalid UTF-8 characters")),
2006 }
2007 }
2008}
2009
2010#[cfg(feature = "serde")]
2011impl Serialize for PathBuf {
2012 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
2013 where
2014 S: Serializer,
2015 {
2016 self.as_path().serialize(serializer)
2017 }
2018}
2019
2020#[cfg(feature = "serde")]
2021struct PathVisitor;
2022
2023#[cfg(feature = "serde")]
2024impl<'a> Visitor<'a> for PathVisitor {
2025 type Value = &'a Path;
2026
2027 fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
2028 formatter.write_str("a borrowed path")
2029 }
2030
2031 fn visit_borrowed_str<E>(self, v: &'a str) -> Result<Self::Value, E>
2032 where
2033 E: de::Error,
2034 {
2035 Ok(v.as_ref())
2036 }
2037
2038 fn visit_borrowed_bytes<E>(self, v: &'a [u8]) -> Result<Self::Value, E>
2039 where
2040 E: de::Error,
2041 {
2042 core::str::from_utf8(v)
2043 .map(AsRef::as_ref)
2044 .map_err(|_| de::Error::invalid_value(Unexpected::Bytes(v), &self))
2045 }
2046}
2047
2048#[cfg(feature = "serde")]
2049impl<'de: 'a, 'a> Deserialize<'de> for &'a Path {
2050 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
2051 where
2052 D: Deserializer<'de>,
2053 {
2054 deserializer.deserialize_str(PathVisitor)
2055 }
2056}
2057
2058#[cfg(feature = "serde")]
2059struct PathBufVisitor;
2060
2061#[cfg(feature = "serde")]
2062impl<'de> Visitor<'de> for PathBufVisitor {
2063 type Value = PathBuf;
2064
2065 fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
2066 formatter.write_str("path string")
2067 }
2068
2069 fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
2070 where
2071 E: de::Error,
2072 {
2073 Ok(From::from(v))
2074 }
2075
2076 fn visit_string<E>(self, v: String) -> Result<Self::Value, E>
2077 where
2078 E: de::Error,
2079 {
2080 Ok(From::from(v))
2081 }
2082
2083 fn visit_bytes<E>(self, v: &[u8]) -> Result<Self::Value, E>
2084 where
2085 E: de::Error,
2086 {
2087 core::str::from_utf8(v)
2088 .map(From::from)
2089 .map_err(|_| de::Error::invalid_value(Unexpected::Bytes(v), &self))
2090 }
2091
2092 fn visit_byte_buf<E>(self, v: Vec<u8>) -> Result<Self::Value, E>
2093 where
2094 E: de::Error,
2095 {
2096 String::from_utf8(v)
2097 .map(From::from)
2098 .map_err(|e| de::Error::invalid_value(Unexpected::Bytes(&e.into_bytes()), &self))
2099 }
2100}
2101
2102#[cfg(feature = "serde")]
2103impl<'de> Deserialize<'de> for PathBuf {
2104 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
2105 where
2106 D: Deserializer<'de>,
2107 {
2108 deserializer.deserialize_string(PathBufVisitor)
2109 }
2110}
2111
2112#[cfg(feature = "serde")]
2113impl<'de> Deserialize<'de> for Box<Path> {
2114 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
2115 where
2116 D: Deserializer<'de>,
2117 {
2118 Deserialize::deserialize(deserializer).map(PathBuf::into_boxed_path)
2119 }
2120}
2121
2122#[cfg(feature = "alloc")]
2123macro_rules! impl_cmp {
2124 ($lhs:ty, $rhs: ty) => {
2125 impl<'a, 'b> PartialEq<$rhs> for $lhs {
2126 #[inline]
2127 fn eq(&self, other: &$rhs) -> bool {
2128 <Path as PartialEq>::eq(self, other)
2129 }
2130 }
2131
2132 impl<'a, 'b> PartialEq<$lhs> for $rhs {
2133 #[inline]
2134 fn eq(&self, other: &$lhs) -> bool {
2135 <Path as PartialEq>::eq(self, other)
2136 }
2137 }
2138
2139 impl<'a, 'b> PartialOrd<$rhs> for $lhs {
2140 #[inline]
2141 fn partial_cmp(&self, other: &$rhs) -> Option<cmp::Ordering> {
2142 <Path as PartialOrd>::partial_cmp(self, other)
2143 }
2144 }
2145
2146 impl<'a, 'b> PartialOrd<$lhs> for $rhs {
2147 #[inline]
2148 fn partial_cmp(&self, other: &$lhs) -> Option<cmp::Ordering> {
2149 <Path as PartialOrd>::partial_cmp(self, other)
2150 }
2151 }
2152 };
2153}
2154
2155#[cfg(feature = "alloc")]
2156impl_cmp!(PathBuf, Path);
2157#[cfg(feature = "alloc")]
2158impl_cmp!(PathBuf, &'a Path);
2159#[cfg(feature = "alloc")]
2160impl_cmp!(Cow<'a, Path>, Path);
2161#[cfg(feature = "alloc")]
2162impl_cmp!(Cow<'a, Path>, &'b Path);
2163#[cfg(feature = "alloc")]
2164impl_cmp!(Cow<'a, Path>, PathBuf);
2165
2166impl fmt::Display for StripPrefixError {
2167 #[allow(deprecated, deprecated_in_future)]
2168 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2169 "prefix not found".fmt(f)
2170 }
2171}
2172
2173#[cfg(feature = "std")]
2174impl Error for StripPrefixError {
2175 #[allow(deprecated)]
2176 fn description(&self) -> &str {
2177 "prefix not found"
2178 }
2179}
2180
2181pub struct Display<'a> {
2182 path: &'a Path,
2183}
2184
2185impl fmt::Debug for Display<'_> {
2186 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
2187 fmt::Debug::fmt(&self.path, formatter)
2188 }
2189}
2190
2191impl fmt::Display for Display<'_> {
2192 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
2193 fmt::Display::fmt(
2194 &lossy::Utf8Lossy::from_bytes(&self.path.as_unix_str().as_bytes()),
2195 formatter,
2196 )
2197 }
2198}
2199
2200#[cfg(test)]
2201mod tests {
2202 use super::*;
2203
2204 use alloc::rc::Rc;
2205 use alloc::sync::Arc;
2206
2207 macro_rules! t(
2208 ($path:expr, iter: $iter:expr) => (
2209 {
2210 let path = Path::new($path);
2211
2212 let comps = path.iter()
2214 .map(|p| p.to_string_lossy().into_owned())
2215 .collect::<Vec<String>>();
2216 let exp: &[&str] = &$iter;
2217 let exps = exp.iter().map(|s| s.to_string()).collect::<Vec<String>>();
2218 assert!(comps == exps, "iter: Expected {:?}, found {:?}",
2219 exps, comps);
2220
2221 let comps = Path::new($path).iter().rev()
2223 .map(|p| p.to_string_lossy().into_owned())
2224 .collect::<Vec<String>>();
2225 let exps = exps.into_iter().rev().collect::<Vec<String>>();
2226 assert!(comps == exps, "iter().rev(): Expected {:?}, found {:?}",
2227 exps, comps);
2228 }
2229 );
2230
2231 ($path:expr, has_root: $has_root:expr, is_absolute: $is_absolute:expr) => (
2232 {
2233 let path = Path::new($path);
2234
2235 let act_root = path.has_root();
2236 assert!(act_root == $has_root, "has_root: Expected {:?}, found {:?}",
2237 $has_root, act_root);
2238
2239 let act_abs = path.is_absolute();
2240 assert!(act_abs == $is_absolute, "is_absolute: Expected {:?}, found {:?}",
2241 $is_absolute, act_abs);
2242 }
2243 );
2244
2245 ($path:expr, parent: $parent:expr, file_name: $file:expr) => (
2246 {
2247 let path = Path::new($path);
2248
2249 let parent = path.parent().map(|p| p.to_str().unwrap());
2250 let exp_parent: Option<&str> = $parent;
2251 assert!(parent == exp_parent, "parent: Expected {:?}, found {:?}",
2252 exp_parent, parent);
2253
2254 let file = path.file_name().map(|p| p.to_str().unwrap());
2255 let exp_file: Option<&str> = $file;
2256 assert!(file == exp_file, "file_name: Expected {:?}, found {:?}",
2257 exp_file, file);
2258 }
2259 );
2260
2261 ($path:expr, file_stem: $file_stem:expr, extension: $extension:expr) => (
2262 {
2263 let path = Path::new($path);
2264
2265 let stem = path.file_stem().map(|p| p.to_str().unwrap());
2266 let exp_stem: Option<&str> = $file_stem;
2267 assert!(stem == exp_stem, "file_stem: Expected {:?}, found {:?}",
2268 exp_stem, stem);
2269
2270 let ext = path.extension().map(|p| p.to_str().unwrap());
2271 let exp_ext: Option<&str> = $extension;
2272 assert!(ext == exp_ext, "extension: Expected {:?}, found {:?}",
2273 exp_ext, ext);
2274 }
2275 );
2276
2277 ($path:expr, iter: $iter:expr,
2278 has_root: $has_root:expr, is_absolute: $is_absolute:expr,
2279 parent: $parent:expr, file_name: $file:expr,
2280 file_stem: $file_stem:expr, extension: $extension:expr) => (
2281 {
2282 t!($path, iter: $iter);
2283 t!($path, has_root: $has_root, is_absolute: $is_absolute);
2284 t!($path, parent: $parent, file_name: $file);
2285 t!($path, file_stem: $file_stem, extension: $extension);
2286 }
2287 );
2288 );
2289
2290 #[test]
2291 fn into() {
2292 use alloc::borrow::Cow;
2293
2294 let static_path = Path::new("/home/foo");
2295 let static_cow_path: Cow<'static, Path> = static_path.into();
2296 let pathbuf = PathBuf::from("/home/foo");
2297
2298 {
2299 let path: &Path = &pathbuf;
2300 let borrowed_cow_path: Cow<'_, Path> = path.into();
2301
2302 assert_eq!(static_cow_path, borrowed_cow_path);
2303 }
2304
2305 let owned_cow_path: Cow<'static, Path> = pathbuf.into();
2306
2307 assert_eq!(static_cow_path, owned_cow_path);
2308 }
2309
2310 #[test]
2311 pub fn test_decompositions_unix() {
2312 t!("",
2313 iter: [],
2314 has_root: false,
2315 is_absolute: false,
2316 parent: None,
2317 file_name: None,
2318 file_stem: None,
2319 extension: None
2320 );
2321
2322 t!("foo",
2323 iter: ["foo"],
2324 has_root: false,
2325 is_absolute: false,
2326 parent: Some(""),
2327 file_name: Some("foo"),
2328 file_stem: Some("foo"),
2329 extension: None
2330 );
2331
2332 t!("/",
2333 iter: ["/"],
2334 has_root: true,
2335 is_absolute: true,
2336 parent: None,
2337 file_name: None,
2338 file_stem: None,
2339 extension: None
2340 );
2341
2342 t!("/foo",
2343 iter: ["/", "foo"],
2344 has_root: true,
2345 is_absolute: true,
2346 parent: Some("/"),
2347 file_name: Some("foo"),
2348 file_stem: Some("foo"),
2349 extension: None
2350 );
2351
2352 t!("foo/",
2353 iter: ["foo"],
2354 has_root: false,
2355 is_absolute: false,
2356 parent: Some(""),
2357 file_name: Some("foo"),
2358 file_stem: Some("foo"),
2359 extension: None
2360 );
2361
2362 t!("/foo/",
2363 iter: ["/", "foo"],
2364 has_root: true,
2365 is_absolute: true,
2366 parent: Some("/"),
2367 file_name: Some("foo"),
2368 file_stem: Some("foo"),
2369 extension: None
2370 );
2371
2372 t!("foo/bar",
2373 iter: ["foo", "bar"],
2374 has_root: false,
2375 is_absolute: false,
2376 parent: Some("foo"),
2377 file_name: Some("bar"),
2378 file_stem: Some("bar"),
2379 extension: None
2380 );
2381
2382 t!("/foo/bar",
2383 iter: ["/", "foo", "bar"],
2384 has_root: true,
2385 is_absolute: true,
2386 parent: Some("/foo"),
2387 file_name: Some("bar"),
2388 file_stem: Some("bar"),
2389 extension: None
2390 );
2391
2392 t!("///foo///",
2393 iter: ["/", "foo"],
2394 has_root: true,
2395 is_absolute: true,
2396 parent: Some("/"),
2397 file_name: Some("foo"),
2398 file_stem: Some("foo"),
2399 extension: None
2400 );
2401
2402 t!("///foo///bar",
2403 iter: ["/", "foo", "bar"],
2404 has_root: true,
2405 is_absolute: true,
2406 parent: Some("///foo"),
2407 file_name: Some("bar"),
2408 file_stem: Some("bar"),
2409 extension: None
2410 );
2411
2412 t!("./.",
2413 iter: ["."],
2414 has_root: false,
2415 is_absolute: false,
2416 parent: Some(""),
2417 file_name: None,
2418 file_stem: None,
2419 extension: None
2420 );
2421
2422 t!("/..",
2423 iter: ["/", ".."],
2424 has_root: true,
2425 is_absolute: true,
2426 parent: Some("/"),
2427 file_name: None,
2428 file_stem: None,
2429 extension: None
2430 );
2431
2432 t!("../",
2433 iter: [".."],
2434 has_root: false,
2435 is_absolute: false,
2436 parent: Some(""),
2437 file_name: None,
2438 file_stem: None,
2439 extension: None
2440 );
2441
2442 t!("foo/.",
2443 iter: ["foo"],
2444 has_root: false,
2445 is_absolute: false,
2446 parent: Some(""),
2447 file_name: Some("foo"),
2448 file_stem: Some("foo"),
2449 extension: None
2450 );
2451
2452 t!("foo/..",
2453 iter: ["foo", ".."],
2454 has_root: false,
2455 is_absolute: false,
2456 parent: Some("foo"),
2457 file_name: None,
2458 file_stem: None,
2459 extension: None
2460 );
2461
2462 t!("foo/./",
2463 iter: ["foo"],
2464 has_root: false,
2465 is_absolute: false,
2466 parent: Some(""),
2467 file_name: Some("foo"),
2468 file_stem: Some("foo"),
2469 extension: None
2470 );
2471
2472 t!("foo/./bar",
2473 iter: ["foo", "bar"],
2474 has_root: false,
2475 is_absolute: false,
2476 parent: Some("foo"),
2477 file_name: Some("bar"),
2478 file_stem: Some("bar"),
2479 extension: None
2480 );
2481
2482 t!("foo/../",
2483 iter: ["foo", ".."],
2484 has_root: false,
2485 is_absolute: false,
2486 parent: Some("foo"),
2487 file_name: None,
2488 file_stem: None,
2489 extension: None
2490 );
2491
2492 t!("foo/../bar",
2493 iter: ["foo", "..", "bar"],
2494 has_root: false,
2495 is_absolute: false,
2496 parent: Some("foo/.."),
2497 file_name: Some("bar"),
2498 file_stem: Some("bar"),
2499 extension: None
2500 );
2501
2502 t!("./a",
2503 iter: [".", "a"],
2504 has_root: false,
2505 is_absolute: false,
2506 parent: Some("."),
2507 file_name: Some("a"),
2508 file_stem: Some("a"),
2509 extension: None
2510 );
2511
2512 t!(".",
2513 iter: ["."],
2514 has_root: false,
2515 is_absolute: false,
2516 parent: Some(""),
2517 file_name: None,
2518 file_stem: None,
2519 extension: None
2520 );
2521
2522 t!("./",
2523 iter: ["."],
2524 has_root: false,
2525 is_absolute: false,
2526 parent: Some(""),
2527 file_name: None,
2528 file_stem: None,
2529 extension: None
2530 );
2531
2532 t!("a/b",
2533 iter: ["a", "b"],
2534 has_root: false,
2535 is_absolute: false,
2536 parent: Some("a"),
2537 file_name: Some("b"),
2538 file_stem: Some("b"),
2539 extension: None
2540 );
2541
2542 t!("a//b",
2543 iter: ["a", "b"],
2544 has_root: false,
2545 is_absolute: false,
2546 parent: Some("a"),
2547 file_name: Some("b"),
2548 file_stem: Some("b"),
2549 extension: None
2550 );
2551
2552 t!("a/./b",
2553 iter: ["a", "b"],
2554 has_root: false,
2555 is_absolute: false,
2556 parent: Some("a"),
2557 file_name: Some("b"),
2558 file_stem: Some("b"),
2559 extension: None
2560 );
2561
2562 t!("a/b/c",
2563 iter: ["a", "b", "c"],
2564 has_root: false,
2565 is_absolute: false,
2566 parent: Some("a/b"),
2567 file_name: Some("c"),
2568 file_stem: Some("c"),
2569 extension: None
2570 );
2571
2572 t!(".foo",
2573 iter: [".foo"],
2574 has_root: false,
2575 is_absolute: false,
2576 parent: Some(""),
2577 file_name: Some(".foo"),
2578 file_stem: Some(".foo"),
2579 extension: None
2580 );
2581 }
2582
2583 #[test]
2584 pub fn test_stem_ext() {
2585 t!("foo",
2586 file_stem: Some("foo"),
2587 extension: None
2588 );
2589
2590 t!("foo.",
2591 file_stem: Some("foo"),
2592 extension: Some("")
2593 );
2594
2595 t!(".foo",
2596 file_stem: Some(".foo"),
2597 extension: None
2598 );
2599
2600 t!("foo.txt",
2601 file_stem: Some("foo"),
2602 extension: Some("txt")
2603 );
2604
2605 t!("foo.bar.txt",
2606 file_stem: Some("foo.bar"),
2607 extension: Some("txt")
2608 );
2609
2610 t!("foo.bar.",
2611 file_stem: Some("foo.bar"),
2612 extension: Some("")
2613 );
2614
2615 t!(".", file_stem: None, extension: None);
2616
2617 t!("..", file_stem: None, extension: None);
2618
2619 t!("", file_stem: None, extension: None);
2620 }
2621
2622 #[test]
2623 pub fn test_push() {
2624 macro_rules! tp(
2625 ($path:expr, $push:expr, $expected:expr) => ( {
2626 let mut actual = PathBuf::from($path);
2627 actual.push($push);
2628 assert!(actual.to_str() == Some($expected),
2629 "pushing {:?} onto {:?}: Expected {:?}, got {:?}",
2630 $push, $path, $expected, actual.to_str().unwrap());
2631 });
2632 );
2633
2634 tp!("", "foo", "foo");
2635 tp!("foo", "bar", "foo/bar");
2636 tp!("foo/", "bar", "foo/bar");
2637 tp!("foo//", "bar", "foo//bar");
2638 tp!("foo/.", "bar", "foo/./bar");
2639 tp!("foo./.", "bar", "foo././bar");
2640 tp!("foo", "", "foo/");
2641 tp!("foo", ".", "foo/.");
2642 tp!("foo", "..", "foo/..");
2643 tp!("foo", "/", "/");
2644 tp!("/foo/bar", "/", "/");
2645 tp!("/foo/bar", "/baz", "/baz");
2646 tp!("/foo/bar", "./baz", "/foo/bar/./baz");
2647 }
2648
2649 #[test]
2650 pub fn test_pop() {
2651 macro_rules! tp(
2652 ($path:expr, $expected:expr, $output:expr) => ( {
2653 let mut actual = PathBuf::from($path);
2654 let output = actual.pop();
2655 assert!(actual.to_str() == Some($expected) && output == $output,
2656 "popping from {:?}: Expected {:?}/{:?}, got {:?}/{:?}",
2657 $path, $expected, $output,
2658 actual.to_str().unwrap(), output);
2659 });
2660 );
2661
2662 tp!("", "", false);
2663 tp!("/", "/", false);
2664 tp!("foo", "", true);
2665 tp!(".", "", true);
2666 tp!("/foo", "/", true);
2667 tp!("/foo/bar", "/foo", true);
2668 tp!("foo/bar", "foo", true);
2669 tp!("foo/.", "", true);
2670 tp!("foo//bar", "foo", true);
2671 }
2672
2673 #[test]
2674 pub fn test_set_file_name() {
2675 macro_rules! tfn(
2676 ($path:expr, $file:expr, $expected:expr) => ( {
2677 let mut p = PathBuf::from($path);
2678 p.set_file_name($file);
2679 assert!(p.to_str() == Some($expected),
2680 "setting file name of {:?} to {:?}: Expected {:?}, got {:?}",
2681 $path, $file, $expected,
2682 p.to_str().unwrap());
2683 });
2684 );
2685
2686 tfn!("foo", "foo", "foo");
2687 tfn!("foo", "bar", "bar");
2688 tfn!("foo", "", "");
2689 tfn!("", "foo", "foo");
2690 tfn!(".", "foo", "./foo");
2691 tfn!("foo/", "bar", "bar");
2692 tfn!("foo/.", "bar", "bar");
2693 tfn!("..", "foo", "../foo");
2694 tfn!("foo/..", "bar", "foo/../bar");
2695 tfn!("/", "foo", "/foo");
2696 }
2697
2698 #[test]
2699 pub fn test_set_extension() {
2700 macro_rules! tfe(
2701 ($path:expr, $ext:expr, $expected:expr, $output:expr) => ( {
2702 let mut p = PathBuf::from($path);
2703 let output = p.set_extension($ext);
2704 assert!(p.to_str() == Some($expected) && output == $output,
2705 "setting extension of {:?} to {:?}: Expected {:?}/{:?}, got {:?}/{:?}",
2706 $path, $ext, $expected, $output,
2707 p.to_str().unwrap(), output);
2708 });
2709 );
2710
2711 tfe!("foo", "txt", "foo.txt", true);
2712 tfe!("foo.bar", "txt", "foo.txt", true);
2713 tfe!("foo.bar.baz", "txt", "foo.bar.txt", true);
2714 tfe!(".test", "txt", ".test.txt", true);
2715 tfe!("foo.txt", "", "foo", true);
2716 tfe!("foo", "", "foo", true);
2717 tfe!("", "foo", "", false);
2718 tfe!(".", "foo", ".", false);
2719 tfe!("foo/", "bar", "foo.bar", true);
2720 tfe!("foo/.", "bar", "foo.bar", true);
2721 tfe!("..", "foo", "..", false);
2722 tfe!("foo/..", "bar", "foo/..", false);
2723 tfe!("/", "foo", "/", false);
2724 }
2725
2726 #[test]
2727 fn test_eq_receivers() {
2728 use alloc::borrow::Cow;
2729
2730 let borrowed: &Path = Path::new("foo/bar");
2731 let mut owned: PathBuf = PathBuf::new();
2732 owned.push("foo");
2733 owned.push("bar");
2734 let borrowed_cow: Cow<'_, Path> = borrowed.into();
2735 let owned_cow: Cow<'_, Path> = owned.clone().into();
2736
2737 macro_rules! t {
2738 ($($current:expr),+) => {
2739 $(
2740 assert_eq!($current, borrowed);
2741 assert_eq!($current, owned);
2742 assert_eq!($current, borrowed_cow);
2743 assert_eq!($current, owned_cow);
2744 )+
2745 }
2746 }
2747
2748 t!(borrowed, owned, borrowed_cow, owned_cow);
2749 }
2750
2751 #[test]
2752 pub fn test_compare() {
2753 use std::collections::hash_map::DefaultHasher;
2754 use std::hash::{Hash, Hasher};
2755
2756 fn hash<T: Hash>(t: T) -> u64 {
2757 let mut s = DefaultHasher::new();
2758 t.hash(&mut s);
2759 s.finish()
2760 }
2761
2762 macro_rules! tc(
2763 ($path1:expr, $path2:expr, eq: $eq:expr,
2764 starts_with: $starts_with:expr, ends_with: $ends_with:expr,
2765 relative_from: $relative_from:expr) => ({
2766 let path1 = Path::new($path1);
2767 let path2 = Path::new($path2);
2768
2769 let eq = path1 == path2;
2770 assert!(eq == $eq, "{:?} == {:?}, expected {:?}, got {:?}",
2771 $path1, $path2, $eq, eq);
2772 assert!($eq == (hash(path1) == hash(path2)),
2773 "{:?} == {:?}, expected {:?}, got {} and {}",
2774 $path1, $path2, $eq, hash(path1), hash(path2));
2775
2776 let starts_with = path1.starts_with(path2);
2777 assert!(starts_with == $starts_with,
2778 "{:?}.starts_with({:?}), expected {:?}, got {:?}", $path1, $path2,
2779 $starts_with, starts_with);
2780
2781 let ends_with = path1.ends_with(path2);
2782 assert!(ends_with == $ends_with,
2783 "{:?}.ends_with({:?}), expected {:?}, got {:?}", $path1, $path2,
2784 $ends_with, ends_with);
2785
2786 let relative_from = path1.strip_prefix(path2)
2787 .map(|p| p.to_str().unwrap())
2788 .ok();
2789 let exp: Option<&str> = $relative_from;
2790 assert!(relative_from == exp,
2791 "{:?}.strip_prefix({:?}), expected {:?}, got {:?}",
2792 $path1, $path2, exp, relative_from);
2793 });
2794 );
2795
2796 tc!("", "",
2797 eq: true,
2798 starts_with: true,
2799 ends_with: true,
2800 relative_from: Some("")
2801 );
2802
2803 tc!("foo", "",
2804 eq: false,
2805 starts_with: true,
2806 ends_with: true,
2807 relative_from: Some("foo")
2808 );
2809
2810 tc!("", "foo",
2811 eq: false,
2812 starts_with: false,
2813 ends_with: false,
2814 relative_from: None
2815 );
2816
2817 tc!("foo", "foo",
2818 eq: true,
2819 starts_with: true,
2820 ends_with: true,
2821 relative_from: Some("")
2822 );
2823
2824 tc!("foo/", "foo",
2825 eq: true,
2826 starts_with: true,
2827 ends_with: true,
2828 relative_from: Some("")
2829 );
2830
2831 tc!("foo/bar", "foo",
2832 eq: false,
2833 starts_with: true,
2834 ends_with: false,
2835 relative_from: Some("bar")
2836 );
2837
2838 tc!("foo/bar/baz", "foo/bar",
2839 eq: false,
2840 starts_with: true,
2841 ends_with: false,
2842 relative_from: Some("baz")
2843 );
2844
2845 tc!("foo/bar", "foo/bar/baz",
2846 eq: false,
2847 starts_with: false,
2848 ends_with: false,
2849 relative_from: None
2850 );
2851
2852 tc!("./foo/bar/", ".",
2853 eq: false,
2854 starts_with: true,
2855 ends_with: false,
2856 relative_from: Some("foo/bar")
2857 );
2858 }
2859
2860 #[test]
2861 fn test_components_debug() {
2862 let path = Path::new("/tmp");
2863
2864 let mut components = path.components();
2865
2866 let expected = "Components([RootDir, Normal(\"tmp\")])";
2867 let actual = format!("{:?}", components);
2868 assert_eq!(expected, actual);
2869
2870 let _ = components.next().unwrap();
2871 let expected = "Components([Normal(\"tmp\")])";
2872 let actual = format!("{:?}", components);
2873 assert_eq!(expected, actual);
2874
2875 let _ = components.next().unwrap();
2876 let expected = "Components([])";
2877 let actual = format!("{:?}", components);
2878 assert_eq!(expected, actual);
2879 }
2880
2881 #[test]
2882 fn test_iter_debug() {
2883 let path = Path::new("/tmp");
2884
2885 let mut iter = path.iter();
2886
2887 let expected = "Iter([\"/\", \"tmp\"])";
2888 let actual = format!("{:?}", iter);
2889 assert_eq!(expected, actual);
2890
2891 let _ = iter.next().unwrap();
2892 let expected = "Iter([\"tmp\"])";
2893 let actual = format!("{:?}", iter);
2894 assert_eq!(expected, actual);
2895
2896 let _ = iter.next().unwrap();
2897 let expected = "Iter([])";
2898 let actual = format!("{:?}", iter);
2899 assert_eq!(expected, actual);
2900 }
2901
2902 #[test]
2903 fn into_boxed() {
2904 let orig: &str = "some/sort/of/path";
2905 let path = Path::new(orig);
2906 let boxed: Box<Path> = Box::from(path);
2907 let path_buf = path.to_owned().into_boxed_path().into_path_buf();
2908 assert_eq!(path, &*boxed);
2909 assert_eq!(&*boxed, &*path_buf);
2910 assert_eq!(&*path_buf, path);
2911 }
2912
2913 #[test]
2914 fn into_rc() {
2915 let orig = "hello/world";
2916 let path = Path::new(orig);
2917 let rc: Rc<Path> = Rc::from(path);
2918 let arc: Arc<Path> = Arc::from(path);
2919
2920 assert_eq!(&*rc, path);
2921 assert_eq!(&*arc, path);
2922
2923 let rc2: Rc<Path> = Rc::from(path.to_owned());
2924 let arc2: Arc<Path> = Arc::from(path.to_owned());
2925
2926 assert_eq!(&*rc2, path);
2927 assert_eq!(&*arc2, path);
2928 }
2929}