mod.rs 27.7 KB
Newer Older
1 2 3 4 5 6 7 8 9 10
// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

11 12 13 14 15 16 17 18 19 20 21 22
/*!

Cross-platform path support

This module implements support for two flavors of paths. `PosixPath` represents
a path on any unix-like system, whereas `WindowsPath` represents a path on
Windows. This module also exposes a typedef `Path` which is equal to the
appropriate platform-specific path variant.

Both `PosixPath` and `WindowsPath` implement a trait `GenericPath`, which
contains the set of methods that behave the same for both paths. They each also
implement some methods that could not be expressed in `GenericPath`, yet behave
23
identically for both path flavors, such as `.components()`.
24 25 26 27 28 29 30 31 32

The three main design goals of this module are 1) to avoid unnecessary
allocation, 2) to behave the same regardless of which flavor of path is being
used, and 3) to support paths that cannot be represented in UTF-8 (as Linux has
no restriction on paths beyond disallowing NUL).

## Usage

Usage of this module is fairly straightforward. Unless writing platform-specific
33
code, `Path` should be used to refer to the platform-native path.
34

35 36
Creation of a path is typically done with either `Path::new(some_str)` or
`Path::new(some_vec)`. This path can be modified with `.push()` and
37
`.pop()` (and other setters). The resulting Path can either be passed to another
38 39
API that expects a path, or can be turned into a `&[u8]` with `.as_vec()` or a
`Option<&str>` with `.as_str()`. Similarly, attributes of the path can be queried
40 41 42
with methods such as `.filename()`. There are also methods that return a new
path instead of modifying the receiver, such as `.join()` or `.dir_path()`.

K
Kevin Ballard 已提交
43
Paths are always kept in normalized form. This means that creating the path
44
`Path::new("a/b/../c")` will return the path `a/c`. Similarly any attempt
K
Kevin Ballard 已提交
45 46
to mutate the path will always leave it in normalized form.

47
When rendering a path to some form of output, there is a method `.display()`
48 49 50 51 52 53 54 55
which is compatible with the `format!()` parameter `{}`. This will render the
path as a string, replacing all non-utf8 sequences with the Replacement
Character (U+FFFD). As such it is not suitable for passing to any API that
actually operates on the path; it is only intended for display.

## Example

```rust
56
let mut path = Path::new("/tmp/path");
A
Alex Crichton 已提交
57
println!("path: {}", path.display());
58 59
path.set_filename("foo");
path.push("bar");
A
Alex Crichton 已提交
60 61
println!("new path: {}", path.display());
println!("path exists: {}", path.exists());
62 63 64
```

*/
65

66 67
#![experimental]

68
use collections::{Collection, MutableSeq};
69 70
use c_str::CString;
use clone::Clone;
71
use fmt;
72
use iter::Iterator;
73 74
use option::{Option, None, Some};
use str;
75
use str::{MaybeOwned, Str, StrSlice};
76
use string::String;
77
use slice::Slice;
78
use slice::{ImmutableEqSlice, ImmutableSlice};
79
use vec::Vec;
80 81 82

/// Typedef for POSIX file paths.
/// See `posix::Path` for more info.
83
pub use PosixPath = self::posix::Path;
84

K
Kevin Ballard 已提交
85 86
/// Typedef for Windows file paths.
/// See `windows::Path` for more info.
87
pub use WindowsPath = self::windows::Path;
88 89 90

/// Typedef for the platform-native path type
#[cfg(unix)]
91
pub use Path = self::posix::Path;
K
Kevin Ballard 已提交
92 93
/// Typedef for the platform-native path type
#[cfg(windows)]
94
pub use Path = self::windows::Path;
95 96 97

/// Typedef for the platform-native component iterator
#[cfg(unix)]
P
Palmer Cox 已提交
98
pub use Components = self::posix::Components;
99 100
/// Typedef for the platform-native component iterator
#[cfg(windows)]
P
Palmer Cox 已提交
101
pub use Components = self::windows::Components;
102 103 104

/// Typedef for the platform-native str component iterator
#[cfg(unix)]
P
Palmer Cox 已提交
105
pub use StrComponents = self::posix::StrComponents;
106 107
/// Typedef for the platform-native str component iterator
#[cfg(windows)]
P
Palmer Cox 已提交
108
pub use StrComponents = self::windows::StrComponents;
109

110 111 112
/// Alias for the platform-native separator character.
#[cfg(unix)]
pub use SEP = self::posix::SEP;
113
/// Alias for the platform-native separator character.
114 115 116
#[cfg(windows)]
pub use SEP = self::windows::SEP;

117
/// Alias for the platform-native separator byte.
118 119 120 121 122 123
#[cfg(unix)]
pub use SEP_BYTE = self::posix::SEP_BYTE;
/// Alias for the platform-native separator byte.
#[cfg(windows)]
pub use SEP_BYTE = self::windows::SEP_BYTE;

