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>(&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>(&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>(&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 { let rw = Box::into_raw(self.inner.into_boxed_path()) as *mut Path; unsafe { Box::from_raw(rw) } } } impl From> for PathBuf { fn from(boxed: Box) -> PathBuf { boxed.into_path_buf() } } impl From for Box { fn from(p: PathBuf) -> Box { p.into_boxed_path() } } impl Clone for Box { #[inline] fn clone(&self) -> Self { self.to_path_buf().into_boxed_path() } } impl> From<&T> for PathBuf { fn from(s: &T) -> PathBuf { PathBuf::from(s.as_ref().to_os_string()) } } impl From for PathBuf { fn from(s: OsString) -> PathBuf { PathBuf { inner: s.into() } } } impl From for OsString { fn from(path_buf: PathBuf) -> OsString { path_buf.inner.into() } } impl From 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 { Ok(PathBuf::from(s)) } } impl> FromIterator

for PathBuf { fn from_iter>(iter: I) -> PathBuf { let mut buf = PathBuf::new(); buf.extend(iter); buf } } impl> iter::Extend

for PathBuf { fn extend>(&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 for PathBuf { fn borrow(&self) -> &Path { self.deref() } } impl<'a> From 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> for PathBuf { #[inline] fn from(p: Cow<'a, Path>) -> Self { p.into_owned() } } impl From for Arc { #[inline] fn from(s: PathBuf) -> Arc { let arc: Arc = Arc::from(s.into_os_string()); unsafe { Arc::from_raw(Arc::into_raw(arc) as *const Path) } } } impl From for Rc { #[inline] fn from(s: PathBuf) -> Rc { let rc: Rc = Rc::from(s.into_os_string()); unsafe { Rc::from_raw(Rc::into_raw(rc) as *const Path) } } } impl AsRef for PathBuf { fn as_ref(&self) -> &OsStr { self.inner.as_ref() } } #[cfg(feature = "unstable")] impl> stream::Extend

for PathBuf { fn extend<'a, S: IntoStream + 'a>( &'a mut self, stream: S, ) -> Pin + 'a>> { let stream = stream.into_stream(); Box::pin(async move { while let Some(item) = stream.next().await { self.push(item.as_ref()); } }) } } #[cfg(feature = "unstable")] impl<'b, P: AsRef + 'b> FromStream

for PathBuf { #[inline] fn from_stream<'a, S: IntoStream + 'a>( stream: S, ) -> Pin + 'a>> { let stream = stream.into_stream(); Box::pin(async move { let mut out = Self::new(); stream::extend(&mut out, stream).await; out }) } } impl From for PathBuf { fn from(path: std::path::PathBuf) -> PathBuf { PathBuf { inner: path } } } impl Into for PathBuf { fn into(self) -> std::path::PathBuf { self.inner } } impl AsRef for PathBuf { fn as_ref(&self) -> &std::path::Path { self.inner.as_ref() } }