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}