124 125 126 127 128 129 130 131 132 133 134 135 136
/// Typedef for the platform-native separator char func
#[cfg(unix)]
pub use is_sep = self::posix::is_sep;
/// Typedef for the platform-native separator char func
#[cfg(windows)]
pub use is_sep = self::windows::is_sep;
/// Typedef for the platform-native separator byte func
#[cfg(unix)]
pub use is_sep_byte = self::posix::is_sep_byte;
/// Typedef for the platform-native separator byte func
#[cfg(windows)]
pub use is_sep_byte = self::windows::is_sep_byte;

137 138
pub mod posix;
pub mod windows;
139 140 141

/// A trait that represents the generic operations available on paths
pub trait GenericPath: Clone + GenericPathUnsafe {
142
    /// Creates a new Path from a byte vector or string.
143 144
    /// The resulting Path will always be normalized.
    ///
N
nham 已提交
145 146 147
    /// # Example
    ///
    /// ```
148 149 150
    /// # foo();
    /// # #[cfg(windows)] fn foo() {}
    /// # #[cfg(unix)] fn foo() {
N
nham 已提交
151
    /// let path = Path::new("foo/bar");
152
    /// # }
N
nham 已提交
153 154
    /// ```
    ///
155 156
    /// # Failure
    ///
A
Alex Crichton 已提交
157
    /// Fails the task if the path contains a NUL.
K
Kevin Ballard 已提交
158 159
    ///
    /// See individual Path impls for additional restrictions.
160
    #[inline]
161
    fn new<T: BytesContainer>(path: T) -> Self {
162
        assert!(!contains_nul(&path));
A
Alex Crichton 已提交
163
        unsafe { GenericPathUnsafe::new_unchecked(path) }
164 165
    }

166
    /// Creates a new Path from a byte vector or string, if possible.
167
    /// The resulting Path will always be normalized.
N
nham 已提交
168 169 170 171
    ///
    /// # Example
    ///
    /// ```
172 173 174
    /// # foo();
    /// # #[cfg(windows)] fn foo() {}
    /// # #[cfg(unix)] fn foo() {
175
    /// let x: &[u8] = b"foo\0";
N
nham 已提交
176
    /// assert!(Path::new_opt(x).is_none());
177
    /// # }
N
nham 已提交
178
    /// ```
179
    #[inline]
180
    fn new_opt<T: BytesContainer>(path: T) -> Option<Self> {
181
        if contains_nul(&path) {
182 183
            None
        } else {
184
            Some(unsafe { GenericPathUnsafe::new_unchecked(path) })
185 186 187
        }
    }

188 189
    /// Returns the path as a string, if possible.
    /// If the path is not representable in utf-8, this returns None.
N
nham 已提交
190 191 192 193
    ///
    /// # Example
    ///
    /// ```
194 195 196
    /// # foo();
    /// # #[cfg(windows)] fn foo() {}
    /// # #[cfg(unix)] fn foo() {
N
nham 已提交
197 198
    /// let p = Path::new("/abc/def");
    /// assert_eq!(p.as_str(), Some("/abc/def"));
199
    /// # }
N
nham 已提交
200
    /// ```
201 202
    #[inline]
    fn as_str<'a>(&'a self) -> Option<&'a str> {
203
        str::from_utf8(self.as_vec())
204 205 206
    }

    /// Returns the path as a byte vector
N
nham 已提交
207 208 209 210
    ///
    /// # Example
    ///
    /// ```
211 212 213
    /// # foo();
    /// # #[cfg(windows)] fn foo() {}
    /// # #[cfg(unix)] fn foo() {
N
nham 已提交
214
    /// let p = Path::new("abc/def");
215
    /// assert_eq!(p.as_vec(), b"abc/def");
216
    /// # }
N
nham 已提交
217
    /// ```
218 219
    fn as_vec<'a>(&'a self) -> &'a [u8];

220
    /// Converts the Path into an owned byte vector
N
nham 已提交
221 222 223 224
    ///
    /// # Example
    ///
    /// ```
225 226 227
    /// # foo();
    /// # #[cfg(windows)] fn foo() {}
    /// # #[cfg(unix)] fn foo() {
N
nham 已提交
228
    /// let p = Path::new("abc/def");
229
    /// assert_eq!(p.into_vec(), b"abc/def".to_vec());
N
nham 已提交
230
    /// // attempting to use p now results in "error: use of moved value"
231
    /// # }
N
nham 已提交
232
    /// ```
233
    fn into_vec(self) -> Vec<u8>;
234

235
    /// Returns an object that implements `Show` for printing paths
N
nham 已提交
236 237 238 239
    ///
    /// # Example
    ///
    /// ```
