]> git.lizzy.rs Git - rust.git/blob - src/libstd/old_path/mod.rs
Auto merge of #22541 - Manishearth:rollup, r=Gankro
[rust.git] / src / libstd / old_path / mod.rs
1 // Copyright 2013 The Rust Project Developers. See the COPYRIGHT
2 // file at the top-level directory of this distribution and at
3 // http://rust-lang.org/COPYRIGHT.
4 //
5 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8 // option. This file may not be copied, modified, or distributed
9 // except according to those terms.
10
11 //! Cross-platform path support
12 //!
13 //! This module implements support for two flavors of paths. `PosixPath` represents a path on any
14 //! unix-like system, whereas `WindowsPath` represents a path on Windows. This module also exposes
15 //! a typedef `Path` which is equal to the appropriate platform-specific path variant.
16 //!
17 //! Both `PosixPath` and `WindowsPath` implement a trait `GenericPath`, which contains the set of
18 //! methods that behave the same for both paths. They each also implement some methods that could
19 //! not be expressed in `GenericPath`, yet behave identically for both path flavors, such as
20 //! `.components()`.
21 //!
22 //! The three main design goals of this module are 1) to avoid unnecessary allocation, 2) to behave
23 //! the same regardless of which flavor of path is being used, and 3) to support paths that cannot
24 //! be represented in UTF-8 (as Linux has no restriction on paths beyond disallowing NUL).
25 //!
26 //! ## Usage
27 //!
28 //! Usage of this module is fairly straightforward. Unless writing platform-specific code, `Path`
29 //! should be used to refer to the platform-native path.
30 //!
31 //! Creation of a path is typically done with either `Path::new(some_str)` or
32 //! `Path::new(some_vec)`. This path can be modified with `.push()` and `.pop()` (and other
33 //! setters). The resulting Path can either be passed to another API that expects a path, or can be
34 //! turned into a `&[u8]` with `.as_vec()` or a `Option<&str>` with `.as_str()`. Similarly,
35 //! attributes of the path can be queried with methods such as `.filename()`. There are also
36 //! methods that return a new path instead of modifying the receiver, such as `.join()` or
37 //! `.dir_path()`.
38 //!
39 //! Paths are always kept in normalized form. This means that creating the path
40 //! `Path::new("a/b/../c")` will return the path `a/c`. Similarly any attempt to mutate the path
41 //! will always leave it in normalized form.
42 //!
43 //! When rendering a path to some form of output, there is a method `.display()` which is
44 //! compatible with the `format!()` parameter `{}`. This will render the path as a string,
45 //! replacing all non-utf8 sequences with the Replacement Character (U+FFFD). As such it is not
46 //! suitable for passing to any API that actually operates on the path; it is only intended for
47 //! display.
48 //!
49 //! ## Example
50 //!
51 //! ```rust
52 //! use std::old_io::fs::PathExtensions;
53 //!
54 //! let mut path = Path::new("/tmp/path");
55 //! println!("path: {}", path.display());
56 //! path.set_filename("foo");
57 //! path.push("bar");
58 //! println!("new path: {}", path.display());
59 //! println!("path exists: {}", path.exists());
60 //! ```
61
62 #![unstable(feature = "old_path")]
63
64 use core::marker::Sized;
65 use ffi::CString;
66 use clone::Clone;
67 use fmt;
68 use iter::IteratorExt;
69 use option::Option;
70 use option::Option::{None, Some};
71 use str;
72 use str::StrExt;
73 use string::{String, CowString};
74 use slice::SliceExt;
75 use vec::Vec;
76
77 /// Typedef for POSIX file paths.
78 /// See `posix::Path` for more info.
79 pub use self::posix::Path as PosixPath;
80
81 /// Typedef for Windows file paths.
82 /// See `windows::Path` for more info.
83 pub use self::windows::Path as WindowsPath;
84
85 /// Typedef for the platform-native path type
86 #[cfg(unix)]
87 pub use self::posix::Path as Path;
88 /// Typedef for the platform-native path type
89 #[cfg(windows)]
90 pub use self::windows::Path as Path;
91
92 /// Typedef for the platform-native component iterator
93 #[cfg(unix)]
94 pub use self::posix::Components as Components;
95 /// Typedef for the platform-native component iterator
96 #[cfg(windows)]
97 pub use self::windows::Components as Components;
98
99 /// Typedef for the platform-native str component iterator
100 #[cfg(unix)]
101 pub use self::posix::StrComponents as StrComponents;
102 /// Typedef for the platform-native str component iterator
103 #[cfg(windows)]
104 pub use self::windows::StrComponents as StrComponents;
105
106 /// Alias for the platform-native separator character.
107 #[cfg(unix)]
108 pub use self::posix::SEP as SEP;
109 /// Alias for the platform-native separator character.
110 #[cfg(windows)]
111 pub use self::windows::SEP as SEP;
112
113 /// Alias for the platform-native separator byte.
114 #[cfg(unix)]
115 pub use self::posix::SEP_BYTE as SEP_BYTE;
116 /// Alias for the platform-native separator byte.
117 #[cfg(windows)]
118 pub use self::windows::SEP_BYTE as SEP_BYTE;
119
120 /// Typedef for the platform-native separator char func
121 #[cfg(unix)]
122 pub use self::posix::is_sep as is_sep;
123 /// Typedef for the platform-native separator char func
124 #[cfg(windows)]
125 pub use self::windows::is_sep as is_sep;
126 /// Typedef for the platform-native separator byte func
127 #[cfg(unix)]
128 pub use self::posix::is_sep_byte as is_sep_byte;
129 /// Typedef for the platform-native separator byte func
130 #[cfg(windows)]
131 pub use self::windows::is_sep_byte as is_sep_byte;
132
133 pub mod posix;
134 pub mod windows;
135
136 /// A trait that represents the generic operations available on paths
137 pub trait GenericPath: Clone + GenericPathUnsafe {
138     /// Creates a new Path from a byte vector or string.
139     /// The resulting Path will always be normalized.
140     ///
141     /// # Example
142     ///
143     /// ```
144     /// # foo();
145     /// # #[cfg(windows)] fn foo() {}
146     /// # #[cfg(unix)] fn foo() {
147     /// let path = Path::new("foo/bar");
148     /// # }
149     /// ```
150     ///
151     /// # Panics
152     ///
153     /// Panics the task if the path contains a NUL.
154     ///
155     /// See individual Path impls for additional restrictions.
156     #[inline]
157     fn new<T: BytesContainer>(path: T) -> Self {
158         assert!(!contains_nul(&path));
159         unsafe { GenericPathUnsafe::new_unchecked(path) }
160     }
161
162     /// Creates a new Path from a byte vector or string, if possible.
163     /// The resulting Path will always be normalized.
164     ///
165     /// # Example
166     ///
167     /// ```
168     /// # foo();
169     /// # #[cfg(windows)] fn foo() {}
170     /// # #[cfg(unix)] fn foo() {
171     /// let x: &[u8] = b"foo\0";
172     /// assert!(Path::new_opt(x).is_none());
173     /// # }
174     /// ```
175     #[inline]
176     fn new_opt<T: BytesContainer>(path: T) -> Option<Self> {
177         if contains_nul(&path) {
178             None
179         } else {
180             Some(unsafe { GenericPathUnsafe::new_unchecked(path) })
181         }
182     }
183
184     /// Returns the path as a string, if possible.
185     /// If the path is not representable in utf-8, this returns None.
186     ///
187     /// # Example
188     ///
189     /// ```
190     /// # foo();
191     /// # #[cfg(windows)] fn foo() {}
192     /// # #[cfg(unix)] fn foo() {
193     /// let p = Path::new("/abc/def");
194     /// assert_eq!(p.as_str(), Some("/abc/def"));
195     /// # }
196     /// ```
197     #[inline]
198     fn as_str<'a>(&'a self) -> Option<&'a str> {
199         str::from_utf8(self.as_vec()).ok()
200     }
201
202     /// Returns the path as a byte vector
203     ///
204     /// # Example
205     ///
206     /// ```
207     /// # foo();
208     /// # #[cfg(windows)] fn foo() {}
209     /// # #[cfg(unix)] fn foo() {
210     /// let p = Path::new("abc/def");
211     /// assert_eq!(p.as_vec(), b"abc/def");
212     /// # }
213     /// ```
214     fn as_vec<'a>(&'a self) -> &'a [u8];
215
216     /// Converts the Path into an owned byte vector
217     ///
218     /// # Example
219     ///
220     /// ```
221     /// # foo();
222     /// # #[cfg(windows)] fn foo() {}
223     /// # #[cfg(unix)] fn foo() {
224     /// let p = Path::new("abc/def");
225     /// assert_eq!(p.into_vec(), b"abc/def".to_vec());
226     /// // attempting to use p now results in "error: use of moved value"
227     /// # }
228     /// ```
229     fn into_vec(self) -> Vec<u8>;
230
231     /// Returns an object that implements `Display` for printing paths
232     ///
233     /// # Example
234     ///
235     /// ```
236     /// # foo();
237     /// # #[cfg(windows)] fn foo() {}
238     /// # #[cfg(unix)] fn foo() {
239     /// let p = Path::new("abc/def");
240     /// println!("{}", p.display()); // prints "abc/def"
241     /// # }
242     /// ```
243     fn display<'a>(&'a self) -> Display<'a, Self> {
244         Display{ path: self, filename: false }
245     }
246
247     /// Returns an object that implements `Display` for printing filenames
248     ///
249     /// If there is no filename, nothing will be printed.
250     ///
251     /// # Example
252     ///
253     /// ```
254     /// # foo();
255     /// # #[cfg(windows)] fn foo() {}
256     /// # #[cfg(unix)] fn foo() {
257     /// let p = Path::new("abc/def");
258     /// println!("{}", p.filename_display()); // prints "def"
259     /// # }
260     /// ```
261     fn filename_display<'a>(&'a self) -> Display<'a, Self> {
262         Display{ path: self, filename: true }
263     }
264
265     /// Returns the directory component of `self`, as a byte vector (with no trailing separator).
266     /// If `self` has no directory component, returns ['.'].
267     ///
268     /// # Example
269     ///
270     /// ```
271     /// # foo();
272     /// # #[cfg(windows)] fn foo() {}
273     /// # #[cfg(unix)] fn foo() {
274     /// let p = Path::new("abc/def/ghi");
275     /// assert_eq!(p.dirname(), b"abc/def");
276     /// # }
277     /// ```
278     fn dirname<'a>(&'a self) -> &'a [u8];
279
280     /// Returns the directory component of `self`, as a string, if possible.
281     /// See `dirname` for details.
282     ///
283     /// # Example
284     ///
285     /// ```
286     /// # foo();
287     /// # #[cfg(windows)] fn foo() {}
288     /// # #[cfg(unix)] fn foo() {
289     /// let p = Path::new("abc/def/ghi");
290     /// assert_eq!(p.dirname_str(), Some("abc/def"));
291     /// # }
292     /// ```
293     #[inline]
294     fn dirname_str<'a>(&'a self) -> Option<&'a str> {
295         str::from_utf8(self.dirname()).ok()
296     }
297
298     /// Returns the file component of `self`, as a byte vector.
299     /// If `self` represents the root of the file hierarchy, returns None.
300     /// If `self` is "." or "..", returns None.
301     ///
302     /// # Example
303     ///
304     /// ```
305     /// # foo();
306     /// # #[cfg(windows)] fn foo() {}
307     /// # #[cfg(unix)] fn foo() {
308     /// let p = Path::new("abc/def/ghi");
309     /// assert_eq!(p.filename(), Some(b"ghi"));
310     /// # }
311     /// ```
312     fn filename<'a>(&'a self) -> Option<&'a [u8]>;
313
314     /// Returns the file component of `self`, as a string, if possible.
315     /// See `filename` for details.
316     ///
317     /// # Example
318     ///
319     /// ```
320     /// # foo();
321     /// # #[cfg(windows)] fn foo() {}
322     /// # #[cfg(unix)] fn foo() {
323     /// let p = Path::new("abc/def/ghi");
324     /// assert_eq!(p.filename_str(), Some("ghi"));
325     /// # }
326     /// ```
327     #[inline]
328     fn filename_str<'a>(&'a self) -> Option<&'a str> {
329         self.filename().and_then(|s| str::from_utf8(s).ok())
330     }
331
332     /// Returns the stem of the filename of `self`, as a byte vector.
333     /// The stem is the portion of the filename just before the last '.'.
334     /// If there is no '.', the entire filename is returned.
335     ///
336     /// # Example
337     ///
338     /// ```
339     /// # foo();
340     /// # #[cfg(windows)] fn foo() {}
341     /// # #[cfg(unix)] fn foo() {
342     /// let p = Path::new("/abc/def.txt");
343     /// assert_eq!(p.filestem(), Some(b"def"));
344     /// # }
345     /// ```
346     fn filestem<'a>(&'a self) -> Option<&'a [u8]> {
347         match self.filename() {
348             None => None,
349             Some(name) => Some({
350                 let dot = b'.';
351                 match name.rposition_elem(&dot) {
352                     None | Some(0) => name,
353                     Some(1) if name == b".." => name,
354                     Some(pos) => &name[..pos]
355                 }
356             })
357         }
358     }
359
360     /// Returns the stem of the filename of `self`, as a string, if possible.
361     /// See `filestem` for details.
362     ///
363     /// # Example
364     ///
365     /// ```
366     /// # foo();
367     /// # #[cfg(windows)] fn foo() {}
368     /// # #[cfg(unix)] fn foo() {
369     /// let p = Path::new("/abc/def.txt");
370     /// assert_eq!(p.filestem_str(), Some("def"));
371     /// # }
372     /// ```
373     #[inline]
374     fn filestem_str<'a>(&'a self) -> Option<&'a str> {
375         self.filestem().and_then(|s| str::from_utf8(s).ok())
376     }
377
378     /// Returns the extension of the filename of `self`, as an optional byte vector.
379     /// The extension is the portion of the filename just after the last '.'.
380     /// If there is no extension, None is returned.
381     /// If the filename ends in '.', the empty vector is returned.
382     ///
383     /// # Example
384     ///
385     /// ```
386     /// # foo();
387     /// # #[cfg(windows)] fn foo() {}
388     /// # #[cfg(unix)] fn foo() {
389     /// let p = Path::new("abc/def.txt");
390     /// assert_eq!(p.extension(), Some(b"txt"));
391     /// # }
392     /// ```
393     fn extension<'a>(&'a self) -> Option<&'a [u8]> {
394         match self.filename() {
395             None => None,
396             Some(name) => {
397                 let dot = b'.';
398                 match name.rposition_elem(&dot) {
399                     None | Some(0) => None,
400                     Some(1) if name == b".." => None,
401                     Some(pos) => Some(&name[pos+1..])
402                 }
403             }
404         }
405     }
406
407     /// Returns the extension of the filename of `self`, as a string, if possible.
408     /// See `extension` for details.
409     ///
410     /// # Example
411     ///
412     /// ```
413     /// # foo();
414     /// # #[cfg(windows)] fn foo() {}
415     /// # #[cfg(unix)] fn foo() {
416     /// let p = Path::new("abc/def.txt");
417     /// assert_eq!(p.extension_str(), Some("txt"));
418     /// # }
419     /// ```
420     #[inline]
421     fn extension_str<'a>(&'a self) -> Option<&'a str> {
422         self.extension().and_then(|s| str::from_utf8(s).ok())
423     }
424
425     /// Replaces the filename portion of the path with the given byte vector or string.
426     /// If the replacement name is [], this is equivalent to popping the path.
427     ///
428     /// # Example
429     ///
430     /// ```
431     /// # foo();
432     /// # #[cfg(windows)] fn foo() {}
433     /// # #[cfg(unix)] fn foo() {
434     /// let mut p = Path::new("abc/def.txt");
435     /// p.set_filename("foo.dat");
436     /// assert!(p == Path::new("abc/foo.dat"));
437     /// # }
438     /// ```
439     ///
440     /// # Panics
441     ///
442     /// Panics the task if the filename contains a NUL.
443     #[inline]
444     fn set_filename<T: BytesContainer>(&mut self, filename: T) {
445         assert!(!contains_nul(&filename));
446         unsafe { self.set_filename_unchecked(filename) }
447     }
448
449     /// Replaces the extension with the given byte vector or string.
450     /// If there is no extension in `self`, this adds one.
451     /// If the argument is [] or "", this removes the extension.
452     /// If `self` has no filename, this is a no-op.
453     ///
454     /// # Example
455     ///
456     /// ```
457     /// # foo();
458     /// # #[cfg(windows)] fn foo() {}
459     /// # #[cfg(unix)] fn foo() {
460     /// let mut p = Path::new("abc/def.txt");
461     /// p.set_extension("csv");
462     /// assert_eq!(p, Path::new("abc/def.csv"));
463     /// # }
464     /// ```
465     ///
466     /// # Panics
467     ///
468     /// Panics the task if the extension contains a NUL.
469     fn set_extension<T: BytesContainer>(&mut self, extension: T) {
470         assert!(!contains_nul(&extension));
471
472         let val = self.filename().and_then(|name| {
473             let dot = b'.';
474             let extlen = extension.container_as_bytes().len();
475             match (name.rposition_elem(&dot), extlen) {
476                 (None, 0) | (Some(0), 0) => None,
477                 (Some(idx), 0) => Some(name[..idx].to_vec()),
478                 (idx, extlen) => {
479                     let idx = match idx {
480                         None | Some(0) => name.len(),
481                         Some(val) => val
482                     };
483
484                     let mut v;
485                     v = Vec::with_capacity(idx + extlen + 1);
486                     v.push_all(&name[..idx]);
487                     v.push(dot);
488                     v.push_all(extension.container_as_bytes());
489                     Some(v)
490                 }
491             }
492         });
493
494         match val {
495             None => (),
496             Some(v) => unsafe { self.set_filename_unchecked(v) }
497         }
498     }
499
500     /// Returns a new Path constructed by replacing the filename with the given
501     /// byte vector or string.
502     /// See `set_filename` for details.
503     ///
504     /// # Example
505     ///
506     /// ```
507     /// # foo();
508     /// # #[cfg(windows)] fn foo() {}
509     /// # #[cfg(unix)] fn foo() {
510     /// let mut p = Path::new("abc/def.txt");
511     /// assert_eq!(p.with_filename("foo.dat"), Path::new("abc/foo.dat"));
512     /// # }
513     /// ```
514     ///
515     /// # Panics
516     ///
517     /// Panics the task if the filename contains a NUL.
518     #[inline]
519     fn with_filename<T: BytesContainer>(&self, filename: T) -> Self {
520         let mut p = self.clone();
521         p.set_filename(filename);
522         p
523     }
524
525     /// Returns a new Path constructed by setting the extension to the given
526     /// byte vector or string.
527     /// See `set_extension` for details.
528     ///
529     /// # Example
530     ///
531     /// ```
532     /// # foo();
533     /// # #[cfg(windows)] fn foo() {}
534     /// # #[cfg(unix)] fn foo() {
535     /// let mut p = Path::new("abc/def.txt");
536     /// assert_eq!(p.with_extension("csv"), Path::new("abc/def.csv"));
537     /// # }
538     /// ```
539     ///
540     /// # Panics
541     ///
542     /// Panics the task if the extension contains a NUL.
543     #[inline]
544     fn with_extension<T: BytesContainer>(&self, extension: T) -> Self {
545         let mut p = self.clone();
546         p.set_extension(extension);
547         p
548     }
549
550     /// Returns the directory component of `self`, as a Path.
551     /// If `self` represents the root of the filesystem hierarchy, returns `self`.
552     ///
553     /// # Example
554     ///
555     /// ```
556     /// # foo();
557     /// # #[cfg(windows)] fn foo() {}
558     /// # #[cfg(unix)] fn foo() {
559     /// let p = Path::new("abc/def/ghi");
560     /// assert_eq!(p.dir_path(), Path::new("abc/def"));
561     /// # }
562     /// ```
563     fn dir_path(&self) -> Self {
564         // self.dirname() returns a NUL-free vector
565         unsafe { GenericPathUnsafe::new_unchecked(self.dirname()) }
566     }
567
568     /// Returns a Path that represents the filesystem root that `self` is rooted in.
569     ///
570     /// If `self` is not absolute, or vol/cwd-relative in the case of Windows, this returns None.
571     ///
572     /// # Example
573     ///
574     /// ```
575     /// # foo();
576     /// # #[cfg(windows)] fn foo() {}
577     /// # #[cfg(unix)] fn foo() {
578     /// assert_eq!(Path::new("abc/def").root_path(), None);
579     /// assert_eq!(Path::new("/abc/def").root_path(), Some(Path::new("/")));
580     /// # }
581     /// ```
582     fn root_path(&self) -> Option<Self>;
583
584     /// Pushes a path (as a byte vector or string) onto `self`.
585     /// If the argument represents an absolute path, it replaces `self`.
586     ///
587     /// # Example
588     ///
589     /// ```
590     /// # foo();
591     /// # #[cfg(windows)] fn foo() {}
592     /// # #[cfg(unix)] fn foo() {
593     /// let mut p = Path::new("foo/bar");
594     /// p.push("baz.txt");
595     /// assert_eq!(p, Path::new("foo/bar/baz.txt"));
596     /// # }
597     /// ```
598     ///
599     /// # Panics
600     ///
601     /// Panics the task if the path contains a NUL.
602     #[inline]
603     fn push<T: BytesContainer>(&mut self, path: T) {
604         assert!(!contains_nul(&path));
605         unsafe { self.push_unchecked(path) }
606     }
607
608     /// Pushes multiple paths (as byte vectors or strings) onto `self`.
609     /// See `push` for details.
610     ///
611     /// # Example
612     ///
613     /// ```
614     /// # foo();
615     /// # #[cfg(windows)] fn foo() {}
616     /// # #[cfg(unix)] fn foo() {
617     /// let mut p = Path::new("foo");
618     /// p.push_many(&["bar", "baz.txt"]);
619     /// assert_eq!(p, Path::new("foo/bar/baz.txt"));
620     /// # }
621     /// ```
622     #[inline]
623     fn push_many<T: BytesContainer>(&mut self, paths: &[T]) {
624         let t: Option<&T> = None;
625         if BytesContainer::is_str(t) {
626             for p in paths {
627                 self.push(p.container_as_str().unwrap())
628             }
629         } else {
630             for p in paths {
631                 self.push(p.container_as_bytes())
632             }
633         }
634     }
635
636     /// Removes the last path component from the receiver.
637     /// Returns `true` if the receiver was modified, or `false` if it already
638     /// represented the root of the file hierarchy.
639     ///
640     /// # Example
641     ///
642     /// ```
643     /// # foo();
644     /// # #[cfg(windows)] fn foo() {}
645     /// # #[cfg(unix)] fn foo() {
646     /// let mut p = Path::new("foo/bar/baz.txt");
647     /// p.pop();
648     /// assert_eq!(p, Path::new("foo/bar"));
649     /// # }
650     /// ```
651     fn pop(&mut self) -> bool;
652
653     /// Returns a new Path constructed by joining `self` with the given path
654     /// (as a byte vector or string).
655     /// If the given path is absolute, the new Path will represent just that.
656     ///
657     /// # Example
658     ///
659     /// ```
660     /// # foo();
661     /// # #[cfg(windows)] fn foo() {}
662     /// # #[cfg(unix)] fn foo() {
663     /// let p = Path::new("/foo");
664     /// assert_eq!(p.join("bar.txt"), Path::new("/foo/bar.txt"));
665     /// # }
666     /// ```
667     ///
668     /// # Panics
669     ///
670     /// Panics the task if the path contains a NUL.
671     #[inline]
672     fn join<T: BytesContainer>(&self, path: T) -> Self {
673         let mut p = self.clone();
674         p.push(path);
675         p
676     }
677
678     /// Returns a new Path constructed by joining `self` with the given paths
679     /// (as byte vectors or strings).
680     /// See `join` for details.
681     ///
682     /// # Example
683     ///
684     /// ```
685     /// # foo();
686     /// # #[cfg(windows)] fn foo() {}
687     /// # #[cfg(unix)] fn foo() {
688     /// let p = Path::new("foo");
689     /// let fbbq = Path::new("foo/bar/baz/quux.txt");
690     /// assert_eq!(p.join_many(&["bar", "baz", "quux.txt"]), fbbq);
691     /// # }
692     /// ```
693     #[inline]
694     fn join_many<T: BytesContainer>(&self, paths: &[T]) -> Self {
695         let mut p = self.clone();
696         p.push_many(paths);
697         p
698     }
699
700     /// Returns whether `self` represents an absolute path.
701     /// An absolute path is defined as one that, when joined to another path, will
702     /// yield back the same absolute path.
703     ///
704     /// # Example
705     ///
706     /// ```
707     /// # foo();
708     /// # #[cfg(windows)] fn foo() {}
709     /// # #[cfg(unix)] fn foo() {
710     /// let p = Path::new("/abc/def");
711     /// assert!(p.is_absolute());
712     /// # }
713     /// ```
714     fn is_absolute(&self) -> bool;
715
716     /// Returns whether `self` represents a relative path.
717     /// Typically this is the inverse of `is_absolute`.
718     /// But for Windows paths, it also means the path is not volume-relative or
719     /// relative to the current working directory.
720     ///
721     /// # Example
722     ///
723     /// ```
724     /// # foo();
725     /// # #[cfg(windows)] fn foo() {}
726     /// # #[cfg(unix)] fn foo() {
727     /// let p = Path::new("abc/def");
728     /// assert!(p.is_relative());
729     /// # }
730     /// ```
731     fn is_relative(&self) -> bool {
732         !self.is_absolute()
733     }
734
735     /// Returns whether `self` is equal to, or is an ancestor of, the given path.
736     /// If both paths are relative, they are compared as though they are relative
737     /// to the same parent path.
738     ///
739     /// # Example
740     ///
741     /// ```
742     /// # foo();
743     /// # #[cfg(windows)] fn foo() {}
744     /// # #[cfg(unix)] fn foo() {
745     /// let p = Path::new("foo/bar/baz/quux.txt");
746     /// let fb = Path::new("foo/bar");
747     /// let bq = Path::new("baz/quux.txt");
748     /// assert!(fb.is_ancestor_of(&p));
749     /// # }
750     /// ```
751     fn is_ancestor_of(&self, other: &Self) -> bool;
752
753     /// Returns the Path that, were it joined to `base`, would yield `self`.
754     /// If no such path exists, None is returned.
755     /// If `self` is absolute and `base` is relative, or on Windows if both
756     /// paths refer to separate drives, an absolute path is returned.
757     ///
758     /// # Example
759     ///
760     /// ```
761     /// # foo();
762     /// # #[cfg(windows)] fn foo() {}
763     /// # #[cfg(unix)] fn foo() {
764     /// let p = Path::new("foo/bar/baz/quux.txt");
765     /// let fb = Path::new("foo/bar");
766     /// let bq = Path::new("baz/quux.txt");
767     /// assert_eq!(p.path_relative_from(&fb), Some(bq));
768     /// # }
769     /// ```
770     fn path_relative_from(&self, base: &Self) -> Option<Self>;
771
772     /// Returns whether the relative path `child` is a suffix of `self`.
773     ///
774     /// # Example
775     ///
776     /// ```
777     /// # foo();
778     /// # #[cfg(windows)] fn foo() {}
779     /// # #[cfg(unix)] fn foo() {
780     /// let p = Path::new("foo/bar/baz/quux.txt");
781     /// let bq = Path::new("baz/quux.txt");
782     /// assert!(p.ends_with_path(&bq));
783     /// # }
784     /// ```
785     fn ends_with_path(&self, child: &Self) -> bool;
786 }
787
788 /// A trait that represents something bytes-like (e.g. a &[u8] or a &str)
789 pub trait BytesContainer {
790     /// Returns a &[u8] representing the receiver
791     fn container_as_bytes<'a>(&'a self) -> &'a [u8];
792     /// Returns the receiver interpreted as a utf-8 string, if possible
793     #[inline]
794     fn container_as_str<'a>(&'a self) -> Option<&'a str> {
795         str::from_utf8(self.container_as_bytes()).ok()
796     }
797     /// Returns whether .container_as_str() is guaranteed to not fail
798     // FIXME (#8888): Remove unused arg once ::<for T> works
799     #[inline]
800     fn is_str(_: Option<&Self>) -> bool { false }
801 }
802
803 /// A trait that represents the unsafe operations on GenericPaths
804 pub trait GenericPathUnsafe {
805     /// Creates a new Path without checking for null bytes.
806     /// The resulting Path will always be normalized.
807     unsafe fn new_unchecked<T: BytesContainer>(path: T) -> Self;
808
809     /// Replaces the filename portion of the path without checking for null
810     /// bytes.
811     /// See `set_filename` for details.
812     unsafe fn set_filename_unchecked<T: BytesContainer>(&mut self, filename: T);
813
814     /// Pushes a path onto `self` without checking for null bytes.
815     /// See `push` for details.
816     unsafe fn push_unchecked<T: BytesContainer>(&mut self, path: T);
817 }
818
819 /// Helper struct for printing paths with format!()
820 pub struct Display<'a, P:'a> {
821     path: &'a P,
822     filename: bool
823 }
824
825 #[stable(feature = "rust1", since = "1.0.0")]
826 impl<'a, P: GenericPath> fmt::Debug for Display<'a, P> {
827     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
828         fmt::Debug::fmt(&self.as_cow(), f)
829     }
830 }
831
832 #[stable(feature = "rust1", since = "1.0.0")]
833 impl<'a, P: GenericPath> fmt::Display for Display<'a, P> {
834     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
835         self.as_cow().fmt(f)
836     }
837 }
838
839 impl<'a, P: GenericPath> Display<'a, P> {
840     /// Returns the path as a possibly-owned string.
841     ///
842     /// If the path is not UTF-8, invalid sequences will be replaced with the
843     /// Unicode replacement char. This involves allocation.
844     #[inline]
845     pub fn as_cow(&self) -> CowString<'a> {
846         String::from_utf8_lossy(if self.filename {
847             match self.path.filename() {
848                 None => {
849                     let result: &[u8] = &[];
850                     result
851                 }
852                 Some(v) => v
853             }
854         } else {
855             self.path.as_vec()
856         })
857     }
858 }
859
860 impl BytesContainer for str {
861     #[inline]
862     fn container_as_bytes(&self) -> &[u8] {
863         self.as_bytes()
864     }
865     #[inline]
866     fn container_as_str(&self) -> Option<&str> {
867         Some(self)
868     }
869     #[inline]
870     fn is_str(_: Option<&str>) -> bool { true }
871 }
872
873 impl BytesContainer for String {
874     #[inline]
875     fn container_as_bytes(&self) -> &[u8] {
876         self.as_bytes()
877     }
878     #[inline]
879     fn container_as_str(&self) -> Option<&str> {
880         Some(&self[..])
881     }
882     #[inline]
883     fn is_str(_: Option<&String>) -> bool { true }
884 }
885
886 impl BytesContainer for [u8] {
887     #[inline]
888     fn container_as_bytes(&self) -> &[u8] {
889         self
890     }
891 }
892
893 impl BytesContainer for Vec<u8> {
894     #[inline]
895     fn container_as_bytes(&self) -> &[u8] {
896         &self[..]
897     }
898 }
899
900 impl BytesContainer for CString {
901     #[inline]
902     fn container_as_bytes<'a>(&'a self) -> &'a [u8] {
903         self.as_bytes()
904     }
905 }
906
907 impl<'a, T: ?Sized + BytesContainer> BytesContainer for &'a T {
908     #[inline]
909     fn container_as_bytes(&self) -> &[u8] {
910         (**self).container_as_bytes()
911     }
912     #[inline]
913     fn container_as_str(&self) -> Option<&str> {
914         (**self).container_as_str()
915     }
916     #[inline]
917     fn is_str(_: Option<& &'a T>) -> bool { BytesContainer::is_str(None::<&T>) }
918 }
919
920 #[inline(always)]
921 fn contains_nul<T: BytesContainer>(v: &T) -> bool {
922     v.container_as_bytes().iter().any(|&x| x == 0)
923 }