diff options
| author | Fenrir <[email protected]> | 2018-01-21 14:06:28 -0700 |
|---|---|---|
| committer | FenrirWolf <[email protected]> | 2018-01-21 19:16:33 -0700 |
| commit | 23be3f4885688e5e0011005e2295c75168854c0a (patch) | |
| tree | dd0850f9c73c489e114a761d5c0757f3dbec3a65 /ctr-std/src/path.rs | |
| parent | Update CI for Rust nightly-2017-12-01 + other fixes (diff) | |
| download | ctru-rs-23be3f4885688e5e0011005e2295c75168854c0a.tar.xz ctru-rs-23be3f4885688e5e0011005e2295c75168854c0a.zip | |
Recreate ctr-std from latest nightly
Diffstat (limited to 'ctr-std/src/path.rs')
| -rw-r--r-- | ctr-std/src/path.rs | 785 |
1 files changed, 616 insertions, 169 deletions
diff --git a/ctr-std/src/path.rs b/ctr-std/src/path.rs index 2435efd..7631a9a 100644 --- a/ctr-std/src/path.rs +++ b/ctr-std/src/path.rs @@ -10,20 +10,27 @@ //! Cross-platform path manipulation. //! -//! This module provides two types, `PathBuf` and `Path` (akin to `String` and -//! `str`), for working with paths abstractly. These types are thin wrappers -//! around `OsString` and `OsStr` respectively, meaning that they work directly +//! This module provides two types, [`PathBuf`] and [`Path`][`Path`] (akin to [`String`] +//! and [`str`]), for working with paths abstractly. These types are thin wrappers +//! around [`OsString`] and [`OsStr`] respectively, meaning that they work directly //! on strings according to the local platform's path syntax. //! +//! Paths can be parsed into [`Component`]s by iterating over the structure +//! returned by the [`components`] method on [`Path`]. [`Component`]s roughly +//! correspond to the substrings between path separators (`/` or `\`). You can +//! reconstruct an equivalent path from components with the [`push`] method on +//! [`PathBuf`]; note that the paths may differ syntactically by the +//! normalization described in the documentation for the [`components`] method. +//! //! ## Simple usage //! //! Path manipulation includes both parsing components from slices and building //! new owned paths. //! -//! To parse a path, you can create a `Path` slice from a `str` +//! To parse a path, you can create a [`Path`] slice from a [`str`] //! slice and start asking questions: //! -//! ```rust +//! ``` //! use std::path::Path; //! use std::ffi::OsStr; //! @@ -39,70 +46,34 @@ //! assert_eq!(extension, Some(OsStr::new("txt"))); //! ``` //! -//! To build or modify paths, use `PathBuf`: +//! To build or modify paths, use [`PathBuf`]: //! -//! ```rust +//! ``` //! use std::path::PathBuf; //! +//! // This way works... //! let mut path = PathBuf::from("c:\\"); +//! //! path.push("windows"); //! path.push("system32"); -//! path.set_extension("dll"); -//! ``` -//! -//! ## Path components and normalization -//! -//! The path APIs are built around the notion of "components", which roughly -//! correspond to the substrings between path separators (`/` and, on Windows, -//! `\`). The APIs for path parsing are largely specified in terms of the path's -//! components, so it's important to clearly understand how those are -//! determined. -//! -//! A path can always be reconstructed into an *equivalent* path by -//! putting together its components via `push`. Syntactically, the -//! paths may differ by the normalization described below. -//! -//! ### Component types -//! -//! Components come in several types: -//! -//! * Normal components are the default: standard references to files or -//! directories. The path `a/b` has two normal components, `a` and `b`. -//! -//! * Current directory components represent the `.` character. For example, -//! `./a` has a current directory component and a normal component `a`. -//! -//! * The root directory component represents a separator that designates -//! starting from root. For example, `/a/b` has a root directory component -//! followed by normal components `a` and `b`. -//! -//! On Windows, an additional component type comes into play: -//! -//! * Prefix components, of which there is a large variety. For example, `C:` -//! and `\\server\share` are prefixes. The path `C:windows` has a prefix -//! component `C:` and a normal component `windows`; the path `C:\windows` has a -//! prefix component `C:`, a root directory component, and a normal component -//! `windows`. //! -//! ### Normalization -//! -//! Aside from splitting on the separator(s), there is a small amount of -//! "normalization": +//! path.set_extension("dll"); //! -//! * Repeated separators are ignored: `a/b` and `a//b` both have components `a` -//! and `b`. +//! // ... but push is best used if you don't know everything up +//! // front. If you do, this way is better: +//! let path: PathBuf = ["c:\\", "windows", "system32.dll"].iter().collect(); +//! ``` //! -//! * Occurrences of `.` are normalized away, *except* if they are at -//! the beginning of the path (in which case they are often meaningful -//! in terms of path searching). So, for example, `a/./b`, `a/b/`, -//! `/a/b/.` and `a/b` all have components `a` and `b`, but `./a/b` -//! has a leading current directory component. +//! [`Component`]: ../../std/path/enum.Component.html +//! [`components`]: ../../std/path/struct.Path.html#method.components +//! [`PathBuf`]: ../../std/path/struct.PathBuf.html +//! [`Path`]: ../../std/path/struct.Path.html +//! [`push`]: ../../std/path/struct.PathBuf.html#method.push +//! [`String`]: ../../std/string/struct.String.html //! -//! No other normalization takes place by default. In particular, -//! `a/c` and `a/b/../c` are distinct, to account for the possibility -//! that `b` is a symbolic link (so its parent isn't `a`). Further -//! normalization is possible to build on top of the components APIs, -//! and will be included in this library in the near future. +//! [`str`]: ../../std/primitive.str.html +//! [`OsString`]: ../../std/ffi/struct.OsString.html +//! [`OsStr`]: ../../std/ffi/struct.OsStr.html #![stable(feature = "rust1", since = "1.0.0")] @@ -114,8 +85,9 @@ use fs; use hash::{Hash, Hasher}; use io; use iter::{self, FusedIterator}; -use mem; use ops::{self, Deref}; +use rc::Rc; +use sync::Arc; use ffi::{OsStr, OsString}; @@ -135,36 +107,81 @@ use sys::path::{is_sep_byte, is_verbatim_sep, MAIN_SEP_STR, parse_prefix}; // Windows Prefixes //////////////////////////////////////////////////////////////////////////////// -/// Path prefixes (Windows only). +/// Windows path prefixes, e.g. `C:` or `\\server\share`. +/// +/// Windows uses a variety of path prefix styles, including references to drive +/// volumes (like `C:`), network shared folders (like `\\server\share`), and +/// others. In addition, some path prefixes are "verbatim" (i.e. prefixed with +/// `\\?\`), in which case `/` is *not* treated as a separator and essentially +/// no normalization is performed. /// -/// Windows uses a variety of path styles, including references to drive -/// volumes (like `C:`), network shared folders (like `\\server\share`) and -/// others. In addition, some path prefixes are "verbatim", in which case -/// `/` is *not* treated as a separator and essentially no normalization is -/// performed. +/// # Examples +/// +/// ``` +/// use std::path::{Component, Path, Prefix}; +/// use std::path::Prefix::*; +/// use std::ffi::OsStr; +/// +/// fn get_path_prefix(s: &str) -> Prefix { +/// let path = Path::new(s); +/// match path.components().next().unwrap() { +/// Component::Prefix(prefix_component) => prefix_component.kind(), +/// _ => panic!(), +/// } +/// } +/// +/// # if cfg!(windows) { +/// assert_eq!(Verbatim(OsStr::new("pictures")), +/// get_path_prefix(r"\\?\pictures\kittens")); +/// assert_eq!(VerbatimUNC(OsStr::new("server"), OsStr::new("share")), +/// get_path_prefix(r"\\?\UNC\server\share")); +/// assert_eq!(VerbatimDisk(b'C'), get_path_prefix(r"\\?\c:\")); +/// assert_eq!(DeviceNS(OsStr::new("BrainInterface")), +/// get_path_prefix(r"\\.\BrainInterface")); +/// assert_eq!(UNC(OsStr::new("server"), OsStr::new("share")), +/// get_path_prefix(r"\\server\share")); +/// assert_eq!(Disk(b'C'), get_path_prefix(r"C:\Users\Rust\Pictures\Ferris")); +/// # } +/// ``` #[derive(Copy, Clone, Debug, Hash, PartialOrd, Ord, PartialEq, Eq)] #[stable(feature = "rust1", since = "1.0.0")] pub enum Prefix<'a> { - /// Prefix `\\?\`, together with the given component immediately following it. + /// Verbatim prefix, e.g. `\\?\cat_pics`. + /// + /// Verbatim prefixes consist of `\\?\` immediately followed by the given + /// component. #[stable(feature = "rust1", since = "1.0.0")] Verbatim(#[stable(feature = "rust1", since = "1.0.0")] &'a OsStr), - /// Prefix `\\?\UNC\`, with the "server" and "share" components following it. + /// Verbatim prefix using Windows' _**U**niform **N**aming **C**onvention_, + /// e.g. `\\?\UNC\server\share`. + /// + /// Verbatim UNC prefixes consist of `\\?\UNC\` immediately followed by the + /// server's hostname and a share name. #[stable(feature = "rust1", since = "1.0.0")] VerbatimUNC( #[stable(feature = "rust1", since = "1.0.0")] &'a OsStr, #[stable(feature = "rust1", since = "1.0.0")] &'a OsStr, ), - /// Prefix like `\\?\C:\`, for the given drive letter + /// Verbatim disk prefix, e.g. `\\?\C:\`. + /// + /// Verbatim disk prefixes consist of `\\?\` immediately followed by the + /// drive letter and `:\`. #[stable(feature = "rust1", since = "1.0.0")] VerbatimDisk(#[stable(feature = "rust1", since = "1.0.0")] u8), - /// Prefix `\\.\`, together with the given component immediately following it. + /// Device namespace prefix, e.g. `\\.\COM42`. + /// + /// Device namespace prefixes consist of `\\.\` immediately followed by the + /// device name. #[stable(feature = "rust1", since = "1.0.0")] DeviceNS(#[stable(feature = "rust1", since = "1.0.0")] &'a OsStr), - /// Prefix `\\server\share`, with the given "server" and "share" components. + /// Prefix using Windows' _**U**niform **N**aming **C**onvention_, e.g. + /// `\\server\share`. + /// + /// UNC prefixes consist of the server's hostname and a share name. #[stable(feature = "rust1", since = "1.0.0")] UNC( #[stable(feature = "rust1", since = "1.0.0")] &'a OsStr, @@ -209,6 +226,20 @@ impl<'a> Prefix<'a> { } /// Determines if the prefix is verbatim, i.e. begins with `\\?\`. + /// + /// # Examples + /// + /// ``` + /// use std::path::Prefix::*; + /// use std::ffi::OsStr; + /// + /// assert!(Verbatim(OsStr::new("pictures")).is_verbatim()); + /// assert!(VerbatimUNC(OsStr::new("server"), OsStr::new("share")).is_verbatim()); + /// assert!(VerbatimDisk(b'C').is_verbatim()); + /// assert!(!DeviceNS(OsStr::new("BrainInterface")).is_verbatim()); + /// assert!(!UNC(OsStr::new("server"), OsStr::new("share")).is_verbatim()); + /// assert!(!Disk(b'C').is_verbatim()); + /// ``` #[inline] #[stable(feature = "rust1", since = "1.0.0")] pub fn is_verbatim(&self) -> bool { @@ -245,7 +276,7 @@ impl<'a> Prefix<'a> { /// ``` /// use std::path; /// -/// assert!(path::is_separator('/')); +/// assert!(path::is_separator('/')); // '/' works for both Unix and Windows /// assert!(!path::is_separator('❤')); /// ``` #[stable(feature = "rust1", since = "1.0.0")] @@ -286,10 +317,15 @@ fn iter_after<A, I, J>(mut iter: I, mut prefix: J) -> Option<I> // See note at the top of this module to understand why these are used: fn os_str_as_u8_slice(s: &OsStr) -> &[u8] { - unsafe { mem::transmute(s) } + unsafe { &*(s as *const OsStr as *const [u8]) } } unsafe fn u8_slice_as_os_str(s: &[u8]) -> &OsStr { - mem::transmute(s) + &*(s as *const [u8] as *const OsStr) +} + +// Detect scheme on Redox +fn has_redox_scheme(s: &[u8]) -> bool { + cfg!(target_os = "redox") && s.split(|b| *b == b'/').next().unwrap_or(b"").contains(&b':') } //////////////////////////////////////////////////////////////////////////////// @@ -348,9 +384,42 @@ enum State { Done = 3, } -/// A Windows path prefix, e.g. `C:` or `\\server\share`. +/// A structure wrapping a Windows path prefix as well as its unparsed string +/// representation. +/// +/// In addition to the parsed [`Prefix`] information returned by [`kind`], +/// `PrefixComponent` also holds the raw and unparsed [`OsStr`] slice, +/// returned by [`as_os_str`]. +/// +/// Instances of this `struct` can be obtained by matching against the +/// [`Prefix` variant] on [`Component`]. /// /// Does not occur on Unix. +/// +/// # Examples +/// +/// ``` +/// # if cfg!(windows) { +/// use std::path::{Component, Path, Prefix}; +/// use std::ffi::OsStr; +/// +/// let path = Path::new(r"c:\you\later\"); +/// match path.components().next().unwrap() { +/// Component::Prefix(prefix_component) => { +/// assert_eq!(Prefix::Disk(b'C'), prefix_component.kind()); +/// assert_eq!(OsStr::new("c:"), prefix_component.as_os_str()); +/// } +/// _ => unreachable!(), +/// } +/// # } +/// ``` +/// +/// [`as_os_str`]: #method.as_os_str +/// [`Component`]: enum.Component.html +/// [`kind`]: #method.kind +/// [`OsStr`]: ../../std/ffi/struct.OsStr.html +/// [`Prefix` variant]: enum.Component.html#variant.Prefix +/// [`Prefix`]: enum.Prefix.html #[stable(feature = "rust1", since = "1.0.0")] #[derive(Copy, Clone, Eq, Debug)] pub struct PrefixComponent<'a> { @@ -362,13 +431,20 @@ pub struct PrefixComponent<'a> { } impl<'a> PrefixComponent<'a> { - /// The parsed prefix data. + /// Returns the parsed prefix data. + /// + /// See [`Prefix`]'s documentation for more information on the different + /// kinds of prefixes. + /// + /// [`Prefix`]: enum.Prefix.html #[stable(feature = "rust1", since = "1.0.0")] pub fn kind(&self) -> Prefix<'a> { self.parsed } - /// The raw `OsStr` slice for this prefix. + /// Returns the raw [`OsStr`] slice for this prefix. + /// + /// [`OsStr`]: ../../std/ffi/struct.OsStr.html #[stable(feature = "rust1", since = "1.0.0")] pub fn as_os_str(&self) -> &'a OsStr { self.raw @@ -405,11 +481,11 @@ impl<'a> Hash for PrefixComponent<'a> { /// A single component of a path. /// -/// See the module documentation for an in-depth explanation of components and -/// their role in the API. +/// A `Component` roughly corresponds to a substring between path separators +/// (`/` or `\`). /// -/// This `enum` is created from iterating over the [`path::Components`] -/// `struct`. +/// This `enum` is created by iterating over [`Components`], which in turn is +/// created by the [`components`][`Path::components`] method on [`Path`]. /// /// # Examples /// @@ -426,37 +502,49 @@ impl<'a> Hash for PrefixComponent<'a> { /// ]); /// ``` /// -/// [`path::Components`]: struct.Components.html +/// [`Components`]: struct.Components.html +/// [`Path`]: struct.Path.html +/// [`Path::components`]: struct.Path.html#method.components #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)] #[stable(feature = "rust1", since = "1.0.0")] pub enum Component<'a> { /// A Windows path prefix, e.g. `C:` or `\\server\share`. /// + /// There is a large variety of prefix types, see [`Prefix`]'s documentation + /// for more. + /// /// Does not occur on Unix. + /// + /// [`Prefix`]: enum.Prefix.html #[stable(feature = "rust1", since = "1.0.0")] Prefix( #[stable(feature = "rust1", since = "1.0.0")] PrefixComponent<'a> ), - /// The root directory component, appears after any prefix and before anything else + /// The root directory component, appears after any prefix and before anything else. + /// + /// It represents a separator that designates that a path starts from root. #[stable(feature = "rust1", since = "1.0.0")] RootDir, - /// A reference to the current directory, i.e. `.` + /// A reference to the current directory, i.e. `.`. #[stable(feature = "rust1", since = "1.0.0")] CurDir, - /// A reference to the parent directory, i.e. `..` + /// A reference to the parent directory, i.e. `..`. #[stable(feature = "rust1", since = "1.0.0")] ParentDir, - /// A normal component, i.e. `a` and `b` in `a/b` + /// A normal component, e.g. `a` and `b` in `a/b`. + /// + /// This variant is the most common one, it represents references to files + /// or directories. #[stable(feature = "rust1", since = "1.0.0")] Normal(#[stable(feature = "rust1", since = "1.0.0")] &'a OsStr), } impl<'a> Component<'a> { - /// Extracts the underlying `OsStr` slice. + /// Extracts the underlying [`OsStr`] slice. /// /// # Examples /// @@ -467,6 +555,8 @@ impl<'a> Component<'a> { /// let components: Vec<_> = path.components().map(|comp| comp.as_os_str()).collect(); /// assert_eq!(&components, &[".", "tmp", "foo", "bar.txt"]); /// ``` + /// + /// [`OsStr`]: ../../std/ffi/struct.OsStr.html #[stable(feature = "rust1", since = "1.0.0")] pub fn as_os_str(self) -> &'a OsStr { match self { @@ -486,12 +576,17 @@ impl<'a> AsRef<OsStr> for Component<'a> { } } -/// The core iterator giving the components of a path. -/// -/// See the module documentation for an in-depth explanation of components and -/// their role in the API. +#[stable(feature = "path_component_asref", since = "1.24.0")] +impl<'a> AsRef<Path> for Component<'a> { + fn as_ref(&self) -> &Path { + self.as_os_str().as_ref() + } +} + +/// An iterator over the [`Component`]s of a [`Path`]. /// -/// This `struct` is created by the [`path::Path::components`] method. +/// This `struct` is created by the [`components`] method on [`Path`]. +/// See its documentation for more. /// /// # Examples /// @@ -505,7 +600,9 @@ impl<'a> AsRef<OsStr> for Component<'a> { /// } /// ``` /// -/// [`path::Path::components`]: struct.Path.html#method.components +/// [`Component`]: enum.Component.html +/// [`components`]: struct.Path.html#method.components +/// [`Path`]: struct.Path.html #[derive(Clone)] #[stable(feature = "rust1", since = "1.0.0")] pub struct Components<'a> { @@ -526,7 +623,15 @@ pub struct Components<'a> { back: State, } -/// An iterator over the components of a path, as `OsStr` slices. +/// An iterator over the [`Component`]s of a [`Path`], as [`OsStr`] slices. +/// +/// This `struct` is created by the [`iter`] method on [`Path`]. +/// See its documentation for more. +/// +/// [`Component`]: enum.Component.html +/// [`iter`]: struct.Path.html#method.iter +/// [`OsStr`]: ../../std/ffi/struct.OsStr.html +/// [`Path`]: struct.Path.html #[derive(Clone)] #[stable(feature = "rust1", since = "1.0.0")] pub struct Iter<'a> { @@ -752,6 +857,18 @@ impl<'a> fmt::Debug for Iter<'a> { impl<'a> Iter<'a> { /// Extracts a slice corresponding to the portion of the path remaining for iteration. + /// + /// # Examples + /// + /// ``` + /// use std::path::Path; + /// + /// let mut iter = Path::new("/tmp/foo/bar.txt").iter(); + /// iter.next(); + /// iter.next(); + /// + /// assert_eq!(Path::new("foo/bar.txt"), iter.as_path()); + /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn as_path(&self) -> &'a Path { self.inner.as_path() @@ -935,18 +1052,44 @@ impl<'a> cmp::Ord for Components<'a> { /// [`Deref`]: ../ops/trait.Deref.html /// /// More details about the overall approach can be found in -/// the module documentation. +/// the [module documentation](index.html). /// /// # Examples /// +/// You can use [`push`] to build up a `PathBuf` from +/// components: +/// /// ``` /// use std::path::PathBuf; /// -/// let mut path = PathBuf::from("c:\\"); +/// let mut path = PathBuf::new(); +/// +/// path.push(r"C:\"); /// path.push("windows"); /// path.push("system32"); +/// /// path.set_extension("dll"); /// ``` +/// +/// However, [`push`] is best used for dynamic situations. This is a better way +/// to do this when you know all of the components ahead of time: +/// +/// ``` +/// use std::path::PathBuf; +/// +/// let path: PathBuf = [r"C:\", "windows", "system32.dll"].iter().collect(); +/// ``` +/// +/// We can still do better than this! Since these are all strings, we can use +/// `From::from`: +/// +/// ``` +/// use std::path::PathBuf; +/// +/// let path = PathBuf::from(r"C:\windows\system32.dll"); +/// ``` +/// +/// Which method works best depends on what kind of situation you're in. #[derive(Clone)] #[stable(feature = "rust1", since = "1.0.0")] pub struct PathBuf { @@ -1055,13 +1198,14 @@ impl PathBuf { self.inner.push(path); } - /// Truncate `self` to [`self.parent()`]. + /// Truncates `self` to [`self.parent`]. /// - /// Returns false and does nothing if [`self.file_name()`] is `None`. + /// Returns `false` and does nothing if [`self.file_name`] is [`None`]. /// Otherwise, returns `true`. /// - /// [`self.parent()`]: struct.PathBuf.html#method.parent - /// [`self.file_name()`]: struct.PathBuf.html#method.file_name + /// [`None`]: ../../std/option/enum.Option.html#variant.None + /// [`self.parent`]: struct.PathBuf.html#method.parent + /// [`self.file_name`]: struct.PathBuf.html#method.file_name /// /// # Examples /// @@ -1086,12 +1230,18 @@ impl PathBuf { } } - /// Updates [`self.file_name()`] to `file_name`. + /// Updates [`self.file_name`] to `file_name`. /// - /// If [`self.file_name()`] was `None`, this is equivalent to pushing + /// If [`self.file_name`] was [`None`], this is equivalent to pushing /// `file_name`. /// - /// [`self.file_name()`]: struct.PathBuf.html#method.file_name + /// Otherwise it is equivalent to calling [`pop`] and then pushing + /// `file_name`. The new path will be a sibling of the original path. + /// (That is, it will have the same parent.) + /// + /// [`self.file_name`]: struct.PathBuf.html#method.file_name + /// [`None`]: ../../std/option/enum.Option.html#variant.None + /// [`pop`]: struct.PathBuf.html#method.pop /// /// # Examples /// @@ -1119,15 +1269,17 @@ impl PathBuf { self.push(file_name); } - /// Updates [`self.extension()`] to `extension`. + /// Updates [`self.extension`] to `extension`. /// - /// If [`self.file_name()`] is `None`, does nothing and returns `false`. + /// Returns `false` and does nothing if [`self.file_name`] is [`None`], + /// returns `true` and updates the extension otherwise. /// - /// Otherwise, returns `true`; if [`self.extension()`] is `None`, the - /// extension is added; otherwise it is replaced. + /// If [`self.extension`] is [`None`], the extension is added; otherwise + /// it is replaced. /// - /// [`self.file_name()`]: struct.PathBuf.html#method.file_name - /// [`self.extension()`]: struct.PathBuf.html#method.extension + /// [`self.file_name`]: struct.PathBuf.html#method.file_name + /// [`self.extension`]: struct.PathBuf.html#method.extension + /// [`None`]: ../../std/option/enum.Option.html#variant.None /// /// # Examples /// @@ -1182,6 +1334,39 @@ impl PathBuf { pub fn into_os_string(self) -> OsString { self.inner } + + /// Converts this `PathBuf` into a [boxed][`Box`] [`Path`]. + /// + /// [`Box`]: ../../std/boxed/struct.Box.html + /// [`Path`]: struct.Path.html + #[stable(feature = "into_boxed_path", since = "1.20.0")] + pub fn into_boxed_path(self) -> Box<Path> { + let rw = Box::into_raw(self.inner.into_boxed_os_str()) as *mut Path; + unsafe { Box::from_raw(rw) } + } +} + +#[stable(feature = "box_from_path", since = "1.17.0")] +impl<'a> From<&'a Path> for Box<Path> { + fn from(path: &'a Path) -> Box<Path> { + let boxed: Box<OsStr> = path.inner.into(); + let rw = Box::into_raw(boxed) as *mut Path; + unsafe { Box::from_raw(rw) } + } +} + +#[stable(feature = "path_buf_from_box", since = "1.18.0")] +impl From<Box<Path>> for PathBuf { + fn from(boxed: Box<Path>) -> PathBuf { + boxed.into_path_buf() + } +} + +#[stable(feature = "box_from_path_buf", since = "1.20.0")] +impl From<PathBuf> for Box<Path> { + fn from(p: PathBuf) -> Box<Path> { + p.into_boxed_path() + } } #[stable(feature = "rust1", since = "1.0.0")] @@ -1253,6 +1438,13 @@ impl Borrow<Path> for PathBuf { } } +#[stable(feature = "default_for_pathbuf", since = "1.17.0")] +impl Default for PathBuf { + fn default() -> Self { + PathBuf::new() + } +} + #[stable(feature = "cow_from_path", since = "1.6.0")] impl<'a> From<&'a Path> for Cow<'a, Path> { #[inline] @@ -1269,12 +1461,51 @@ impl<'a> From<PathBuf> for Cow<'a, Path> { } } +#[stable(feature = "shared_from_slice2", since = "1.24.0")] +impl From<PathBuf> for Arc<Path> { + #[inline] + fn from(s: PathBuf) -> Arc<Path> { + let arc: Arc<OsStr> = Arc::from(s.into_os_string()); + unsafe { Arc::from_raw(Arc::into_raw(arc) as *const Path) } + } +} + +#[stable(feature = "shared_from_slice2", since = "1.24.0")] +impl<'a> From<&'a Path> for Arc<Path> { + #[inline] + fn from(s: &Path) -> Arc<Path> { + let arc: Arc<OsStr> = Arc::from(s.as_os_str()); + unsafe { Arc::from_raw(Arc::into_raw(arc) as *const Path) } + } +} + +#[stable(feature = "shared_from_slice2", since = "1.24.0")] +impl From<PathBuf> for Rc<Path> { + #[inline] + fn from(s: PathBuf) -> Rc<Path> { + let rc: Rc<OsStr> = Rc::from(s.into_os_string()); + unsafe { Rc::from_raw(Rc::into_raw(rc) as *const Path) } + } +} + +#[stable(feature = "shared_from_slice2", since = "1.24.0")] +impl<'a> From<&'a Path> for Rc<Path> { + #[inline] + fn from(s: &Path) -> Rc<Path> { + let rc: Rc<OsStr> = Rc::from(s.as_os_str()); + unsafe { Rc::from_raw(Rc::into_raw(rc) as *const Path) } + } +} + #[stable(feature = "rust1", since = "1.0.0")] impl ToOwned for Path { type Owned = PathBuf; fn to_owned(&self) -> PathBuf { self.to_path_buf() } + fn clone_into(&self, target: &mut PathBuf) { + self.inner.clone_into(&mut target.inner); + } } #[stable(feature = "rust1", since = "1.0.0")] @@ -1318,9 +1549,9 @@ impl AsRef<OsStr> for PathBuf { /// A slice of a path (akin to [`str`]). /// /// This type supports a number of operations for inspecting a path, including -/// breaking the path into its components (separated by `/` or `\`, depending on -/// the platform), extracting the file name, determining whether the path is -/// absolute, and so on. +/// breaking the path into its components (separated by `/` on Unix and by either +/// `/` or `\` on Windows), extracting the file name, determining whether the path +/// is absolute, and so on. /// /// This is an *unsized* type, meaning that it must always be used behind a /// pointer like `&` or [`Box`]. For an owned version of this type, @@ -1331,7 +1562,7 @@ impl AsRef<OsStr> for PathBuf { /// [`PathBuf`]: struct.PathBuf.html /// /// More details about the overall approach can be found in -/// the module documentation. +/// the [module documentation](index.html). /// /// # Examples /// @@ -1339,10 +1570,11 @@ impl AsRef<OsStr> for PathBuf { /// use std::path::Path; /// use std::ffi::OsStr; /// -/// let path = Path::new("/tmp/foo/bar.txt"); +/// // Note: this example does work on Windows +/// let path = Path::new("./foo/bar.txt"); /// /// let parent = path.parent(); -/// assert_eq!(parent, Some(Path::new("/tmp/foo"))); +/// assert_eq!(parent, Some(Path::new("./foo"))); /// /// let file_stem = path.file_stem(); /// assert_eq!(file_stem, Some(OsStr::new("bar"))); @@ -1355,8 +1587,14 @@ pub struct Path { inner: OsStr, } -/// An error returned from the `Path::strip_prefix` method indicating that the -/// prefix was not found in `self`. +/// An error returned from [`Path::strip_prefix`][`strip_prefix`] if the prefix +/// was not found. +/// +/// This `struct` is created by the [`strip_prefix`] method on [`Path`]. +/// See its documentation for more. +/// +/// [`strip_prefix`]: struct.Path.html#method.strip_prefix +/// [`Path`]: struct.Path.html #[derive(Debug, Clone, PartialEq, Eq)] #[stable(since = "1.7.0", feature = "strip_prefix")] pub struct StripPrefixError(()); @@ -1372,7 +1610,7 @@ impl Path { os_str_as_u8_slice(&self.inner) } - /// Directly wrap a string slice as a `Path` slice. + /// Directly wraps a string slice as a `Path` slice. /// /// This is a cost-free conversion. /// @@ -1396,7 +1634,7 @@ impl Path { /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn new<S: AsRef<OsStr> + ?Sized>(s: &S) -> &Path { - unsafe { mem::transmute(s.as_ref()) } + unsafe { &*(s.as_ref() as *const OsStr as *const Path) } } /// Yields the underlying [`OsStr`] slice. @@ -1427,8 +1665,8 @@ impl Path { /// ``` /// use std::path::Path; /// - /// let path_str = Path::new("foo.txt").to_str(); - /// assert_eq!(path_str, Some("foo.txt")); + /// let path = Path::new("foo.txt"); + /// assert_eq!(path.to_str(), Some("foo.txt")); /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn to_str(&self) -> Option<&str> { @@ -1443,12 +1681,17 @@ impl Path { /// /// # Examples /// + /// Calling `to_string_lossy` on a `Path` with valid unicode: + /// /// ``` /// use std::path::Path; /// - /// let path_str = Path::new("foo.txt").to_string_lossy(); - /// assert_eq!(path_str, "foo.txt"); + /// let path = Path::new("foo.txt"); + /// assert_eq!(path.to_string_lossy(), "foo.txt"); /// ``` + /// + /// Had `path` contained invalid unicode, the `to_string_lossy` call might + /// have returned `"fo�.txt"`. #[stable(feature = "rust1", since = "1.0.0")] pub fn to_string_lossy(&self) -> Cow<str> { self.inner.to_string_lossy() @@ -1466,15 +1709,17 @@ impl Path { /// let path_buf = Path::new("foo.txt").to_path_buf(); /// assert_eq!(path_buf, std::path::PathBuf::from("foo.txt")); /// ``` + #[rustc_conversion_suggestion] #[stable(feature = "rust1", since = "1.0.0")] pub fn to_path_buf(&self) -> PathBuf { PathBuf::from(self.inner.to_os_string()) } - /// A path is *absolute* if it is independent of the current directory. + /// Returns `true` if the `Path` is absolute, i.e. if it is independent of + /// the current directory. /// /// * On Unix, a path is absolute if it starts with the root, so - /// `is_absolute` and `has_root` are equivalent. + /// `is_absolute` and [`has_root`] are equivalent. /// /// * On Windows, a path is absolute if it has a prefix and starts with the /// root: `c:\windows` is absolute, while `c:temp` and `\temp` are not. @@ -1486,13 +1731,22 @@ impl Path { /// /// assert!(!Path::new("foo.txt").is_absolute()); /// ``` + /// + /// [`has_root`]: #method.has_root #[stable(feature = "rust1", since = "1.0.0")] #[allow(deprecated)] pub fn is_absolute(&self) -> bool { - self.has_root() && (cfg!(unix) || self.prefix().is_some()) + if cfg!(target_os = "redox") { + // FIXME: Allow Redox prefixes + self.has_root() || has_redox_scheme(self.as_u8_slice()) + } else { + self.has_root() && (cfg!(unix) || self.prefix().is_some()) + } } - /// A path is *relative* if it is not absolute. + /// Returns `true` if the `Path` is relative, i.e. not absolute. + /// + /// See [`is_absolute`]'s documentation for more details. /// /// # Examples /// @@ -1501,6 +1755,8 @@ impl Path { /// /// assert!(Path::new("foo.txt").is_relative()); /// ``` + /// + /// [`is_absolute`]: #method.is_absolute #[stable(feature = "rust1", since = "1.0.0")] pub fn is_relative(&self) -> bool { !self.is_absolute() @@ -1510,7 +1766,7 @@ impl Path { self.components().prefix } - /// A path has a root if the body of the path begins with the directory separator. + /// Returns `true` if the `Path` has a root. /// /// * On Unix, a path has a root if it begins with `/`. /// @@ -1531,9 +1787,11 @@ impl Path { self.components().has_root() } - /// The path without its final component, if any. + /// Returns the `Path` without its final component, if there is one. + /// + /// Returns [`None`] if the path terminates in a root or prefix. /// - /// Returns `None` if the path terminates in a root or prefix. + /// [`None`]: ../../std/option/enum.Option.html#variant.None /// /// # Examples /// @@ -1562,31 +1820,27 @@ impl Path { }) } - /// The final component of the path, if it is a normal file. + /// Returns the final component of the `Path`, if there is one. /// - /// If the path terminates in `..`, `file_name` will return `None`. + /// If the path is a normal file, this is the file name. If it's the path of a directory, this + /// is the directory name. /// - /// # Examples + /// Returns [`None`] If the path terminates in `..`. /// - /// ``` - /// use std::path::Path; - /// use std::ffi::OsStr; - /// - /// let path = Path::new("foo.txt"); - /// let os_str = OsStr::new("foo.txt"); + /// [`None`]: ../../std/option/enum.Option.html#variant.None /// - /// assert_eq!(Some(os_str), path.file_name()); - /// ``` - /// - /// # Other examples + /// # Examples /// /// ``` /// use std::path::Path; /// use std::ffi::OsStr; /// + /// assert_eq!(Some(OsStr::new("bin")), Path::new("/usr/bin/").file_name()); + /// assert_eq!(Some(OsStr::new("foo.txt")), Path::new("tmp/foo.txt").file_name()); /// assert_eq!(Some(OsStr::new("foo.txt")), Path::new("foo.txt/.").file_name()); /// assert_eq!(Some(OsStr::new("foo.txt")), Path::new("foo.txt/.//").file_name()); /// assert_eq!(None, Path::new("foo.txt/..").file_name()); + /// assert_eq!(None, Path::new("/").file_name()); /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn file_name(&self) -> Option<&OsStr> { @@ -1602,8 +1856,11 @@ impl Path { /// /// # Errors /// - /// If `base` is not a prefix of `self` (i.e. `starts_with` - /// returns `false`), returns `Err`. + /// If `base` is not a prefix of `self` (i.e. [`starts_with`] + /// returns `false`), returns [`Err`]. + /// + /// [`starts_with`]: #method.starts_with + /// [`Err`]: ../../std/result/enum.Result.html#variant.Err /// /// # Examples /// @@ -1677,17 +1934,19 @@ impl Path { iter_after(self.components().rev(), child.components().rev()).is_some() } - /// Extracts the stem (non-extension) portion of [`self.file_name()`]. + /// Extracts the stem (non-extension) portion of [`self.file_name`]. /// - /// [`self.file_name()`]: struct.Path.html#method.file_name + /// [`self.file_name`]: struct.Path.html#method.file_name /// /// The stem is: /// - /// * None, if there is no file name; + /// * [`None`], if there is no file name; /// * The entire file name if there is no embedded `.`; /// * The entire file name if the file name begins with `.` and has no other `.`s within; /// * Otherwise, the portion of the file name before the final `.` /// + /// [`None`]: ../../std/option/enum.Option.html#variant.None + /// /// # Examples /// /// ``` @@ -1702,17 +1961,18 @@ impl Path { self.file_name().map(split_file_at_dot).and_then(|(before, after)| before.or(after)) } - /// Extracts the extension of [`self.file_name()`], if possible. - /// - /// [`self.file_name()`]: struct.Path.html#method.file_name + /// Extracts the extension of [`self.file_name`], if possible. /// /// The extension is: /// - /// * None, if there is no file name; - /// * None, if there is no embedded `.`; - /// * None, if the file name begins with `.` and has no other `.`s within; + /// * [`None`], if there is no file name; + /// * [`None`], if there is no embedded `.`; + /// * [`None`], if the file name begins with `.` and has no other `.`s within; /// * Otherwise, the portion of the file name after the final `.` /// + /// [`self.file_name`]: struct.Path.html#method.file_name + /// [`None`]: ../../std/option/enum.Option.html#variant.None + /// /// # Examples /// /// ``` @@ -1766,6 +2026,9 @@ impl Path { /// /// let path = Path::new("/tmp/foo.txt"); /// assert_eq!(path.with_file_name("bar.txt"), PathBuf::from("/tmp/bar.txt")); + /// + /// let path = Path::new("/tmp"); + /// assert_eq!(path.with_file_name("var"), PathBuf::from("/var")); /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn with_file_name<S: AsRef<OsStr>>(&self, file_name: S) -> PathBuf { @@ -1804,7 +2067,21 @@ impl Path { buf } - /// Produce an iterator over the components of the path. + /// Produces an iterator over the [`Component`]s of the path. + /// + /// When parsing the path, there is a small amount of normalization: + /// + /// * Repeated separators are ignored, so `a/b` and `a//b` both have + /// `a` and `b` as components. + /// + /// * Occurrences of `.` are normalized away, except if they are at the + /// beginning of the path. For example, `a/./b`, `a/b/`, `a/b/.` and + /// `a/b` all have `a` and `b` as components, but `./a/b` starts with + /// an additional [`CurDir`] component. + /// + /// Note that no other normalization takes place; in particular, `a/c` + /// and `a/b/../c` are distinct, to account for the possibility that `b` + /// is a symbolic link (so its parent isn't `a`). /// /// # Examples /// @@ -1819,20 +2096,29 @@ impl Path { /// assert_eq!(components.next(), Some(Component::Normal(OsStr::new("foo.txt")))); /// assert_eq!(components.next(), None) /// ``` + /// + /// [`Component`]: enum.Component.html + /// [`CurDir`]: enum.Component.html#variant.CurDir #[stable(feature = "rust1", since = "1.0.0")] pub fn components(&self) -> Components { let prefix = parse_prefix(self.as_os_str()); Components { path: self.as_u8_slice(), - prefix: prefix, - has_physical_root: has_physical_root(self.as_u8_slice(), prefix), + prefix, + has_physical_root: has_physical_root(self.as_u8_slice(), prefix) || + has_redox_scheme(self.as_u8_slice()), front: State::Prefix, back: State::Body, } } - /// Produce an iterator over the path's components viewed as [`OsStr`] slices. + /// Produces an iterator over the path's components viewed as [`OsStr`] + /// slices. /// + /// For more information about the particulars of how the path is separated + /// into components, see [`components`]. + /// + /// [`components`]: #method.components /// [`OsStr`]: ../ffi/struct.OsStr.html /// /// # Examples @@ -1871,8 +2157,7 @@ impl Path { Display { path: self } } - - /// Query the file system to get information about a file, directory, etc. + /// Queries the file system to get information about a file, directory, etc. /// /// This function will traverse symbolic links to query information about the /// destination file. @@ -1880,16 +2165,36 @@ impl Path { /// This is an alias to [`fs::metadata`]. /// /// [`fs::metadata`]: ../fs/fn.metadata.html + /// + /// # Examples + /// + /// ```no_run + /// use std::path::Path; + /// + /// let path = Path::new("/Minas/tirith"); + /// let metadata = path.metadata().expect("metadata call failed"); + /// println!("{:?}", metadata.file_type()); + /// ``` #[stable(feature = "path_ext", since = "1.5.0")] pub fn metadata(&self) -> io::Result<fs::Metadata> { fs::metadata(self) } - /// Query the metadata about a file without following symlinks. + /// Queries the metadata about a file without following symlinks. /// /// This is an alias to [`fs::symlink_metadata`]. /// /// [`fs::symlink_metadata`]: ../fs/fn.symlink_metadata.html + /// + /// # Examples + /// + /// ```no_run + /// use std::path::Path; + /// + /// let path = Path::new("/Minas/tirith"); + /// let metadata = path.symlink_metadata().expect("symlink_metadata call failed"); + /// println!("{:?}", metadata.file_type()); + /// ``` #[stable(feature = "path_ext", since = "1.5.0")] pub fn symlink_metadata(&self) -> io::Result<fs::Metadata> { fs::symlink_metadata(self) @@ -1901,6 +2206,15 @@ impl Path { /// This is an alias to [`fs::canonicalize`]. /// /// [`fs::canonicalize`]: ../fs/fn.canonicalize.html + /// + /// # Examples + /// + /// ```no_run + /// use std::path::{Path, PathBuf}; + /// + /// let path = Path::new("/foo/test/../test/bar.rs"); + /// assert_eq!(path.canonicalize().unwrap(), PathBuf::from("/foo/test/bar.rs")); + /// ``` #[stable(feature = "path_ext", since = "1.5.0")] pub fn canonicalize(&self) -> io::Result<PathBuf> { fs::canonicalize(self) @@ -1911,6 +2225,15 @@ impl Path { /// This is an alias to [`fs::read_link`]. /// /// [`fs::read_link`]: ../fs/fn.read_link.html + /// + /// # Examples + /// + /// ```no_run + /// use std::path::Path; + /// + /// let path = Path::new("/laputa/sky_castle.rs"); + /// let path_link = path.read_link().expect("read_link call failed"); + /// ``` #[stable(feature = "path_ext", since = "1.5.0")] pub fn read_link(&self) -> io::Result<PathBuf> { fs::read_link(self) @@ -1926,6 +2249,19 @@ impl Path { /// [`io::Result`]: ../io/type.Result.html /// [`DirEntry`]: ../fs/struct.DirEntry.html /// [`fs::read_dir`]: ../fs/fn.read_dir.html + /// + /// # Examples + /// + /// ```no_run + /// use std::path::Path; + /// + /// let path = Path::new("/laputa"); + /// for entry in path.read_dir().expect("read_dir call failed") { + /// if let Ok(entry) = entry { + /// println!("{:?}", entry.path()); + /// } + /// } + /// ``` #[stable(feature = "path_ext", since = "1.5.0")] pub fn read_dir(&self) -> io::Result<fs::ReadDir> { fs::read_dir(self) @@ -1936,22 +2272,35 @@ impl Path { /// This function will traverse symbolic links to query information about the /// destination file. In case of broken symbolic links this will return `false`. /// + /// If you cannot access the directory containing the file, e.g. because of a + /// permission error, this will return `false`. + /// /// # Examples /// /// ```no_run /// use std::path::Path; /// assert_eq!(Path::new("does_not_exist.txt").exists(), false); /// ``` + /// + /// # See Also + /// + /// This is a convenience function that coerces errors to false. If you want to + /// check errors, call [fs::metadata]. + /// + /// [fs::metadata]: ../../std/fs/fn.metadata.html #[stable(feature = "path_ext", since = "1.5.0")] pub fn exists(&self) -> bool { fs::metadata(self).is_ok() } - /// Returns whether the path is pointing at a regular file. + /// Returns whether the path exists on disk and is pointing at a regular file. /// /// This function will traverse symbolic links to query information about the /// destination file. In case of broken symbolic links this will return `false`. /// + /// If you cannot access the directory containing the file, e.g. because of a + /// permission error, this will return `false`. + /// /// # Examples /// /// ```no_run @@ -1959,16 +2308,28 @@ impl Path { /// assert_eq!(Path::new("./is_a_directory/").is_file(), false); /// assert_eq!(Path::new("a_file.txt").is_file(), true); /// ``` + /// + /// # See Also + /// + /// This is a convenience function that coerces errors to false. If you want to + /// check errors, call [fs::metadata] and handle its Result. Then call + /// [fs::Metadata::is_file] if it was Ok. + /// + /// [fs::metadata]: ../../std/fs/fn.metadata.html + /// [fs::Metadata::is_file]: ../../std/fs/struct.Metadata.html#method.is_file #[stable(feature = "path_ext", since = "1.5.0")] pub fn is_file(&self) -> bool { fs::metadata(self).map(|m| m.is_file()).unwrap_or(false) } - /// Returns whether the path is pointing at a directory. + /// Returns whether the path exists on disk and is pointing at a directory. /// /// This function will traverse symbolic links to query information about the /// destination file. In case of broken symbolic links this will return `false`. /// + /// If you cannot access the directory containing the file, e.g. because of a + /// permission error, this will return `false`. + /// /// # Examples /// /// ```no_run @@ -1976,10 +2337,31 @@ impl Path { /// assert_eq!(Path::new("./is_a_directory/").is_dir(), true); /// assert_eq!(Path::new("a_file.txt").is_dir(), false); /// ``` + /// + /// # See Also + /// + /// This is a convenience function that coerces errors to false. If you want to + /// check errors, call [fs::metadata] and handle its Result. Then call + /// [fs::Metadata::is_dir] if it was Ok. + /// + /// [fs::metadata]: ../../std/fs/fn.metadata.html + /// [fs::Metadata::is_dir]: ../../std/fs/struct.Metadata.html#method.is_dir #[stable(feature = "path_ext", since = "1.5.0")] pub fn is_dir(&self) -> bool { fs::metadata(self).map(|m| m.is_dir()).unwrap_or(false) } + + /// Converts a [`Box<Path>`][`Box`] into a [`PathBuf`] without copying or + /// allocating. + /// + /// [`Box`]: ../../std/boxed/struct.Box.html + /// [`PathBuf`]: struct.PathBuf.html + #[stable(feature = "into_boxed_path", since = "1.20.0")] + pub fn into_path_buf(self: Box<Path>) -> PathBuf { + let rw = Box::into_raw(self) as *mut OsStr; + let inner = unsafe { Box::from_raw(rw) }; + PathBuf { inner: OsString::from(inner) } + } } #[stable(feature = "rust1", since = "1.0.0")] @@ -1991,12 +2373,31 @@ impl AsRef<OsStr> for Path { #[stable(feature = "rust1", since = "1.0.0")] impl fmt::Debug for Path { - fn fmt(&self, formatter: &mut fmt::Formatter) -> Result<(), fmt::Error> { - self.inner.fmt(formatter) + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + fmt::Debug::fmt(&self.inner, formatter) } } -/// Helper struct for safely printing paths with `format!()` and `{}` +/// Helper struct for safely printing paths with [`format!`] and `{}`. +/// +/// A [`Path`] might contain non-Unicode data. This `struct` implements the +/// [`Display`] trait in a way that mitigates that. It is created by the +/// [`display`][`Path::display`] method on [`Path`]. +/// +/// # Examples +/// +/// ``` +/// use std::path::Path; +/// +/// let path = Path::new("/tmp/foo.rs"); +/// +/// println!("{}", path.display()); +/// ``` +/// +/// [`Display`]: ../../std/fmt/trait.Display.html +/// [`format!`]: ../../std/macro.format.html +/// [`Path`]: struct.Path.html +/// [`Path::display`]: struct.Path.html#method.display #[stable(feature = "rust1", since = "1.0.0")] pub struct Display<'a> { path: &'a Path, @@ -2005,14 +2406,14 @@ pub struct Display<'a> { #[stable(feature = "rust1", since = "1.0.0")] impl<'a> fmt::Debug for Display<'a> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - fmt::Debug::fmt(&self.path.to_string_lossy(), f) + fmt::Debug::fmt(&self.path, f) } } #[stable(feature = "rust1", since = "1.0.0")] impl<'a> fmt::Display for Display<'a> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - fmt::Display::fmt(&self.path.to_string_lossy(), f) + self.path.inner.display(f) } } @@ -2213,6 +2614,9 @@ impl Error for StripPrefixError { mod tests { use super::*; + use rc::Rc; + use sync::Arc; + macro_rules! t( ($path:expr, iter: $iter:expr) => ( { @@ -3397,7 +3801,7 @@ mod tests { } #[test] - fn test_eq_recievers() { + fn test_eq_receivers() { use borrow::Cow; let borrowed: &Path = Path::new("foo/bar"); @@ -3589,4 +3993,47 @@ mod tests { let actual = format!("{:?}", iter); assert_eq!(expected, actual); } + + #[test] + fn into_boxed() { + let orig: &str = "some/sort/of/path"; + let path = Path::new(orig); + let boxed: Box<Path> = Box::from(path); + let path_buf = path.to_owned().into_boxed_path().into_path_buf(); + assert_eq!(path, &*boxed); + assert_eq!(&*boxed, &*path_buf); + assert_eq!(&*path_buf, path); + } + + #[test] + fn test_clone_into() { + let mut path_buf = PathBuf::from("supercalifragilisticexpialidocious"); + let path = Path::new("short"); + path.clone_into(&mut path_buf); + assert_eq!(path, path_buf); + assert!(path_buf.into_os_string().capacity() >= 15); + } + + #[test] + fn display_format_flags() { + assert_eq!(format!("a{:#<5}b", Path::new("").display()), "a#####b"); + assert_eq!(format!("a{:#<5}b", Path::new("a").display()), "aa####b"); + } + + #[test] + fn into_rc() { + let orig = "hello/world"; + let path = Path::new(orig); + let rc: Rc<Path> = Rc::from(path); + let arc: Arc<Path> = Arc::from(path); + + assert_eq!(&*rc, path); + assert_eq!(&*arc, path); + + let rc2: Rc<Path> = Rc::from(path.to_owned()); + let arc2: Arc<Path> = Arc::from(path.to_owned()); + + assert_eq!(&*rc2, path); + assert_eq!(&*arc2, path); + } } |