| use std::borrow::{Borrow, Cow}; |
| use std::ffi::{OsStr, OsString}; |
| use std::iter::{self, FromIterator}; |
| use std::ops::Deref; |
| #[cfg(feature = "unstable")] |
| use std::pin::Pin; |
| use std::rc::Rc; |
| use std::str::FromStr; |
| use std::sync::Arc; |
| |
| use crate::path::Path; |
| #[cfg(feature = "unstable")] |
| use crate::prelude::*; |
| #[cfg(feature = "unstable")] |
| use crate::stream::{self, FromStream, IntoStream}; |
| |
| /// This struct is an async version of [`std::path::PathBuf`]. |
| /// |
| /// [`std::path::Path`]: https://doc.rust-lang.org/std/path/struct.PathBuf.html |
| #[derive(Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)] |
| pub struct PathBuf { |
| inner: std::path::PathBuf, |
| } |
| |
| impl PathBuf { |
| /// Allocates an empty `PathBuf`. |
| /// |
| /// # Examples |
| /// |
| /// ``` |
| /// use async_std::path::PathBuf; |
| /// |
| /// let path = PathBuf::new(); |
| /// ``` |
| pub fn new() -> PathBuf { |
| std::path::PathBuf::new().into() |
| } |
| |
| /// Coerces to a [`Path`] slice. |
| /// |
| /// [`Path`]: struct.Path.html |
| /// |
| /// # Examples |
| /// |
| /// ``` |
| /// use async_std::path::{Path, PathBuf}; |
| /// |
| /// let p = PathBuf::from("/test"); |
| /// assert_eq!(Path::new("/test"), p.as_path()); |
| /// ``` |
| pub fn as_path(&self) -> &Path { |
| self.inner.as_path().into() |
| } |
| |
| /// Extends `self` with `path`. |
| /// |
| /// If `path` is absolute, it replaces the current path. |
| /// |
| /// On Windows: |
| /// |
| /// * if `path` has a root but no prefix (e.g., `\windows`), it |
| /// replaces everything except for the prefix (if any) of `self`. |
| /// * if `path` has a prefix but no root, it replaces `self`. |
| /// |
| /// # Examples |
| /// |
| /// Pushing a relative path extends the existing path: |
| /// |
| /// ``` |
| /// use async_std::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 async_std::path::PathBuf; |
| /// |
| /// let mut path = PathBuf::from("/tmp"); |
| /// path.push("/etc"); |
| /// assert_eq!(path, PathBuf::from("/etc")); |
| /// ``` |
| pub fn push<P: AsRef<Path>>(&mut self, path: P) { |
| self.inner.push(path.as_ref()) |
| } |
| |
| /// Truncates `self` to [`self.parent`]. |
| /// |
| /// Returns `false` and does nothing if [`self.parent`] is [`None`]. |
| /// Otherwise, returns `true`. |
| /// |
| /// [`None`]: https://doc.rust-lang.org/std/option/enum.Option.html#variant.None |
| /// [`self.parent`]: struct.PathBuf.html#method.parent |
| /// |
| /// # Examples |
| /// |
| /// ``` |
| /// use async_std::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); |
| /// ``` |
| pub fn pop(&mut self) -> bool { |
| self.inner.pop() |
| } |
| |
| /// 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 |
| /// [`None`]: https://doc.rust-lang.org/std/option/enum.Option.html#variant.None |
| /// [`pop`]: struct.PathBuf.html#method.pop |
| /// |
| /// # Examples |
| /// |
| /// ``` |
| /// use async_std::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")); |
| /// ``` |
| pub fn set_file_name<S: AsRef<OsStr>>(&mut self, file_name: S) { |
| self.inner.set_file_name(file_name) |
| } |
| |
| /// 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 |
| /// [`None`]: https://doc.rust-lang.org/std/option/enum.Option.html#variant.None |
| /// |
| /// # Examples |
| /// |
| /// ``` |
| /// use async_std::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()); |
| /// ``` |
| pub fn set_extension<S: AsRef<OsStr>>(&mut self, extension: S) -> bool { |
| self.inner.set_extension(extension) |
| } |
| |
| /// Consumes the `PathBuf`, returning its internal [`OsString`] storage. |
| /// |
| /// [`OsString`]: https://doc.rust-lang.org/std/ffi/struct.OsString.html |
| /// |
| /// # Examples |
| /// |
| /// ``` |
| /// use async_std::path::PathBuf; |
| /// |
| /// let p = PathBuf::from("/the/head"); |
| /// let os_str = p.into_os_string(); |
| /// ``` |
| pub fn into_os_string(self) -> OsString { |
| self.inner.into_os_string() |
| } |
| |
| /// Converts this `PathBuf` into a [boxed][`Box`] [`Path`]. |
| /// |
| /// [`Box`]: https://doc.rust-lang.org/std/boxed/struct.Box.html |
| /// [`Path`]: struct.Path.html |
| pub fn into_boxed_path(self) -> Box<Path> { |
| let rw = Box::into_raw(self.inner.into_boxed_path()) as *mut Path; |
| unsafe { Box::from_raw(rw) } |
| } |
| } |
| |
| impl From<Box<Path>> for PathBuf { |
| fn from(boxed: Box<Path>) -> PathBuf { |
| boxed.into_path_buf() |
| } |
| } |
| |
| impl From<PathBuf> for Box<Path> { |
| fn from(p: PathBuf) -> Box<Path> { |
| p.into_boxed_path() |
| } |
| } |
| |
| impl Clone for Box<Path> { |
| #[inline] |
| fn clone(&self) -> Self { |
| self.to_path_buf().into_boxed_path() |
| } |
| } |
| |
| impl<T: ?Sized + AsRef<OsStr>> From<&T> for PathBuf { |
| fn from(s: &T) -> PathBuf { |
| PathBuf::from(s.as_ref().to_os_string()) |
| } |
| } |
| |
| impl From<OsString> for PathBuf { |
| fn from(s: OsString) -> PathBuf { |
| PathBuf { inner: s.into() } |
| } |
| } |
| |
| impl From<PathBuf> for OsString { |
| fn from(path_buf: PathBuf) -> OsString { |
| path_buf.inner.into() |
| } |
| } |
| |
| impl From<String> for PathBuf { |
| fn from(s: String) -> PathBuf { |
| PathBuf::from(OsString::from(s)) |
| } |
| } |
| |
| impl FromStr for PathBuf { |
| type Err = core::convert::Infallible; |
| |
| fn from_str(s: &str) -> Result<Self, Self::Err> { |
| Ok(PathBuf::from(s)) |
| } |
| } |
| |
| impl<P: AsRef<Path>> FromIterator<P> for PathBuf { |
| fn from_iter<I: IntoIterator<Item = P>>(iter: I) -> PathBuf { |
| let mut buf = PathBuf::new(); |
| buf.extend(iter); |
| buf |
| } |
| } |
| |
| impl<P: AsRef<Path>> iter::Extend<P> for PathBuf { |
| fn extend<I: IntoIterator<Item = P>>(&mut self, iter: I) { |
| iter.into_iter().for_each(move |p| self.push(p.as_ref())); |
| } |
| } |
| |
| impl Deref for PathBuf { |
| type Target = Path; |
| |
| fn deref(&self) -> &Path { |
| Path::new(&self.inner) |
| } |
| } |
| |
| impl Borrow<Path> for PathBuf { |
| fn borrow(&self) -> &Path { |
| self.deref() |
| } |
| } |
| |
| impl<'a> From<PathBuf> for Cow<'a, Path> { |
| #[inline] |
| fn from(s: PathBuf) -> Cow<'a, Path> { |
| Cow::Owned(s) |
| } |
| } |
| |
| impl<'a> From<&'a PathBuf> for Cow<'a, Path> { |
| #[inline] |
| fn from(p: &'a PathBuf) -> Cow<'a, Path> { |
| Cow::Borrowed(p.as_path()) |
| } |
| } |
| |
| impl<'a> From<Cow<'a, Path>> for PathBuf { |
| #[inline] |
| fn from(p: Cow<'a, Path>) -> Self { |
| p.into_owned() |
| } |
| } |
| |
| 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) } |
| } |
| } |
| |
| 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) } |
| } |
| } |
| |
| impl AsRef<OsStr> for PathBuf { |
| fn as_ref(&self) -> &OsStr { |
| self.inner.as_ref() |
| } |
| } |
| |
| #[cfg(feature = "unstable")] |
| impl<P: AsRef<Path>> stream::Extend<P> for PathBuf { |
| fn extend<'a, S: IntoStream<Item = P> + 'a>( |
| &'a mut self, |
| stream: S, |
| ) -> Pin<Box<dyn Future<Output = ()> + 'a>> { |
| let stream = stream.into_stream(); |
| |
| Box::pin(async move { |
| pin_utils::pin_mut!(stream); |
| |
| while let Some(item) = stream.next().await { |
| self.push(item.as_ref()); |
| } |
| }) |
| } |
| } |
| |
| #[cfg(feature = "unstable")] |
| impl<'b, P: AsRef<Path> + 'b> FromStream<P> for PathBuf { |
| #[inline] |
| fn from_stream<'a, S: IntoStream<Item = P> + 'a>( |
| stream: S, |
| ) -> Pin<Box<dyn Future<Output = Self> + 'a>> { |
| let stream = stream.into_stream(); |
| |
| Box::pin(async move { |
| let mut out = Self::new(); |
| stream::extend(&mut out, stream).await; |
| out |
| }) |
| } |
| } |
| |
| impl From<std::path::PathBuf> for PathBuf { |
| fn from(path: std::path::PathBuf) -> PathBuf { |
| PathBuf { inner: path } |
| } |
| } |
| |
| impl Into<std::path::PathBuf> for PathBuf { |
| fn into(self) -> std::path::PathBuf { |
| self.inner |
| } |
| } |
| |
| impl AsRef<std::path::Path> for PathBuf { |
| fn as_ref(&self) -> &std::path::Path { |
| self.inner.as_ref() |
| } |
| } |