240 241 242
    /// # foo();
    /// # #[cfg(windows)] fn foo() {}
    /// # #[cfg(unix)] fn foo() {
N
nham 已提交
243 244
    /// let p = Path::new("abc/def");
    /// println!("{}", p.display()); // prints "abc/def"
245
    /// # }
N
nham 已提交
246
    /// ```
247
    fn display<'a>(&'a self) -> Display<'a, Self> {
248
        Display{ path: self, filename: false }
249 250
    }

251
    /// Returns an object that implements `Show` for printing filenames
252
    ///
253
    /// If there is no filename, nothing will be printed.
N
nham 已提交
254 255 256 257
    ///
    /// # Example
    ///
    /// ```
258 259 260
    /// # foo();
    /// # #[cfg(windows)] fn foo() {}
    /// # #[cfg(unix)] fn foo() {
N
nham 已提交
261 262
    /// let p = Path::new("abc/def");
    /// println!("{}", p.filename_display()); // prints "def"
263
    /// # }
N
nham 已提交
264
    /// ```
265 266
    fn filename_display<'a>(&'a self) -> Display<'a, Self> {
        Display{ path: self, filename: true }
267 268
    }

269 270
    /// Returns the directory component of `self`, as a byte vector (with no trailing separator).
    /// If `self` has no directory component, returns ['.'].
N
nham 已提交
271 272 273 274
    ///
    /// # Example
    ///
    /// ```
275 276 277
    /// # foo();
    /// # #[cfg(windows)] fn foo() {}
    /// # #[cfg(unix)] fn foo() {
N
nham 已提交
278
    /// let p = Path::new("abc/def/ghi");
279
    /// assert_eq!(p.dirname(), b"abc/def");
280
    /// # }
N
nham 已提交
281
    /// ```
282
    fn dirname<'a>(&'a self) -> &'a [u8];
N
nham 已提交
283

284 285
    /// Returns the directory component of `self`, as a string, if possible.
    /// See `dirname` for details.
N
nham 已提交
286 287 288 289
    ///
    /// # Example
    ///
    /// ```
290 291 292
    /// # foo();
    /// # #[cfg(windows)] fn foo() {}
    /// # #[cfg(unix)] fn foo() {
N
nham 已提交
293 294
    /// let p = Path::new("abc/def/ghi");
    /// assert_eq!(p.dirname_str(), Some("abc/def"));
295
    /// # }
N
nham 已提交
296
    /// ```
297 298
    #[inline]
    fn dirname_str<'a>(&'a self) -> Option<&'a str> {
299
        str::from_utf8(self.dirname())
300
    }
N
nham 已提交
301

302
    /// Returns the file component of `self`, as a byte vector.
303 304
    /// If `self` represents the root of the file hierarchy, returns None.
    /// If `self` is "." or "..", returns None.
N
nham 已提交
305 306 307 308
    ///
    /// # Example
    ///
    /// ```
309 310 311
    /// # foo();
    /// # #[cfg(windows)] fn foo() {}
    /// # #[cfg(unix)] fn foo() {
N
nham 已提交
312
    /// let p = Path::new("abc/def/ghi");
313
    /// assert_eq!(p.filename(), Some(b"ghi"));
314
    /// # }
N
nham 已提交
315
    /// ```
316
    fn filename<'a>(&'a self) -> Option<&'a [u8]>;
N
nham 已提交
317

318 319
    /// Returns the file component of `self`, as a string, if possible.
    /// See `filename` for details.
N
nham 已提交
320 321 322 323
    ///
    /// # Example
    ///
    /// ```
324 325 326
    /// # foo();
    /// # #[cfg(windows)] fn foo() {}
    /// # #[cfg(unix)] fn foo() {
N
nham 已提交
327 328
    /// let p = Path::new("abc/def/ghi");
    /// assert_eq!(p.filename_str(), Some("ghi"));
329
    /// # }
N
nham 已提交
330
    /// ```
331 332
    #[inline]
    fn filename_str<'a>(&'a self) -> Option<&'a str> {
333
        self.filename().and_then(str::from_utf8)
334
    }
N
nham 已提交
335

336 337 338
    /// Returns the stem of the filename of `self`, as a byte vector.
    /// The stem is the portion of the filename just before the last '.'.
    /// If there is no '.', the entire filename is returned.
N
nham 已提交
339 340 341 342
    ///
    /// # Example
    ///
    /// ```
343 344 345
    /// # foo();
    /// # #[cfg(windows)] fn foo() {}
    /// # #[cfg(unix)] fn foo() {
N
nham 已提交
346
    /// let p = Path::new("/abc/def.txt");
347
    /// assert_eq!(p.filestem(), Some(b"def"));
348
    /// # }
N
nham 已提交
349
    /// ```
