//! Unix path manipulation. //! //! This crate provides two types, [`PathBuf`] and [`Path`] (akin to `String` //! and `str`), for working with paths abstractly. These types are thin wrappers //! around `UnixString` and `UnixStr` respectively, meaning that they work //! directly on strings independently from 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 (`/`). 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` //! slice and start asking questions: //! //! ``` //! use unix_path::Path; //! use unix_str::UnixStr; //! //! let path = Path::new("/tmp/foo/bar.txt"); //! //! let parent = path.parent(); //! assert_eq!(parent, Some(Path::new("/tmp/foo"))); //! //! let file_stem = path.file_stem(); //! assert_eq!(file_stem, Some(UnixStr::new("bar"))); //! //! let extension = path.extension(); //! assert_eq!(extension, Some(UnixStr::new("txt"))); //! ``` //! //! To build or modify paths, use [`PathBuf`]: //! //! ``` //! use unix_path::PathBuf; //! //! // This way works... //! let mut path = PathBuf::from("/"); //! //! path.push("feel"); //! path.push("the"); //! //! path.set_extension("force"); //! //! // ... but push is best used if you don't know everything up //! // front. If you do, this way is better: //! let path: PathBuf = ["/", "feel", "the.force"].iter().collect(); //! ``` //! //! [`Component`]: enum.Component.html //! [`components`]:struct.Path.html#method.components //! [`PathBuf`]: struct.PathBuf.html //! [`Path`]: struct.Path.html //! [`push`]: struct.PathBuf.html#method.push
use unix_str::UnixStr; #[cfg(feature = "alloc")] use unix_str::UnixString;
#[cfg(feature = "alloc")] use core::borrow::Borrow; use core::cmp; use core::fmt; use core::hash::{Hash, Hasher}; #[cfg(feature = "alloc")] use core::iter; use core::iter::FusedIterator; #[cfg(feature = "alloc")] use core::ops::{self, Deref};
/// Says whether the first byte after the prefix is a separator. fn has_physical_root(path: &[u8]) -> bool {
!path.is_empty() && path[0] == b'/'
}
// basic workhorse for splitting stem and extension fn split_file_at_dot(file: &UnixStr) -> (Option<&UnixStr>, Option<&UnixStr>) { unsafe { if unix_str_as_u8_slice(file) == b".." { return (Some(file), None);
}
// The unsafety here stems from converting between &OsStr and &[u8] // and back. This is safe to do because (1) we only look at ASCII // contents of the encoding and (2) new &OsStr values are produced // only from ASCII-bounded slices of existing &OsStr values.
letmut iter = unix_str_as_u8_slice(file).rsplitn(2, |b| *b == b'.'); let after = iter.next(); let before = iter.next(); if before == Some(b"") {
(Some(file), None)
} else {
(
before.map(|s| u8_slice_as_unix_str(s)),
after.map(|s| u8_slice_as_unix_str(s)),
)
}
}
}
//////////////////////////////////////////////////////////////////////////////// // The core iterators ////////////////////////////////////////////////////////////////////////////////
/// Component parsing works by a double-ended state machine; the cursors at the /// front and back of the path each keep track of what parts of the path have /// been consumed so far. /// /// Going front to back, a path is made up of a prefix, a starting /// directory component, and a body (of normal components) #[derive(Copy, Clone, PartialEq, PartialOrd, Debug)] enum State {
Prefix = 0,
StartDir = 1, // / or . or nothing
Body = 2, // foo/bar/baz
Done = 3,
}
/// A single component of a path. /// /// A `Component` roughly corresponds to a substring between path separators /// (`/`). /// /// This `enum` is created by iterating over [`Components`], which in turn is /// created by the [`components`][`Path::components`] method on [`Path`]. /// /// # Examples /// /// ```rust /// use unix_path::{Component, Path}; /// /// let path = Path::new("/tmp/foo/bar.txt"); /// let components = path.components().collect::<Vec<_>>(); /// assert_eq!(&components, &[ /// Component::RootDir, /// Component::Normal("tmp".as_ref()), /// Component::Normal("foo".as_ref()), /// Component::Normal("bar.txt".as_ref()), /// ]); /// ``` /// /// [`Components`]: struct.Components.html /// [`Path`]: struct.Path.html /// [`Path::components`]: struct.Path.html#method.components #[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] pubenum Component<'a> { /// The root directory component, appears after any prefix and before anything else. /// /// It represents a separator that designates that a path starts from root.
RootDir,
/// A reference to the current directory, i.e., `.`.
CurDir,
/// A reference to the parent directory, i.e., `..`.
ParentDir,
/// 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.
Normal(&'a UnixStr),
}
/// An iterator over the [`Component`]s of a [`Path`]. /// /// This `struct` is created by the [`components`] method on [`Path`]. /// See its documentation for more. /// /// # Examples /// /// ``` /// use unix_path::Path; /// /// let path = Path::new("/tmp/foo/bar.txt"); /// /// for component in path.components() { /// println!("{:?}", component); /// } /// ``` /// /// [`Component`]: enum.Component.html /// [`components`]: struct.Path.html#method.components /// [`Path`]: struct.Path.html #[derive(Clone)] pubstruct Components<'a> { // The path left to parse components from
path: &'a [u8],
// true if path *physically* has a root separator;.
has_physical_root: bool,
// The iterator is double-ended, and these two states keep track of what has // been produced from either end
front: State,
back: State,
}
/// An iterator over the [`Component`]s of a [`Path`], as `UnixStr` 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 /// [`Path`]: struct.Path.html #[derive(Clone)] pubstruct Iter<'a> {
inner: Components<'a>,
}
/// Extracts a slice corresponding to the portion of the path remaining for iteration. /// /// # Examples /// /// ``` /// use unix_path::Path; /// /// let mut components = Path::new("/tmp/foo/bar.txt").components(); /// components.next(); /// components.next(); /// /// assert_eq!(Path::new("foo/bar.txt"), components.as_path()); /// ``` pubfn as_path(&self) -> &'a Path { letmut comps = self.clone(); if comps.front == State::Body {
comps.trim_left();
} if comps.back == State::Body {
comps.trim_right();
} unsafe { Path::from_u8_slice(comps.path) }
}
/// Is the *original* path rooted? fn has_root(&self) -> bool { self.has_physical_root
}
/// Should the normalized path include a leading . ? fn include_cur_dir(&self) -> bool { ifself.has_root() { returnfalse;
} letmut iter = self.path[..].iter(); match (iter.next(), iter.next()) {
(Some(&b'.'), None) => true,
(Some(&b'.'), Some(&b)) => self.is_sep_byte(b),
_ => false,
}
}
// parse a given byte sequence into the corresponding path component fn parse_single_component<'b>(&self, comp: &'b [u8]) -> Option<Component<'b>> { match comp {
b"." => None, // . components are normalized away, except at // the beginning of a path, which is treated // separately via `include_cur_dir`
b".." => Some(Component::ParentDir),
b"" => None,
_ => Some(Component::Normal(unsafe { u8_slice_as_unix_str(comp) })),
}
}
// parse a component from the left, saying how many bytes to consume to // remove the component fn parse_next_component(&self) -> (usize, Option<Component<'a>>) {
debug_assert!(self.front == State::Body); let (extra, comp) = matchself.path.iter().position(|b| self.is_sep_byte(*b)) {
None => (0, self.path),
Some(i) => (1, &self.path[..i]),
};
(comp.len() + extra, self.parse_single_component(comp))
}
// parse a component from the right, saying how many bytes to consume to // remove the component fn parse_next_component_back(&self) -> (usize, Option<Component<'a>>) {
debug_assert!(self.back == State::Body); let start = self.len_before_body(); let (extra, comp) = matchself.path[start..]
.iter()
.rposition(|b| self.is_sep_byte(*b))
{
None => (0, &self.path[start..]),
Some(i) => (1, &self.path[start + i + 1..]),
};
(comp.len() + extra, self.parse_single_component(comp))
}
// trim away repeated separators (i.e., empty components) on the left fn trim_left(&mutself) { while !self.path.is_empty() { let (size, comp) = self.parse_next_component(); if comp.is_some() { return;
} else { self.path = &self.path[size..];
}
}
}
// trim away repeated separators (i.e., empty components) on the right fn trim_right(&mutself) { whileself.path.len() > self.len_before_body() { let (size, comp) = self.parse_next_component_back(); if comp.is_some() { return;
} else { self.path = &self.path[..self.path.len() - size];
}
}
}
}
/// An iterator over [`Path`] and its ancestors. /// /// This `struct` is created by the [`ancestors`] method on [`Path`]. /// See its documentation for more. /// /// # Examples /// /// ``` /// use unix_path::Path; /// /// let path = Path::new("/foo/bar"); /// /// for ancestor in path.ancestors() { /// println!("{:?}", ancestor); /// } /// ``` /// /// [`ancestors`]: struct.Path.html#method.ancestors /// [`Path`]: struct.Path.html #[derive(Copy, Clone, Debug)] pubstruct Ancestors<'a> {
next: Option<&'a Path>,
}
impl<'a> Iterator for Ancestors<'a> { type Item = &'a Path;
fn next(&mutself) -> Option<Self::Item> { let next = self.next; self.next = next.and_then(Path::parent);
next
}
}
impl FusedIterator for Ancestors<'_> {}
//////////////////////////////////////////////////////////////////////////////// // Basic types and traits ////////////////////////////////////////////////////////////////////////////////
/// An owned, mutable path (akin to `String`). /// /// This type provides methods like [`push`] and [`set_extension`] that mutate /// the path in place. It also implements `Deref` to [`Path`], meaning that /// all methods on [`Path`] slices are available on `PathBuf` values as well. /// /// [`Path`]: struct.Path.html /// [`push`]: struct.PathBuf.html#method.push /// [`set_extension`]: struct.PathBuf.html#method.set_extension /// /// More details about the overall approach can be found in /// the [crate documentation](index.html). /// /// # Examples /// /// You can use [`push`] to build up a `PathBuf` from /// components: /// /// ``` /// use unix_path::PathBuf; /// /// let mut path = PathBuf::new(); /// /// path.push("/"); /// path.push("feel"); /// path.push("the"); /// /// path.set_extension("force"); /// ``` /// /// 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 unix_path::PathBuf; /// /// let path: PathBuf = ["/", "feel", "the.force"].iter().collect(); /// ``` /// /// We can still do better than this! Since these are all strings, we can use /// `From::from`: /// /// ``` /// use unix_path::PathBuf; /// /// let path = PathBuf::from(r"/feel/the.force"); /// ``` /// /// Which method works best depends on what kind of situation you're in. #[derive(Clone)] #[cfg(feature = "alloc")] pubstruct PathBuf {
inner: UnixString,
}
/// Creates a new `PathBuf` with a given capacity used to create the /// internal `UnixString`. See `with_capacity` defined on `UnixString`. /// /// # Examples /// /// ``` /// use unix_path::PathBuf; /// /// let mut path = PathBuf::with_capacity(10); /// let capacity = path.capacity(); /// /// // This push is done without reallocating /// path.push("/"); /// /// assert_eq!(capacity, path.capacity()); /// ``` pubfn with_capacity(capacity: usize) -> PathBuf {
PathBuf {
inner: UnixString::with_capacity(capacity),
}
}
/// Coerces to a [`Path`] slice. /// /// [`Path`]: struct.Path.html /// /// # Examples /// /// ``` /// use unix_path::{Path, PathBuf}; /// /// let p = PathBuf::from("/test"); /// assert_eq!(Path::new("/test"), p.as_path()); /// ``` pubfn as_path(&self) -> &Path { self
}
/// Extends `self` with `path`. /// /// If `path` is absolute, it replaces the current path. /// /// # Examples /// /// Pushing a relative path extends the existing path: /// /// ``` /// use unix_path::PathBuf; /// /// let mut path = PathBuf::from("/tmp"); /// path.push("file.bk"); /// assert_eq!(path, PathBuf::from("/tmp/file.bk")); /// ``` /// /// Pushing an absolute path replaces the existing path: /// /// ``` /// use unix_path::PathBuf; /// /// let mut path = PathBuf::from("/tmp"); /// path.push("/etc"); /// assert_eq!(path, PathBuf::from("/etc")); /// ``` pubfn push<P: AsRef<Path>>(&mutself, path: P) { self._push(path.as_ref())
}
fn _push(&mutself, path: &Path) { // in general, a separator is needed if the rightmost byte is not a separator let need_sep = self
.as_mut_vec()
.last()
.map(|c| *c != b'/')
.unwrap_or(false);
/// Truncates `self` to [`self.parent`]. /// /// Returns `false` and does nothing if [`self.parent`] is `None`. /// Otherwise, returns `true`. /// /// [`self.parent`]: struct.PathBuf.html#method.parent /// /// # Examples /// /// ``` /// use unix_path::{Path, PathBuf}; /// /// let mut p = PathBuf::from("/test/test.rs"); /// /// p.pop(); /// assert_eq!(Path::new("/test"), p); /// p.pop(); /// assert_eq!(Path::new("/"), p); /// ``` pubfn pop(&mutself) -> bool { matchself.parent().map(|p| p.as_unix_str().len()) {
Some(len) => { self.as_mut_vec().truncate(len); true
}
None => false,
}
}
/// Updates [`self.file_name`] to `file_name`. /// /// If [`self.file_name`] was `None`, this is equivalent to pushing /// `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 /// [`pop`]: struct.PathBuf.html#method.pop /// /// # Examples /// /// ``` /// use unix_path::PathBuf; /// /// let mut buf = PathBuf::from("/"); /// assert!(buf.file_name() == None); /// buf.set_file_name("bar"); /// assert!(buf == PathBuf::from("/bar")); /// assert!(buf.file_name().is_some()); /// buf.set_file_name("baz.txt"); /// assert!(buf == PathBuf::from("/baz.txt")); /// ``` pubfn set_file_name<S: AsRef<UnixStr>>(&mutself, file_name: S) { self._set_file_name(file_name.as_ref())
}
/// Updates [`self.extension`] to `extension`. /// /// Returns `false` and does nothing if [`self.file_name`] is `None`, /// returns `true` and updates the extension otherwise. /// /// 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 /// /// # Examples /// /// ``` /// use unix_path::{Path, PathBuf}; /// /// let mut p = PathBuf::from("/feel/the"); /// /// p.set_extension("force"); /// assert_eq!(Path::new("/feel/the.force"), p.as_path()); /// /// p.set_extension("dark_side"); /// assert_eq!(Path::new("/feel/the.dark_side"), p.as_path()); /// ```
// truncate until right after the file stem let end_file_stem = file_stem[file_stem.len()..].as_ptr() as usize; let start = unix_str_as_u8_slice(&self.inner).as_ptr() as usize; let v = self.as_mut_vec();
v.truncate(end_file_stem.wrapping_sub(start));
// add the new extension, if any let new = unix_str_as_u8_slice(extension); if !new.is_empty() {
v.reserve_exact(new.len() + 1);
v.push(b'.');
v.extend_from_slice(new);
}
true
}
/// Consumes the `PathBuf`, yielding its internal `UnixString` storage. /// /// # Examples /// /// ``` /// use unix_path::PathBuf; /// /// let p = PathBuf::from("/the/head"); /// let bytes = p.into_unix_string(); /// ``` pubfn into_unix_string(self) -> UnixString { self.inner
}
/// Converts this `PathBuf` into a boxed [`Path`]. /// /// [`Path`]: struct.Path.html pubfn into_boxed_path(self) -> Box<Path> { let rw = Box::into_raw(self.inner.into_boxed_unix_str()) as *mut Path; unsafe { Box::from_raw(rw) }
}
/// Invokes `capacity` on the underlying instance of `UnixString`. pubfn capacity(&self) -> usize { self.inner.capacity()
}
/// Invokes `clear` on the underlying instance of `UnixString`. pubfn clear(&mutself) { self.inner.clear()
}
/// Invokes `reserve` on the underlying instance of `UnixString`. pubfn reserve(&mutself, additional: usize) { self.inner.reserve(additional)
}
/// Invokes `reserve_exact` on the underlying instance of `UnixString`. pubfn reserve_exact(&mutself, additional: usize) { self.inner.reserve_exact(additional)
}
/// Invokes `shrink_to_fit` on the underlying instance of `UnixString`. pubfn shrink_to_fit(&mutself) { self.inner.shrink_to_fit()
}
/// Invokes `shrink_to` on the underlying instance of `UnixString`. #[cfg(feature = "shrink_to")] pubfn shrink_to(&mutself, min_capacity: usize) { self.inner.shrink_to(min_capacity)
}
}
#[cfg(feature = "alloc")] impl From<Box<Path>> for PathBuf { /// Converts a `Box<Path>` into a `PathBuf` /// /// This conversion does not allocate or copy memory. fn from(boxed: Box<Path>) -> PathBuf {
boxed.into_path_buf()
}
}
#[cfg(feature = "alloc")] impl From<PathBuf> forBox<Path> { /// Converts a `PathBuf` into a `Box<Path>` /// /// This conversion currently should not allocate memory, /// but this behavior is not guaranteed in all future versions. fn from(p: PathBuf) -> Self {
p.into_boxed_path()
}
}
#[cfg(feature = "alloc")] impl From<UnixString> for PathBuf { /// Converts a `UnixString` into a `PathBuf` /// /// This conversion does not allocate or copy memory. #[inline] fn from(s: UnixString) -> Self {
PathBuf { inner: s }
}
}
#[cfg(feature = "alloc")] impl From<PathBuf> for UnixString { /// Converts a `PathBuf` into a `UnixString` /// /// This conversion does not allocate or copy memory. fn from(path_buf: PathBuf) -> Self {
path_buf.inner
}
}
#[cfg(feature = "alloc")] impl From<String> for PathBuf { /// Converts a `String` into a `PathBuf` /// /// This conversion does not allocate or copy memory. fn from(s: String) -> PathBuf {
PathBuf::from(UnixString::from(s))
}
}
#[cfg(feature = "alloc")] impl FromStr for PathBuf { type Err = core::convert::Infallible;
#[cfg(feature = "alloc")] impl From<PathBuf> for Arc<Path> { /// Converts a `PathBuf` into an `Arc` by moving the `PathBuf` data into a new `Arc` buffer. #[inline] fn from(s: PathBuf) -> Arc<Path> { let arc: Arc<UnixStr> = Arc::from(s.into_unix_string()); unsafe { Arc::from_raw(Arc::into_raw(arc) as *const Path) }
}
}
#[cfg(feature = "alloc")] impl From<&Path> for Arc<Path> { /// Converts a `Path` into an `Arc` by copying the `Path` data into a new `Arc` buffer. #[inline] fn from(s: &Path) -> Arc<Path> { let arc: Arc<UnixStr> = Arc::from(s.as_unix_str()); unsafe { Arc::from_raw(Arc::into_raw(arc) as *const Path) }
}
}
#[cfg(feature = "alloc")] impl From<PathBuf> for Rc<Path> { /// Converts a `PathBuf` into an `Rc` by moving the `PathBuf` data into a new `Rc` buffer. #[inline] fn from(s: PathBuf) -> Rc<Path> { let rc: Rc<UnixStr> = Rc::from(s.into_unix_string()); unsafe { Rc::from_raw(Rc::into_raw(rc) as *const Path) }
}
}
#[cfg(feature = "alloc")] impl From<&Path> for Rc<Path> { /// Converts a `Path` into an `Rc` by copying the `Path` data into a new `Rc` buffer. #[inline] fn from(s: &Path) -> Rc<Path> { let rc: Rc<UnixStr> = Rc::from(s.as_unix_str()); unsafe { Rc::from_raw(Rc::into_raw(rc) as *const Path) }
}
}
#[cfg(feature = "alloc")] impl ToOwned for Path { type Owned = PathBuf; fn to_owned(&self) -> PathBuf { self.to_path_buf()
}
}
/// 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 `/` ), 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, /// see [`PathBuf`]. /// /// [`PathBuf`]: struct.PathBuf.html /// /// More details about the overall approach can be found in /// the [crate documentation](index.html). /// /// # Examples /// /// ``` /// use unix_path::Path; /// use unix_str::UnixStr; /// /// let path = Path::new("./foo/bar.txt"); /// /// let parent = path.parent(); /// assert_eq!(parent, Some(Path::new("./foo"))); /// /// let file_stem = path.file_stem(); /// assert_eq!(file_stem, Some(UnixStr::new("bar"))); /// /// let extension = path.extension(); /// assert_eq!(extension, Some(UnixStr::new("txt"))); /// ``` pubstruct Path {
inner: UnixStr,
}
/// 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)] pubstruct StripPrefixError(());
impl Path { // The following (private!) function allows construction of a path from a u8 // slice, which is only safe when it is known to follow the OsStr encoding. unsafefn from_u8_slice(s: &[u8]) -> &Path {
Path::new(u8_slice_as_unix_str(s))
} // The following (private!) function reveals the byte encoding used for OsStr. fn as_u8_slice(&self) -> &[u8] {
unix_str_as_u8_slice(&self.inner)
}
/// Directly wraps a string slice as a `Path` slice. /// /// This is a cost-free conversion. /// /// # Examples /// /// ``` /// use unix_path::Path; /// /// Path::new("foo.txt"); /// ``` /// /// You can create `Path`s from `String`s, or even other `Path`s: /// /// ``` /// use unix_path::Path; /// /// let string = String::from("foo.txt"); /// let from_string = Path::new(&string); /// let from_path = Path::new(&from_string); /// assert_eq!(from_string, from_path); /// ``` pubfn new<S: AsRef<UnixStr> + ?Sized>(s: &S) -> &Path { unsafe { &*(s.as_ref() as *const UnixStr as *const Path) }
}
/// Yields the underlying bytes. /// /// # Examples /// /// ``` /// use unix_path::Path; /// use unix_str::UnixStr; /// /// let os_str = Path::new("foo.txt").as_unix_str(); /// assert_eq!(os_str, UnixStr::new("foo.txt")); /// ``` pubfn as_unix_str(&self) -> &UnixStr {
&self.inner
}
/// Yields a `&str` slice if the `Path` is valid unicode. /// /// This conversion may entail doing a check for UTF-8 validity. /// Note that validation is performed because non-UTF-8 strings are /// perfectly valid for some OS. /// /// # Examples /// /// ``` /// use unix_path::Path; /// /// let path = Path::new("foo.txt"); /// assert_eq!(path.to_str(), Some("foo.txt")); /// ``` pubfn to_str(&self) -> Option<&str> { self.inner.to_str()
}
/// Converts a `Path` to a `Cow<str>`. /// /// Any non-Unicode sequences are replaced with /// `U+FFFD REPLACEMENT CHARACTER`. /// /// /// # Examples /// /// Calling `to_string_lossy` on a `Path` with valid unicode: /// /// ``` /// use unix_path::Path; /// /// 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"`. #[cfg(feature = "alloc")] pubfn to_string_lossy(&self) -> Cow<'_, str> { self.inner.to_string_lossy()
}
/// Converts a `Path` to an owned [`PathBuf`]. /// /// [`PathBuf`]: struct.PathBuf.html /// /// # Examples /// /// ``` /// use unix_path::Path; /// /// let path_buf = Path::new("foo.txt").to_path_buf(); /// assert_eq!(path_buf, unix_path::PathBuf::from("foo.txt")); /// ``` #[cfg(feature = "alloc")] pubfn to_path_buf(&self) -> PathBuf {
PathBuf::from(&self.inner)
}
/// Returns `true` if the `Path` is absolute, i.e., if it is independent of /// the current directory. /// /// A path is absolute if it starts with the root, so `is_absolute` and /// [`has_root`] are equivalent. /// /// # Examples /// /// ``` /// use unix_path::Path; /// /// assert!(!Path::new("foo.txt").is_absolute()); /// ``` /// /// [`has_root`]: #method.has_root pubfn is_absolute(&self) -> bool { self.has_root()
}
/// Returns `true` if the `Path` is relative, i.e., not absolute. /// /// See [`is_absolute`]'s documentation for more details. /// /// # Examples /// /// ``` /// use unix_path::Path; /// /// assert!(Path::new("foo.txt").is_relative()); /// ``` /// /// [`is_absolute`]: #method.is_absolute pubfn is_relative(&self) -> bool {
!self.is_absolute()
}
/// Returns `true` if the `Path` has a root. /// /// A path has a root if it begins with `/`. /// /// # Examples /// /// ``` /// use unix_path::Path; /// /// assert!(Path::new("/etc/passwd").has_root()); /// ``` pubfn has_root(&self) -> bool { self.components().has_root()
}
/// Returns the `Path` without its final component, if there is one. /// /// Returns `None` if the path terminates in a root or prefix. /// /// # Examples /// /// ``` /// use unix_path::Path; /// /// let path = Path::new("/foo/bar"); /// let parent = path.parent().unwrap(); /// assert_eq!(parent, Path::new("/foo")); /// /// let grand_parent = parent.parent().unwrap(); /// assert_eq!(grand_parent, Path::new("/")); /// assert_eq!(grand_parent.parent(), None); /// ``` pubfn parent(&self) -> Option<&Path> { letmut comps = self.components(); let comp = comps.next_back();
comp.and_then(|p| match p {
Component::Normal(_) | Component::CurDir | Component::ParentDir => {
Some(comps.as_path())
}
_ => None,
})
}
/// Produces an iterator over `Path` and its ancestors. /// /// The iterator will yield the `Path` that is returned if the [`parent`] method is used zero /// or more times. That means, the iterator will yield `&self`, `&self.parent().unwrap()`, /// `&self.parent().unwrap().parent().unwrap()` and so on. If the [`parent`] method returns /// `None`, the iterator will do likewise. The iterator will always yield at least one value, /// namely `&self`. /// /// # Examples /// /// ``` /// use unix_path::Path; /// /// let mut ancestors = Path::new("/foo/bar").ancestors(); /// assert_eq!(ancestors.next(), Some(Path::new("/foo/bar"))); /// assert_eq!(ancestors.next(), Some(Path::new("/foo"))); /// assert_eq!(ancestors.next(), Some(Path::new("/"))); /// assert_eq!(ancestors.next(), None); /// ``` /// /// [`parent`]: struct.Path.html#method.parent pubfn ancestors(&self) -> Ancestors<'_> {
Ancestors { next: Some(&self) }
}
/// Returns the final component of the `Path`, if there is one. /// /// 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. /// /// Returns `None` if the path terminates in `..`. /// /// # Examples /// /// ``` /// use unix_path::Path; /// use unix_str::UnixStr; /// /// assert_eq!(Some(UnixStr::new("bin")), Path::new("/usr/bin/").file_name()); /// assert_eq!(Some(UnixStr::new("foo.txt")), Path::new("tmp/foo.txt").file_name()); /// assert_eq!(Some(UnixStr::new("foo.txt")), Path::new("foo.txt/.").file_name()); /// assert_eq!(Some(UnixStr::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()); /// ``` pubfn file_name(&self) -> Option<&UnixStr> { self.components().next_back().and_then(|p| match p {
Component::Normal(p) => Some(p),
_ => None,
})
}
/// Returns a path that, when joined onto `base`, yields `self`. /// /// # Errors /// /// If `base` is not a prefix of `self` (i.e., [`starts_with`] /// returns `false`), returns `Err`. /// /// [`starts_with`]: #method.starts_with /// /// # Examples /// /// ``` /// use unix_path::{Path, PathBuf}; /// /// let path = Path::new("/test/haha/foo.txt"); /// /// assert_eq!(path.strip_prefix("/"), Ok(Path::new("test/haha/foo.txt"))); /// assert_eq!(path.strip_prefix("/test"), Ok(Path::new("haha/foo.txt"))); /// assert_eq!(path.strip_prefix("/test/"), Ok(Path::new("haha/foo.txt"))); /// assert_eq!(path.strip_prefix("/test/haha/foo.txt"), Ok(Path::new(""))); /// assert_eq!(path.strip_prefix("/test/haha/foo.txt/"), Ok(Path::new(""))); /// assert_eq!(path.strip_prefix("test").is_ok(), false); /// assert_eq!(path.strip_prefix("/haha").is_ok(), false); /// /// let prefix = PathBuf::from("/test/"); /// assert_eq!(path.strip_prefix(prefix), Ok(Path::new("haha/foo.txt"))); /// ``` pubfn strip_prefix<P>(&self, base: P) -> Result<&Path, StripPrefixError> where
P: AsRef<Path>,
{ self._strip_prefix(base.as_ref())
}
/// Extracts the stem (non-extension) portion of [`self.file_name`]. /// /// [`self.file_name`]: struct.Path.html#method.file_name /// /// The stem is: /// /// * `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 `.` /// /// # Examples /// /// ``` /// use unix_path::Path; /// /// let path = Path::new("foo.rs"); /// /// assert_eq!("foo", path.file_stem().unwrap()); /// ``` pubfn file_stem(&self) -> Option<&UnixStr> { self.file_name()
.map(split_file_at_dot)
.and_then(|(before, after)| before.or(after))
}
/// 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; /// * Otherwise, the portion of the file name after the final `.` /// /// [`self.file_name`]: struct.Path.html#method.file_name /// /// # Examples /// /// ``` /// use unix_path::Path; /// use unix_str::UnixStr; /// /// let path = Path::new("foo.rs"); /// /// assert_eq!(UnixStr::new("rs"), path.extension().unwrap()); /// ``` pubfn extension(&self) -> Option<&UnixStr> { self.file_name()
.map(split_file_at_dot)
.and_then(|(before, after)| before.and(after))
}
/// Creates an owned [`PathBuf`] with `path` adjoined to `self`. /// /// See [`PathBuf::push`] for more details on what it means to adjoin a path. /// /// [`PathBuf`]: struct.PathBuf.html /// [`PathBuf::push`]: struct.PathBuf.html#method.push /// /// # Examples /// /// ``` /// use unix_path::{Path, PathBuf}; /// /// assert_eq!(Path::new("/etc").join("passwd"), PathBuf::from("/etc/passwd")); /// ``` #[must_use] #[cfg(feature = "alloc")] pubfn join<P: AsRef<Path>>(&self, path: P) -> PathBuf { self._join(path.as_ref())
}
/// 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. /// /// * A trailing slash is normalized away, `/a/b` and `/a/b/` are equivalent. /// /// 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 /// /// ``` /// use unix_path::{Path, Component}; /// use unix_str::UnixStr; /// /// let mut components = Path::new("/tmp/foo.txt").components(); /// /// assert_eq!(components.next(), Some(Component::RootDir)); /// assert_eq!(components.next(), Some(Component::Normal(UnixStr::new("tmp")))); /// assert_eq!(components.next(), Some(Component::Normal(UnixStr::new("foo.txt")))); /// assert_eq!(components.next(), None) /// ``` /// /// [`Component`]: enum.Component.html /// [`CurDir`]: enum.Component.html#variant.CurDir pubfn components(&self) -> Components<'_> {
Components {
path: self.as_u8_slice(),
has_physical_root: has_physical_root(self.as_u8_slice()),
front: State::Prefix,
back: State::Body,
}
}
/// Produces an iterator over the path's components viewed as `UnixStr` /// slices. /// /// For more information about the particulars of how the path is separated /// into components, see [`components`]. /// /// [`components`]: #method.components /// /// # Examples /// /// ``` /// use unix_path::{self, Path}; /// use unix_str::UnixStr; /// /// let mut it = Path::new("/tmp/foo.txt").iter(); /// assert_eq!(it.next(), Some(UnixStr::new("/"))); /// assert_eq!(it.next(), Some(UnixStr::new("tmp"))); /// assert_eq!(it.next(), Some(UnixStr::new("foo.txt"))); /// assert_eq!(it.next(), None) /// ``` pubfn iter(&self) -> Iter<'_> {
Iter {
inner: self.components(),
}
}
/// Converts a `Box<Path>` into a [`PathBuf`] without copying or /// allocating. /// /// [`PathBuf`]: struct.PathBuf.html #[cfg(feature = "alloc")] pubfn into_path_buf(self: Box<Path>) -> PathBuf { let rw = Box::into_raw(self) as *mut UnixStr; let inner = unsafe { Box::from_raw(rw) };
PathBuf {
inner: UnixString::from(inner),
}
}
/// Returns a newtype that implements Display for safely printing paths /// that may contain non-Unicode data. pubfn display(&self) -> Display<'_> {
Display { path: self }
}
}
#[test] fn test_components_debug() { let path = Path::new("/tmp");
letmut components = path.components();
let expected = "Components([RootDir, Normal(\"tmp\")])"; let actual = format!("{:?}", components);
assert_eq!(expected, actual);
let _ = components.next().unwrap(); let expected = "Components([Normal(\"tmp\")])"; let actual = format!("{:?}", components);
assert_eq!(expected, actual);
let _ = components.next().unwrap(); let expected = "Components([])"; let actual = format!("{:?}", components);
assert_eq!(expected, actual);
}
#[test] fn test_iter_debug() { let path = Path::new("/tmp");
letmut iter = path.iter();
let expected = "Iter([\"/\", \"tmp\"])"; let actual = format!("{:?}", iter);
assert_eq!(expected, actual);
let _ = iter.next().unwrap(); let expected = "Iter([\"tmp\"])"; let actual = format!("{:?}", iter);
assert_eq!(expected, actual);
let _ = iter.next().unwrap(); let expected = "Iter([])"; 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 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());
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.