async_std/path/
pathbuf.rs

1use std::borrow::{Borrow, Cow};
2use std::ffi::{OsStr, OsString};
3use std::iter::{self, FromIterator};
4use std::ops::Deref;
5#[cfg(feature = "unstable")]
6use std::pin::Pin;
7use std::rc::Rc;
8use std::str::FromStr;
9use std::sync::Arc;
10
11use crate::path::Path;
12#[cfg(feature = "unstable")]
13use crate::prelude::*;
14#[cfg(feature = "unstable")]
15use crate::stream::{self, FromStream, IntoStream};
16
17/// This struct is an async version of [`std::path::PathBuf`].
18///
19/// [`std::path::Path`]: https://doc.rust-lang.org/std/path/struct.PathBuf.html
20#[derive(Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
21pub struct PathBuf {
22    inner: std::path::PathBuf,
23}
24
25impl PathBuf {
26    /// Allocates an empty `PathBuf`.
27    ///
28    /// # Examples
29    ///
30    /// ```
31    /// use async_std::path::PathBuf;
32    ///
33    /// let path = PathBuf::new();
34    /// ```
35    pub fn new() -> PathBuf {
36        std::path::PathBuf::new().into()
37    }
38
39    /// Coerces to a [`Path`] slice.
40    ///
41    /// [`Path`]: struct.Path.html
42    ///
43    /// # Examples
44    ///
45    /// ```
46    /// use async_std::path::{Path, PathBuf};
47    ///
48    /// let p = PathBuf::from("/test");
49    /// assert_eq!(Path::new("/test"), p.as_path());
50    /// ```
51    pub fn as_path(&self) -> &Path {
52        self.inner.as_path().into()
53    }
54
55    /// Extends `self` with `path`.
56    ///
57    /// If `path` is absolute, it replaces the current path.
58    ///
59    /// On Windows:
60    ///
61    /// * if `path` has a root but no prefix (e.g., `\windows`), it
62    ///   replaces everything except for the prefix (if any) of `self`.
63    /// * if `path` has a prefix but no root, it replaces `self`.
64    ///
65    /// # Examples
66    ///
67    /// Pushing a relative path extends the existing path:
68    ///
69    /// ```
70    /// use async_std::path::PathBuf;
71    ///
72    /// let mut path = PathBuf::from("/tmp");
73    /// path.push("file.bk");
74    /// assert_eq!(path, PathBuf::from("/tmp/file.bk"));
75    /// ```
76    ///
77    /// Pushing an absolute path replaces the existing path:
78    ///
79    /// ```
80    /// use async_std::path::PathBuf;
81    ///
82    /// let mut path = PathBuf::from("/tmp");
83    /// path.push("/etc");
84    /// assert_eq!(path, PathBuf::from("/etc"));
85    /// ```
86    pub fn push<P: AsRef<Path>>(&mut self, path: P) {
87        self.inner.push(path.as_ref())
88    }
89
90    /// Truncates `self` to [`self.parent`].
91    ///
92    /// Returns `false` and does nothing if [`self.parent`] is [`None`].
93    /// Otherwise, returns `true`.
94    ///
95    /// [`None`]: https://doc.rust-lang.org/std/option/enum.Option.html#variant.None
96    /// [`self.parent`]: struct.PathBuf.html#method.parent
97    ///
98    /// # Examples
99    ///
100    /// ```
101    /// use async_std::path::{Path, PathBuf};
102    ///
103    /// let mut p = PathBuf::from("/test/test.rs");
104    ///
105    /// p.pop();
106    /// assert_eq!(Path::new("/test"), p);
107    /// p.pop();
108    /// assert_eq!(Path::new("/"), p);
109    /// ```
110    pub fn pop(&mut self) -> bool {
111        self.inner.pop()
112    }
113
114    /// Updates [`self.file_name`] to `file_name`.
115    ///
116    /// If [`self.file_name`] was [`None`], this is equivalent to pushing
117    /// `file_name`.
118    ///
119    /// Otherwise it is equivalent to calling [`pop`] and then pushing
120    /// `file_name`. The new path will be a sibling of the original path.
121    /// (That is, it will have the same parent.)
122    ///
123    /// [`self.file_name`]: struct.PathBuf.html#method.file_name
124    /// [`None`]: https://doc.rust-lang.org/std/option/enum.Option.html#variant.None
125    /// [`pop`]: struct.PathBuf.html#method.pop
126    ///
127    /// # Examples
128    ///
129    /// ```
130    /// use async_std::path::PathBuf;
131    ///
132    /// let mut buf = PathBuf::from("/");
133    /// assert!(buf.file_name() == None);
134    /// buf.set_file_name("bar");
135    /// assert!(buf == PathBuf::from("/bar"));
136    /// assert!(buf.file_name().is_some());
137    /// buf.set_file_name("baz.txt");
138    /// assert!(buf == PathBuf::from("/baz.txt"));
139    /// ```
140    pub fn set_file_name<S: AsRef<OsStr>>(&mut self, file_name: S) {
141        self.inner.set_file_name(file_name)
142    }
143
144    /// Updates [`self.extension`] to `extension`.
145    ///
146    /// Returns `false` and does nothing if [`self.file_name`] is [`None`],
147    /// returns `true` and updates the extension otherwise.
148    ///
149    /// If [`self.extension`] is [`None`], the extension is added; otherwise
150    /// it is replaced.
151    ///
152    /// [`self.file_name`]: struct.PathBuf.html#method.file_name
153    /// [`self.extension`]: struct.PathBuf.html#method.extension
154    /// [`None`]: https://doc.rust-lang.org/std/option/enum.Option.html#variant.None
155    ///
156    /// # Examples
157    ///
158    /// ```
159    /// use async_std::path::{Path, PathBuf};
160    ///
161    /// let mut p = PathBuf::from("/feel/the");
162    ///
163    /// p.set_extension("force");
164    /// assert_eq!(Path::new("/feel/the.force"), p.as_path());
165    ///
166    /// p.set_extension("dark_side");
167    /// assert_eq!(Path::new("/feel/the.dark_side"), p.as_path());
168    /// ```
169    pub fn set_extension<S: AsRef<OsStr>>(&mut self, extension: S) -> bool {
170        self.inner.set_extension(extension)
171    }
172
173    /// Consumes the `PathBuf`, returning its internal [`OsString`] storage.
174    ///
175    /// [`OsString`]: https://doc.rust-lang.org/std/ffi/struct.OsString.html
176    ///
177    /// # Examples
178    ///
179    /// ```
180    /// use async_std::path::PathBuf;
181    ///
182    /// let p = PathBuf::from("/the/head");
183    /// let os_str = p.into_os_string();
184    /// ```
185    pub fn into_os_string(self) -> OsString {
186        self.inner.into_os_string()
187    }
188
189    /// Converts this `PathBuf` into a [boxed][`Box`] [`Path`].
190    ///
191    /// [`Box`]: https://doc.rust-lang.org/std/boxed/struct.Box.html
192    /// [`Path`]: struct.Path.html
193    pub fn into_boxed_path(self) -> Box<Path> {
194        let rw = Box::into_raw(self.inner.into_boxed_path()) as *mut Path;
195        unsafe { Box::from_raw(rw) }
196    }
197}
198
199impl From<Box<Path>> for PathBuf {
200    fn from(boxed: Box<Path>) -> PathBuf {
201        boxed.into_path_buf()
202    }
203}
204
205impl From<PathBuf> for Box<Path> {
206    fn from(p: PathBuf) -> Box<Path> {
207        p.into_boxed_path()
208    }
209}
210
211impl Clone for Box<Path> {
212    #[inline]
213    fn clone(&self) -> Self {
214        self.to_path_buf().into_boxed_path()
215    }
216}
217
218impl<T: ?Sized + AsRef<OsStr>> From<&T> for PathBuf {
219    fn from(s: &T) -> PathBuf {
220        PathBuf::from(s.as_ref().to_os_string())
221    }
222}
223
224impl From<OsString> for PathBuf {
225    fn from(s: OsString) -> PathBuf {
226        PathBuf { inner: s.into() }
227    }
228}
229
230impl From<PathBuf> for OsString {
231    fn from(path_buf: PathBuf) -> OsString {
232        path_buf.inner.into()
233    }
234}
235
236impl From<String> for PathBuf {
237    fn from(s: String) -> PathBuf {
238        PathBuf::from(OsString::from(s))
239    }
240}
241
242impl FromStr for PathBuf {
243    type Err = core::convert::Infallible;
244
245    fn from_str(s: &str) -> Result<Self, Self::Err> {
246        Ok(PathBuf::from(s))
247    }
248}
249
250impl<P: AsRef<Path>> FromIterator<P> for PathBuf {
251    fn from_iter<I: IntoIterator<Item = P>>(iter: I) -> PathBuf {
252        let mut buf = PathBuf::new();
253        buf.extend(iter);
254        buf
255    }
256}
257
258impl<P: AsRef<Path>> iter::Extend<P> for PathBuf {
259    fn extend<I: IntoIterator<Item = P>>(&mut self, iter: I) {
260        iter.into_iter().for_each(move |p| self.push(p.as_ref()));
261    }
262}
263
264impl Deref for PathBuf {
265    type Target = Path;
266
267    fn deref(&self) -> &Path {
268        Path::new(&self.inner)
269    }
270}
271
272impl Borrow<Path> for PathBuf {
273    fn borrow(&self) -> &Path {
274        self.deref()
275    }
276}
277
278impl<'a> From<PathBuf> for Cow<'a, Path> {
279    #[inline]
280    fn from(s: PathBuf) -> Cow<'a, Path> {
281        Cow::Owned(s)
282    }
283}
284
285impl<'a> From<&'a PathBuf> for Cow<'a, Path> {
286    #[inline]
287    fn from(p: &'a PathBuf) -> Cow<'a, Path> {
288        Cow::Borrowed(p.as_path())
289    }
290}
291
292impl<'a> From<Cow<'a, Path>> for PathBuf {
293    #[inline]
294    fn from(p: Cow<'a, Path>) -> Self {
295        p.into_owned()
296    }
297}
298
299impl From<PathBuf> for Arc<Path> {
300    #[inline]
301    fn from(s: PathBuf) -> Arc<Path> {
302        let arc: Arc<OsStr> = Arc::from(s.into_os_string());
303        unsafe { Arc::from_raw(Arc::into_raw(arc) as *const Path) }
304    }
305}
306
307impl From<PathBuf> for Rc<Path> {
308    #[inline]
309    fn from(s: PathBuf) -> Rc<Path> {
310        let rc: Rc<OsStr> = Rc::from(s.into_os_string());
311        unsafe { Rc::from_raw(Rc::into_raw(rc) as *const Path) }
312    }
313}
314
315impl AsRef<OsStr> for PathBuf {
316    fn as_ref(&self) -> &OsStr {
317        self.inner.as_ref()
318    }
319}
320
321#[cfg(feature = "unstable")]
322impl<P: AsRef<Path>> stream::Extend<P> for PathBuf {
323    fn extend<'a, S: IntoStream<Item = P> + 'a>(
324        &'a mut self,
325        stream: S,
326    ) -> Pin<Box<dyn Future<Output = ()> + 'a + Send>>
327    where
328        <S as IntoStream>::IntoStream: Send,
329    {
330        let stream = stream.into_stream();
331
332        Box::pin(async move {
333            pin_utils::pin_mut!(stream);
334
335            while let Some(item) = stream.next().await {
336                self.push(item.as_ref());
337            }
338        })
339    }
340}
341
342#[cfg(feature = "unstable")]
343impl<'b, P: AsRef<Path> + 'b + Send> FromStream<P> for PathBuf {
344    #[inline]
345    fn from_stream<'a, S: IntoStream<Item = P> + 'a>(
346        stream: S,
347    ) -> Pin<Box<dyn Future<Output = Self> + 'a + Send>>
348    where
349        <S as IntoStream>::IntoStream: Send,
350    {
351        let stream = stream.into_stream();
352
353        Box::pin(async move {
354            let mut out = Self::new();
355            stream::extend(&mut out, stream).await;
356            out
357        })
358    }
359}
360
361impl From<std::path::PathBuf> for PathBuf {
362    fn from(path: std::path::PathBuf) -> PathBuf {
363        PathBuf { inner: path }
364    }
365}
366
367impl Into<std::path::PathBuf> for PathBuf {
368    fn into(self) -> std::path::PathBuf {
369        self.inner
370    }
371}
372
373impl AsRef<std::path::Path> for PathBuf {
374    fn as_ref(&self) -> &std::path::Path {
375        self.inner.as_ref()
376    }
377}