350 351 352 353
    fn filestem<'a>(&'a self) -> Option<&'a [u8]> {
        match self.filename() {
            None => None,
            Some(name) => Some({
N
nham 已提交
354
                let dot = b'.';
355 356
                match name.rposition_elem(&dot) {
                    None | Some(0) => name,
S
Simon Sapin 已提交
357
                    Some(1) if name == b".." => name,
358 359 360
                    Some(pos) => name.slice_to(pos)
                }
            })
361 362
        }
    }
N
nham 已提交
363

364 365
    /// Returns the stem of the filename of `self`, as a string, if possible.
    /// See `filestem` for details.
N
nham 已提交
366 367 368 369
    ///
    /// # Example
    ///
    /// ```
370 371 372
    /// # foo();
    /// # #[cfg(windows)] fn foo() {}
    /// # #[cfg(unix)] fn foo() {
N
nham 已提交
373 374
    /// let p = Path::new("/abc/def.txt");
    /// assert_eq!(p.filestem_str(), Some("def"));
375
    /// # }
N
nham 已提交
376
    /// ```
377 378
    #[inline]
    fn filestem_str<'a>(&'a self) -> Option<&'a str> {
379
        self.filestem().and_then(str::from_utf8)
380
    }
N
nham 已提交
381

382 383 384 385
    /// Returns the extension of the filename of `self`, as an optional byte vector.
    /// The extension is the portion of the filename just after the last '.'.
    /// If there is no extension, None is returned.
    /// If the filename ends in '.', the empty vector is returned.
N
nham 已提交
386 387 388 389
    ///
    /// # Example
    ///
    /// ```
390 391 392
    /// # foo();
    /// # #[cfg(windows)] fn foo() {}
    /// # #[cfg(unix)] fn foo() {
N
nham 已提交
393
    /// let p = Path::new("abc/def.txt");
394
    /// assert_eq!(p.extension(), Some(b"txt"));
395
    /// # }
N
nham 已提交
396
    /// ```
397
    fn extension<'a>(&'a self) -> Option<&'a [u8]> {
398 399 400
        match self.filename() {
            None => None,
            Some(name) => {
N
nham 已提交
401
                let dot = b'.';
402 403
                match name.rposition_elem(&dot) {
                    None | Some(0) => None,
S
Simon Sapin 已提交
404
                    Some(1) if name == b".." => None,
405 406 407
                    Some(pos) => Some(name.slice_from(pos+1))
                }
            }
408 409
        }
    }
N
nham 已提交
410

411 412
    /// Returns the extension of the filename of `self`, as a string, if possible.
    /// See `extension` for details.
N
nham 已提交
413 414 415 416
    ///
    /// # Example
    ///
    /// ```
417 418 419
    /// # foo();
    /// # #[cfg(windows)] fn foo() {}
    /// # #[cfg(unix)] fn foo() {
N
nham 已提交
420 421
    /// let p = Path::new("abc/def.txt");
    /// assert_eq!(p.extension_str(), Some("txt"));
422
    /// # }
N
nham 已提交
423
    /// ```
424 425
    #[inline]
    fn extension_str<'a>(&'a self) -> Option<&'a str> {
426
        self.extension().and_then(str::from_utf8)
427 428
    }

429
    /// Replaces the filename portion of the path with the given byte vector or string.
430 431
    /// If the replacement name is [], this is equivalent to popping the path.
    ///
N
nham 已提交
432 433 434
    /// # Example
    ///
    /// ```
435 436 437
    /// # foo();
    /// # #[cfg(windows)] fn foo() {}
    /// # #[cfg(unix)] fn foo() {
N
nham 已提交
438 439 440
    /// let mut p = Path::new("abc/def.txt");
    /// p.set_filename("foo.dat");
    /// assert!(p == Path::new("abc/foo.dat"));
441
    /// # }
N
nham 已提交
442 443
    /// ```
    ///
444 445
    /// # Failure
    ///
A
Alex Crichton 已提交
446
    /// Fails the task if the filename contains a NUL.
447
    #[inline]
448
    fn set_filename<T: BytesContainer>(&mut self, filename: T) {
449
        assert!(!contains_nul(&filename));
A
Alex Crichton 已提交
450
        unsafe { self.set_filename_unchecked(filename) }
451
    }
N
nham 已提交
452

453
    /// Replaces the extension with the given byte vector or string.
454
    /// If there is no extension in `self`, this adds one.
455
    /// If the argument is [] or "", this removes the extension.
456 457
    /// If `self` has no filename, this is a no-op.
    ///
N
nham 已提交
458 459 460
    /// # Example
    ///
    /// ```
461 462 463
    /// # foo();
    /// # #[cfg(windows)] fn foo() {}
    /// # #[cfg(unix)] fn foo() {
N
nham 已提交
464 465 466
    /// let mut p = Path::new("abc/def.txt");
    /// p.set_extension("csv");
    /// assert!(p == Path::new("abc/def.csv"));
