1 | use std::borrow::{Borrow, Cow}; |
2 | use std::ffi::{OsStr, OsString}; |
3 | use std::iter::{self, FromIterator}; |
4 | use std::ops::Deref; |
5 | #[cfg (feature = "unstable" )] |
6 | use std::pin::Pin; |
7 | use std::rc::Rc; |
8 | use std::str::FromStr; |
9 | use std::sync::Arc; |
10 | |
11 | use crate::path::Path; |
12 | #[cfg (feature = "unstable" )] |
13 | use crate::prelude::*; |
14 | #[cfg (feature = "unstable" )] |
15 | use 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)] |
21 | pub struct PathBuf { |
22 | inner: std::path::PathBuf, |
23 | } |
24 | |
25 | impl 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 | |
199 | impl From<Box<Path>> for PathBuf { |
200 | fn from(boxed: Box<Path>) -> PathBuf { |
201 | boxed.into_path_buf() |
202 | } |
203 | } |
204 | |
205 | impl From<PathBuf> for Box<Path> { |
206 | fn from(p: PathBuf) -> Box<Path> { |
207 | p.into_boxed_path() |
208 | } |
209 | } |
210 | |
211 | impl Clone for Box<Path> { |
212 | #[inline ] |
213 | fn clone(&self) -> Self { |
214 | self.to_path_buf().into_boxed_path() |
215 | } |
216 | } |
217 | |
218 | impl<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 | |
224 | impl From<OsString> for PathBuf { |
225 | fn from(s: OsString) -> PathBuf { |
226 | PathBuf { inner: s.into() } |
227 | } |
228 | } |
229 | |
230 | impl From<PathBuf> for OsString { |
231 | fn from(path_buf: PathBuf) -> OsString { |
232 | path_buf.inner.into() |
233 | } |
234 | } |
235 | |
236 | impl From<String> for PathBuf { |
237 | fn from(s: String) -> PathBuf { |
238 | PathBuf::from(OsString::from(s)) |
239 | } |
240 | } |
241 | |
242 | impl 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 | |
250 | impl<P: AsRef<Path>> FromIterator<P> for PathBuf { |
251 | fn from_iter<I: IntoIterator<Item = P>>(iter: I) -> PathBuf { |
252 | let mut buf: PathBuf = PathBuf::new(); |
253 | buf.extend(iter); |
254 | buf |
255 | } |
256 | } |
257 | |
258 | impl<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: P| self.push(path:p.as_ref())); |
261 | } |
262 | } |
263 | |
264 | impl Deref for PathBuf { |
265 | type Target = Path; |
266 | |
267 | fn deref(&self) -> &Path { |
268 | Path::new(&self.inner) |
269 | } |
270 | } |
271 | |
272 | impl Borrow<Path> for PathBuf { |
273 | fn borrow(&self) -> &Path { |
274 | self.deref() |
275 | } |
276 | } |
277 | |
278 | impl<'a> From<PathBuf> for Cow<'a, Path> { |
279 | #[inline ] |
280 | fn from(s: PathBuf) -> Cow<'a, Path> { |
281 | Cow::Owned(s) |
282 | } |
283 | } |
284 | |
285 | impl<'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 | |
292 | impl<'a> From<Cow<'a, Path>> for PathBuf { |
293 | #[inline ] |
294 | fn from(p: Cow<'a, Path>) -> Self { |
295 | p.into_owned() |
296 | } |
297 | } |
298 | |
299 | impl 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(ptr:Arc::into_raw(this:arc) as *const Path) } |
304 | } |
305 | } |
306 | |
307 | impl 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(ptr:Rc::into_raw(this:rc) as *const Path) } |
312 | } |
313 | } |
314 | |
315 | impl AsRef<OsStr> for PathBuf { |
316 | fn as_ref(&self) -> &OsStr { |
317 | self.inner.as_ref() |
318 | } |
319 | } |
320 | |
321 | #[cfg (feature = "unstable" )] |
322 | impl<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" )] |
343 | impl<'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 | |
361 | impl From<std::path::PathBuf> for PathBuf { |
362 | fn from(path: std::path::PathBuf) -> PathBuf { |
363 | PathBuf { inner: path } |
364 | } |
365 | } |
366 | |
367 | impl Into<std::path::PathBuf> for PathBuf { |
368 | fn into(self) -> std::path::PathBuf { |
369 | self.inner |
370 | } |
371 | } |
372 | |
373 | impl AsRef<std::path::Path> for PathBuf { |
374 | fn as_ref(&self) -> &std::path::Path { |
375 | self.inner.as_ref() |
376 | } |
377 | } |
378 | |