467
    /// # }
N
nham 已提交
468 469
    /// ```
    ///
470 471
    /// # Failure
    ///
A
Alex Crichton 已提交
472
    /// Fails the task if the extension contains a NUL.
473
    fn set_extension<T: BytesContainer>(&mut self, extension: T) {
474
        assert!(!contains_nul(&extension));
475 476

        let val = self.filename().and_then(|name| {
N
nham 已提交
477
            let dot = b'.';
478 479 480
            let extlen = extension.container_as_bytes().len();
            match (name.rposition_elem(&dot), extlen) {
                (None, 0) | (Some(0), 0) => None,
481
                (Some(idx), 0) => Some(Vec::from_slice(name.slice_to(idx))),
482 483 484 485 486 487 488
                (idx, extlen) => {
                    let idx = match idx {
                        None | Some(0) => name.len(),
                        Some(val) => val
                    };

                    let mut v;
489
                    v = Vec::with_capacity(idx + extlen + 1);
490 491 492 493
                    v.push_all(name.slice_to(idx));
                    v.push(dot);
                    v.push_all(extension.container_as_bytes());
                    Some(v)
494
                }
495
            }
496 497
        });

498 499 500 501 502 503
        match val {
            None => (),
            Some(v) => unsafe { self.set_filename_unchecked(v) }
        }
    }

504 505
    /// Returns a new Path constructed by replacing the filename with the given
    /// byte vector or string.
506 507
    /// See `set_filename` for details.
    ///
N
nham 已提交
508 509 510
    /// # Example
    ///
    /// ```
511 512 513
    /// # foo();
    /// # #[cfg(windows)] fn foo() {}
    /// # #[cfg(unix)] fn foo() {
N
nham 已提交
514 515
    /// let mut p = Path::new("abc/def.txt");
    /// assert!(p.with_filename("foo.dat") == Path::new("abc/foo.dat"));
516
    /// # }
N
nham 已提交
517 518
    /// ```
    ///
519 520
    /// # Failure
    ///
A
Alex Crichton 已提交
521
    /// Fails the task if the filename contains a NUL.
522
    #[inline]
523
    fn with_filename<T: BytesContainer>(&self, filename: T) -> Self {
524 525 526 527
        let mut p = self.clone();
        p.set_filename(filename);
        p
    }
N
nham 已提交
528

529 530
    /// Returns a new Path constructed by setting the extension to the given
    /// byte vector or string.
531 532
    /// See `set_extension` for details.
    ///
533 534 535
    /// # Example
    ///
    /// ```
536 537 538
    /// # foo();
    /// # #[cfg(windows)] fn foo() {}
    /// # #[cfg(unix)] fn foo() {
539 540
    /// let mut p = Path::new("abc/def.txt");
    /// assert!(p.with_extension("csv") == Path::new("abc/def.csv"));
541
    /// # }
542 543
    /// ```
    ///
544 545
    /// # Failure
    ///
A
Alex Crichton 已提交
546
    /// Fails the task if the extension contains a NUL.
547
    #[inline]
548
    fn with_extension<T: BytesContainer>(&self, extension: T) -> Self {
549 550 551 552 553 554 555
        let mut p = self.clone();
        p.set_extension(extension);
        p
    }

    /// Returns the directory component of `self`, as a Path.
    /// If `self` represents the root of the filesystem hierarchy, returns `self`.
N
nham 已提交
556 557 558 559
    ///
    /// # Example
    ///
    /// ```
560 561 562
    /// # foo();
    /// # #[cfg(windows)] fn foo() {}
    /// # #[cfg(unix)] fn foo() {
N
nham 已提交
563 564
    /// let p = Path::new("abc/def/ghi");
    /// assert!(p.dir_path() == Path::new("abc/def"));
565
    /// # }
N
nham 已提交
566
    /// ```
567
    fn dir_path(&self) -> Self {
K
Kevin Ballard 已提交
568
        // self.dirname() returns a NUL-free vector
569
        unsafe { GenericPathUnsafe::new_unchecked(self.dirname()) }
570 571
    }

572 573
    /// Returns a Path that represents the filesystem root that `self` is rooted in.
    ///
574
    /// If `self` is not absolute, or vol/cwd-relative in the case of Windows, this returns None.
N
nham 已提交
575 576 577 578
    ///
    /// # Example
    ///
    /// ```
579 580 581
    /// # foo();
    /// # #[cfg(windows)] fn foo() {}
    /// # #[cfg(unix)] fn foo() {
N
nham 已提交
582 583
    /// assert!(Path::new("abc/def").root_path() == None);
    /// assert!(Path::new("/abc/def").root_path() == Some(Path::new("/")));
584
    /// # }
N
nham 已提交
585
    /// ```
586 587
    fn root_path(&self) -> Option<Self>;

588
    /// Pushes a path (as a byte vector or string) onto `self`.
589 590
    /// If the argument represents an absolute path, it replaces `self`.
    ///
N
nham 已提交
591 592 593
    /// # Example
    ///
    /// ```
594 595 596
    /// # foo();
    /// # #[cfg(windows)] fn foo() {}
    /// # #[cfg(unix)] fn foo() {
N
nham 已提交
597 598 599
    /// let mut p = Path::new("foo/bar");
    /// p.push("baz.txt");
    /// assert!(p == Path::new("foo/bar/baz.txt"));
600
    /// # }
N
nham 已提交
601 602
    /// ```
    ///
603 604
    /// # Failure
    ///
A
Alex Crichton 已提交
605
    /// Fails the task if the path contains a NUL.
606
    #[inline]
607
    fn push<T: BytesContainer>(&mut self, path: T) {
608
        assert!(!contains_nul(&path));
A
Alex Crichton 已提交
609
        unsafe { self.push_unchecked(path) }
610
    }
N
nham 已提交
611

612
    /// Pushes multiple paths (as byte vectors or strings) onto `self`.
613
    /// See `push` for details.
N
nham 已提交
614 615 616 617
    ///
    /// # Example
    ///
    /// ```
618 619 620
    /// # foo();
    /// # #[cfg(windows)] fn foo() {}
    /// # #[cfg(unix)] fn foo() {
N
nham 已提交
621 622 623
    /// let mut p = Path::new("foo");
    /// p.push_many(&["bar", "baz.txt"]);
    /// assert!(p == Path::new("foo/bar/baz.txt"));
624
    /// # }
N
nham 已提交
625
    /// ```
626
    #[inline]
627 628 629 630
    fn push_many<T: BytesContainer>(&mut self, paths: &[T]) {
        let t: Option<T> = None;
        if BytesContainer::is_str(t) {
            for p in paths.iter() {
631
                self.push(p.container_as_str().unwrap())
632 633 634 635 636
            }
        } else {
            for p in paths.iter() {
                self.push(p.container_as_bytes())
            }
637 638
        }
    }
N
nham 已提交
639

K
Kevin Ballard 已提交
640 641 642
    /// Removes the last path component from the receiver.
    /// Returns `true` if the receiver was modified, or `false` if it already
    /// represented the root of the file hierarchy.
N
nham 已提交
643 644 645 646
    ///
    /// # Example
    ///
    /// ```
647 648 649
    /// # foo();
    /// # #[cfg(windows)] fn foo() {}
    /// # #[cfg(unix)] fn foo() {
N
nham 已提交
650 651 652
    /// let mut p = Path::new("foo/bar/baz.txt");
    /// p.pop();
    /// assert!(p == Path::new("foo/bar"));
653
    /// # }
N
nham 已提交
654
    /// ```
K
Kevin Ballard 已提交
655
    fn pop(&mut self) -> bool;
656

657 658
    /// Returns a new Path constructed by joining `self` with the given path
    /// (as a byte vector or string).
659 660
    /// If the given path is absolute, the new Path will represent just that.
    ///
N
nham 已提交
661 662 663
    /// # Example
    ///
    /// ```
664 665 666
    /// # foo();
    /// # #[cfg(windows)] fn foo() {}
    /// # #[cfg(unix)] fn foo() {
N
nham 已提交
667 668
    /// let p = Path::new("/foo");
    /// assert!(p.join("bar.txt") == Path::new("/foo/bar.txt"));
669
    /// # }
N
nham 已提交
670 671
    /// ```
    ///
672 673
    /// # Failure
    ///
A
Alex Crichton 已提交
674
    /// Fails the task if the path contains a NUL.
675
    #[inline]
676
    fn join<T: BytesContainer>(&self, path: T) -> Self {
677 678 679 680
        let mut p = self.clone();
        p.push(path);
        p
    }
N
nham 已提交
681

682 683
    /// Returns a new Path constructed by joining `self` with the given paths
    /// (as byte vectors or strings).
684
    /// See `join` for details.
N
nham 已提交
685 686 687 688
    ///
    /// # Example
    ///
    /// ```
689 690 691
    /// # foo();
    /// # #[cfg(windows)] fn foo() {}
    /// # #[cfg(unix)] fn foo() {
N
nham 已提交
692 693 694
    /// let p = Path::new("foo");
    /// let fbbq = Path::new("foo/bar/baz/quux.txt");
    /// assert!(p.join_many(&["bar", "baz", "quux.txt"]) == fbbq);
695
    /// # }
N
nham 已提交
696
    /// ```
697
    #[inline]
698
    fn join_many<T: BytesContainer>(&self, paths: &[T]) -> Self {
699 700 701 702
        let mut p = self.clone();
        p.push_many(paths);
        p
    }
703 704

    /// Returns whether `self` represents an absolute path.
K
Kevin Ballard 已提交
705 706
    /// An absolute path is defined as one that, when joined to another path, will
    /// yield back the same absolute path.
N
nham 已提交
707 708 709 710
    ///
    /// # Example
    ///
    /// ```
711 712 713
    /// # foo();
    /// # #[cfg(windows)] fn foo() {}
    /// # #[cfg(unix)] fn foo() {
N
nham 已提交
714 715
    /// let p = Path::new("/abc/def");
    /// assert!(p.is_absolute());
716
    /// # }
N
nham 已提交
717
    /// ```
718 719
    fn is_absolute(&self) -> bool;

720 721 722 723
    /// Returns whether `self` represents a relative path.
    /// Typically this is the inverse of `is_absolute`.
    /// But for Windows paths, it also means the path is not volume-relative or
    /// relative to the current working directory.
N
nham 已提交
724 725 726 727
    ///
    /// # Example
    ///
    /// ```
728 729 730
    /// # foo();
    /// # #[cfg(windows)] fn foo() {}
    /// # #[cfg(unix)] fn foo() {
N
nham 已提交
731 732
    /// let p = Path::new("abc/def");
    /// assert!(p.is_relative());
733
    /// # }
N
nham 已提交
734
    /// ```
735 736 737 738
    fn is_relative(&self) -> bool {
        !self.is_absolute()
    }

739 740 741
    /// Returns whether `self` is equal to, or is an ancestor of, the given path.
    /// If both paths are relative, they are compared as though they are relative
    /// to the same parent path.
N
nham 已提交
742 743 744 745
    ///
    /// # Example
    ///
    /// ```
746 747 748
    /// # foo();
    /// # #[cfg(windows)] fn foo() {}
    /// # #[cfg(unix)] fn foo() {
N
nham 已提交
749 750 751 752
    /// let p = Path::new("foo/bar/baz/quux.txt");
    /// let fb = Path::new("foo/bar");
    /// let bq = Path::new("baz/quux.txt");
    /// assert!(fb.is_ancestor_of(&p));
753
    /// # }
N
nham 已提交
754
    /// ```
755 756 757 758 759 760
    fn is_ancestor_of(&self, other: &Self) -> bool;

    /// Returns the Path that, were it joined to `base`, would yield `self`.
    /// If no such path exists, None is returned.
    /// If `self` is absolute and `base` is relative, or on Windows if both
    /// paths refer to separate drives, an absolute path is returned.
N
nham 已提交
761 762 763 764
    ///
    /// # Example
    ///
    /// ```
765 766 767
    /// # foo();
    /// # #[cfg(windows)] fn foo() {}
    /// # #[cfg(unix)] fn foo() {
N
nham 已提交
768 769 770 771
    /// let p = Path::new("foo/bar/baz/quux.txt");
    /// let fb = Path::new("foo/bar");
    /// let bq = Path::new("baz/quux.txt");
    /// assert!(p.path_relative_from(&fb) == Some(bq));
772
    /// # }
N
nham 已提交
773
    /// ```
774
    fn path_relative_from(&self, base: &Self) -> Option<Self>;
775

776
    /// Returns whether the relative path `child` is a suffix of `self`.
N
nham 已提交
777 778 779 780
    ///
    /// # Example
    ///
    /// ```
781 782 783
    /// # foo();
    /// # #[cfg(windows)] fn foo() {}
    /// # #[cfg(unix)] fn foo() {
N
nham 已提交
784 785 786
    /// let p = Path::new("foo/bar/baz/quux.txt");
    /// let bq = Path::new("baz/quux.txt");
    /// assert!(p.ends_with_path(&bq));
787
    /// # }
N
nham 已提交
788
    /// ```
789 790 791 792 793 794 795
    fn ends_with_path(&self, child: &Self) -> bool;
}

/// A trait that represents something bytes-like (e.g. a &[u8] or a &str)
pub trait BytesContainer {
    /// Returns a &[u8] representing the receiver
    fn container_as_bytes<'a>(&'a self) -> &'a [u8];
796
    /// Consumes the receiver and converts it into Vec<u8>
797
    #[inline]
798 799
    fn container_into_owned_bytes(self) -> Vec<u8> {
        Vec::from_slice(self.container_as_bytes())
800 801 802
    }
    /// Returns the receiver interpreted as a utf-8 string, if possible
    #[inline]
803
    fn container_as_str<'a>(&'a self) -> Option<&'a str> {
804
        str::from_utf8(self.container_as_bytes())
805
    }
806
    /// Returns whether .container_as_str() is guaranteed to not fail
807 808 809
    // FIXME (#8888): Remove unused arg once ::<for T> works
    #[inline]
    fn is_str(_: Option<Self>) -> bool { false }
810 811 812 813
}

/// A trait that represents the unsafe operations on GenericPaths
pub trait GenericPathUnsafe {
814
    /// Creates a new Path without checking for null bytes.
815
    /// The resulting Path will always be normalized.
816
    unsafe fn new_unchecked<T: BytesContainer>(path: T) -> Self;
817

818 819
    /// Replaces the filename portion of the path without checking for null
    /// bytes.
820
    /// See `set_filename` for details.
821
    unsafe fn set_filename_unchecked<T: BytesContainer>(&mut self, filename: T);
K
Kevin Ballard 已提交
822

823
    /// Pushes a path onto `self` without checking for null bytes.
824
    /// See `push` for details.
825
    unsafe fn push_unchecked<T: BytesContainer>(&mut self, path: T);
826 827
}

828
/// Helper struct for printing paths with format!()
E
Erik Price 已提交
829
pub struct Display<'a, P> {
830 831
    path: &'a P,
    filename: bool
832 833
}

834
impl<'a, P: GenericPath> fmt::Show for Display<'a, P> {
835
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
836
        self.as_maybe_owned().as_slice().fmt(f)
837 838 839
    }
}

E
Erik Price 已提交
840
impl<'a, P: GenericPath> Display<'a, P> {
841
    /// Returns the path as a possibly-owned string.
842 843 844 845
    ///
    /// If the path is not UTF-8, invalid sequences will be replaced with the
    /// unicode replacement char. This involves allocation.
    #[inline]
846
    pub fn as_maybe_owned(&self) -> MaybeOwned<'a> {
847
        String::from_utf8_lossy(if self.filename {
848 849 850
            match self.path.filename() {
                None => &[],
                Some(v) => v
851
            }
852 853 854
        } else {
            self.path.as_vec()
        })
855 856 857
    }
}

E
Erik Price 已提交
858
impl<'a> BytesContainer for &'a str {
859 860 861 862 863
    #[inline]
    fn container_as_bytes<'a>(&'a self) -> &'a [u8] {
        self.as_bytes()
    }
    #[inline]
864
    fn container_as_str<'a>(&'a self) -> Option<&'a str> {
865 866 867
        Some(*self)
    }
    #[inline]
E
Erik Price 已提交
868
    fn is_str(_: Option<&'a str>) -> bool { true }
869 870
}

871
impl BytesContainer for String {
872 873 874 875 876 877 878 879 880
    #[inline]
    fn container_as_bytes<'a>(&'a self) -> &'a [u8] {
        self.as_bytes()
    }
    #[inline]
    fn container_as_str<'a>(&'a self) -> Option<&'a str> {
        Some(self.as_slice())
    }
    #[inline]
881
    fn is_str(_: Option<String>) -> bool { true }
882
}
883

E
Erik Price 已提交
884
impl<'a> BytesContainer for &'a [u8] {
885 886 887 888 889 890
    #[inline]
    fn container_as_bytes<'a>(&'a self) -> &'a [u8] {
        *self
    }
}

891 892 893 894 895
impl BytesContainer for Vec<u8> {
    #[inline]
    fn container_as_bytes<'a>(&'a self) -> &'a [u8] {
        self.as_slice()
    }
896
    #[inline]
897
    fn container_into_owned_bytes(self) -> Vec<u8> {
898 899 900 901
        self
    }
}

902 903 904
impl BytesContainer for CString {
    #[inline]
    fn container_as_bytes<'a>(&'a self) -> &'a [u8] {
905
        self.as_bytes_no_nul()
906 907 908
    }
}

909 910 911 912 913 914 915 916 917 918 919 920 921
impl<'a> BytesContainer for str::MaybeOwned<'a> {
    #[inline]
    fn container_as_bytes<'b>(&'b self) -> &'b [u8] {
        self.as_slice().as_bytes()
    }
    #[inline]
    fn container_as_str<'b>(&'b self) -> Option<&'b str> {
        Some(self.as_slice())
    }
    #[inline]
    fn is_str(_: Option<str::MaybeOwned>) -> bool { true }
}

922
#[inline(always)]
923 924
fn contains_nul<T: BytesContainer>(v: &T) -> bool {
    v.container_as_bytes().iter().any(|&x| x == 0)
925
}
K
Kevin Ballard 已提交
926

927 928
#[cfg(test)]
mod tests {
929
    use prelude::*;
930 931 932 933
    use super::{GenericPath, PosixPath, WindowsPath};
    use c_str::ToCStr;

    #[test]
934
    fn test_cstring() {
935
        let input = "/foo/bar/baz";
936
        let path: PosixPath = PosixPath::new(input.to_c_str());
937 938
        assert_eq!(path.as_vec(), input.as_bytes());

939
        let input = r"\foo\bar\baz";
940
        let path: WindowsPath = WindowsPath::new(input.to_c_str());
941
        assert_eq!(path.as_str().unwrap(), input.as_slice());
942 943
    }
}