1 | use std::borrow::{Cow, ToOwned}; |
2 | use std::cmp::Ordering; |
3 | use std::ffi::{OsStr, OsString}; |
4 | use std::rc::Rc; |
5 | use std::sync::Arc; |
6 | |
7 | use crate::path::{Ancestors, Components, Display, Iter, PathBuf, StripPrefixError}; |
8 | #[cfg (not(target_os = "unknown" ))] |
9 | use crate::{fs, io}; |
10 | |
11 | /// A slice of a path. |
12 | /// |
13 | /// This struct is an async version of [`std::path::Path`]. |
14 | /// |
15 | /// This type supports a number of operations for inspecting a path, including |
16 | /// breaking the path into its components (separated by `/` on Unix and by either |
17 | /// `/` or `\` on Windows), extracting the file name, determining whether the path |
18 | /// is absolute, and so on. |
19 | /// |
20 | /// This is an *unsized* type, meaning that it must always be used behind a |
21 | /// pointer like `&` or `Box`. For an owned version of this type, |
22 | /// see [`PathBuf`]. |
23 | /// |
24 | /// [`PathBuf`]: struct.PathBuf.html |
25 | /// [`std::path::Path`]: https://doc.rust-lang.org/std/path/struct.Path.html |
26 | /// |
27 | /// More details about the overall approach can be found in |
28 | /// the [module documentation](index.html). |
29 | /// |
30 | /// # Examples |
31 | /// |
32 | /// ``` |
33 | /// use std::path::Path; |
34 | /// use std::ffi::OsStr; |
35 | /// |
36 | /// // Note: this example does work on Windows |
37 | /// let path = Path::new("./foo/bar.txt" ); |
38 | /// |
39 | /// let parent = path.parent(); |
40 | /// assert_eq!(parent, Some(Path::new("./foo" ))); |
41 | /// |
42 | /// let file_stem = path.file_stem(); |
43 | /// assert_eq!(file_stem, Some(OsStr::new("bar" ))); |
44 | /// |
45 | /// let extension = path.extension(); |
46 | /// assert_eq!(extension, Some(OsStr::new("txt" ))); |
47 | /// ``` |
48 | #[derive (Debug, PartialEq, Eq, Hash, PartialOrd, Ord)] |
49 | pub struct Path { |
50 | inner: std::path::Path, |
51 | } |
52 | |
53 | impl Path { |
54 | /// Directly wraps a string slice as a `Path` slice. |
55 | /// |
56 | /// This is a cost-free conversion. |
57 | /// |
58 | /// # Examples |
59 | /// |
60 | /// ``` |
61 | /// use async_std::path::Path; |
62 | /// |
63 | /// Path::new("foo.txt" ); |
64 | /// ``` |
65 | /// |
66 | /// You can create `Path`s from `String`s, or even other `Path`s: |
67 | /// |
68 | /// ``` |
69 | /// use async_std::path::Path; |
70 | /// |
71 | /// let string = String::from("foo.txt" ); |
72 | /// let from_string = Path::new(&string); |
73 | /// let from_path = Path::new(&from_string); |
74 | /// assert_eq!(from_string, from_path); |
75 | /// ``` |
76 | pub fn new<S: AsRef<OsStr> + ?Sized>(s: &S) -> &Path { |
77 | unsafe { &*(std::path::Path::new(s) as *const std::path::Path as *const Path) } |
78 | } |
79 | |
80 | /// Returns the underlying [`OsStr`] slice. |
81 | /// |
82 | /// [`OsStr`]: https://doc.rust-lang.org/std/ffi/struct.OsStr.html |
83 | /// |
84 | /// # Examples |
85 | /// |
86 | /// ``` |
87 | /// use std::ffi::OsStr; |
88 | /// |
89 | /// use async_std::path::Path; |
90 | /// |
91 | /// let os_str = Path::new("foo.txt" ).as_os_str(); |
92 | /// assert_eq!(os_str, OsStr::new("foo.txt" )); |
93 | /// ``` |
94 | pub fn as_os_str(&self) -> &OsStr { |
95 | self.inner.as_os_str() |
96 | } |
97 | |
98 | /// Returns a [`&str`] slice if the `Path` is valid unicode. |
99 | /// |
100 | /// This conversion may entail doing a check for UTF-8 validity. |
101 | /// Note that validation is performed because non-UTF-8 strings are |
102 | /// perfectly valid for some OS. |
103 | /// |
104 | /// [`&str`]: https://doc.rust-lang.org/std/primitive.str.html |
105 | /// |
106 | /// # Examples |
107 | /// |
108 | /// ``` |
109 | /// use async_std::path::Path; |
110 | /// |
111 | /// let path = Path::new("foo.txt" ); |
112 | /// assert_eq!(path.to_str(), Some("foo.txt" )); |
113 | /// ``` |
114 | pub fn to_str(&self) -> Option<&str> { |
115 | self.inner.to_str() |
116 | } |
117 | |
118 | /// Converts a `Path` to a [`Cow<str>`]. |
119 | /// |
120 | /// Any non-Unicode sequences are replaced with |
121 | /// [`U+FFFD REPLACEMENT CHARACTER`][U+FFFD]. |
122 | /// |
123 | /// [`Cow<str>`]: https://doc.rust-lang.org/std/borrow/enum.Cow.html |
124 | /// [U+FFFD]: https://doc.rust-lang.org/std/char/constant.REPLACEMENT_CHARACTER.html |
125 | /// |
126 | /// # Examples |
127 | /// |
128 | /// Calling `to_string_lossy` on a `Path` with valid unicode: |
129 | /// |
130 | /// ``` |
131 | /// use async_std::path::Path; |
132 | /// |
133 | /// let path = Path::new("foo.txt" ); |
134 | /// assert_eq!(path.to_string_lossy(), "foo.txt" ); |
135 | /// ``` |
136 | /// |
137 | /// Had `path` contained invalid unicode, the `to_string_lossy` call might |
138 | /// have returned `"fo�.txt"`. |
139 | pub fn to_string_lossy(&self) -> Cow<'_, str> { |
140 | self.inner.to_string_lossy() |
141 | } |
142 | |
143 | /// Converts a `Path` to an owned [`PathBuf`]. |
144 | /// |
145 | /// [`PathBuf`]: struct.PathBuf.html |
146 | /// |
147 | /// # Examples |
148 | /// |
149 | /// ``` |
150 | /// use async_std::path::{Path, PathBuf}; |
151 | /// |
152 | /// let path_buf = Path::new("foo.txt" ).to_path_buf(); |
153 | /// assert_eq!(path_buf, PathBuf::from("foo.txt" )); |
154 | /// ``` |
155 | pub fn to_path_buf(&self) -> PathBuf { |
156 | PathBuf::from(self.inner.to_path_buf()) |
157 | } |
158 | |
159 | /// Returns `true` if the `Path` is absolute, i.e. if it is independent of |
160 | /// the current directory. |
161 | /// |
162 | /// * On Unix, a path is absolute if it starts with the root, so |
163 | /// `is_absolute` and [`has_root`] are equivalent. |
164 | /// |
165 | /// * On Windows, a path is absolute if it has a prefix and starts with the |
166 | /// root: `c:\windows` is absolute, while `c:temp` and `\temp` are not. |
167 | /// |
168 | /// [`has_root`]: #method.has_root |
169 | /// |
170 | /// # Examples |
171 | /// |
172 | /// ``` |
173 | /// use async_std::path::Path; |
174 | /// |
175 | /// assert!(!Path::new("foo.txt" ).is_absolute()); |
176 | /// ``` |
177 | pub fn is_absolute(&self) -> bool { |
178 | self.inner.is_absolute() |
179 | } |
180 | |
181 | /// Returns `true` if the `Path` is relative, i.e. not absolute. |
182 | /// |
183 | /// See [`is_absolute`]'s documentation for more details. |
184 | /// |
185 | /// [`is_absolute`]: #method.is_absolute |
186 | /// |
187 | /// # Examples |
188 | /// |
189 | /// ``` |
190 | /// use async_std::path::Path; |
191 | /// |
192 | /// assert!(Path::new("foo.txt" ).is_relative()); |
193 | /// ``` |
194 | pub fn is_relative(&self) -> bool { |
195 | self.inner.is_relative() |
196 | } |
197 | |
198 | /// Returns `true` if the `Path` has a root. |
199 | /// |
200 | /// * On Unix, a path has a root if it begins with `/`. |
201 | /// |
202 | /// * On Windows, a path has a root if it: |
203 | /// * has no prefix and begins with a separator, e.g. `\windows` |
204 | /// * has a prefix followed by a separator, e.g. `c:\windows` but not `c:windows` |
205 | /// * has any non-disk prefix, e.g. `\\server\share` |
206 | /// |
207 | /// # Examples |
208 | /// |
209 | /// ``` |
210 | /// use async_std::path::Path; |
211 | /// |
212 | /// assert!(Path::new("/etc/passwd" ).has_root()); |
213 | /// ``` |
214 | pub fn has_root(&self) -> bool { |
215 | self.inner.has_root() |
216 | } |
217 | |
218 | /// Returns the `Path` without its final component, if there is one. |
219 | /// |
220 | /// Returns [`None`] if the path terminates in a root or prefix. |
221 | /// |
222 | /// [`None`]: https://doc.rust-lang.org/std/option/enum.Option.html#variant.None |
223 | /// |
224 | /// # Examples |
225 | /// |
226 | /// ``` |
227 | /// use async_std::path::Path; |
228 | /// |
229 | /// let path = Path::new("/foo/bar" ); |
230 | /// let parent = path.parent().unwrap(); |
231 | /// assert_eq!(parent, Path::new("/foo" )); |
232 | /// |
233 | /// let grand_parent = parent.parent().unwrap(); |
234 | /// assert_eq!(grand_parent, Path::new("/" )); |
235 | /// assert_eq!(grand_parent.parent(), None); |
236 | /// ``` |
237 | pub fn parent(&self) -> Option<&Path> { |
238 | self.inner.parent().map(|p| p.into()) |
239 | } |
240 | |
241 | /// Produces an iterator over `Path` and its ancestors. |
242 | /// |
243 | /// The iterator will yield the `Path` that is returned if the [`parent`] method is used zero |
244 | /// or more times. That means, the iterator will yield `&self`, `&self.parent().unwrap()`, |
245 | /// `&self.parent().unwrap().parent().unwrap()` and so on. If the [`parent`] method returns |
246 | /// [`None`], the iterator will do likewise. The iterator will always yield at least one value, |
247 | /// namely `&self`. |
248 | /// |
249 | /// [`None`]: https://doc.rust-lang.org/std/option/enum.Option.html |
250 | /// [`parent`]: struct.Path.html#method.parent |
251 | /// |
252 | /// # Examples |
253 | /// |
254 | /// ``` |
255 | /// use async_std::path::Path; |
256 | /// |
257 | /// let mut ancestors = Path::new("/foo/bar" ).ancestors(); |
258 | /// assert_eq!(ancestors.next(), Some(Path::new("/foo/bar" ).into())); |
259 | /// assert_eq!(ancestors.next(), Some(Path::new("/foo" ).into())); |
260 | /// assert_eq!(ancestors.next(), Some(Path::new("/" ).into())); |
261 | /// assert_eq!(ancestors.next(), None); |
262 | /// ``` |
263 | pub fn ancestors(&self) -> Ancestors<'_> { |
264 | Ancestors { next: Some(&self) } |
265 | } |
266 | |
267 | /// Returns the final component of the `Path`, if there is one. |
268 | /// |
269 | /// If the path is a normal file, this is the file name. If it's the path of a directory, this |
270 | /// is the directory name. |
271 | /// |
272 | /// Returns [`None`] if the path terminates in `..`. |
273 | /// |
274 | /// [`None`]: https://doc.rust-lang.org/std/option/enum.Option.html#variant.None |
275 | /// |
276 | /// # Examples |
277 | /// |
278 | /// ``` |
279 | /// use std::ffi::OsStr; |
280 | /// |
281 | /// use async_std::path::Path; |
282 | /// |
283 | /// assert_eq!(Some(OsStr::new("bin" )), Path::new("/usr/bin/" ).file_name()); |
284 | /// assert_eq!(Some(OsStr::new("foo.txt" )), Path::new("tmp/foo.txt" ).file_name()); |
285 | /// assert_eq!(Some(OsStr::new("foo.txt" )), Path::new("foo.txt/." ).file_name()); |
286 | /// assert_eq!(Some(OsStr::new("foo.txt" )), Path::new("foo.txt/.//" ).file_name()); |
287 | /// assert_eq!(None, Path::new("foo.txt/.." ).file_name()); |
288 | /// assert_eq!(None, Path::new("/" ).file_name()); |
289 | /// ``` |
290 | pub fn file_name(&self) -> Option<&OsStr> { |
291 | self.inner.file_name() |
292 | } |
293 | |
294 | /// Returns a path that becomes `self` when joined onto `base`. |
295 | /// |
296 | /// # Errors |
297 | /// |
298 | /// If `base` is not a prefix of `self` (i.e., [`starts_with`] |
299 | /// returns `false`), returns [`Err`]. |
300 | /// |
301 | /// [`starts_with`]: #method.starts_with |
302 | /// [`Err`]: https://doc.rust-lang.org/std/result/enum.Result.html#variant.Err |
303 | /// |
304 | /// # Examples |
305 | /// |
306 | /// ``` |
307 | /// use async_std::path::{Path, PathBuf}; |
308 | /// |
309 | /// let path = Path::new("/test/haha/foo.txt" ); |
310 | /// |
311 | /// assert_eq!(path.strip_prefix("/" ), Ok(Path::new("test/haha/foo.txt" ))); |
312 | /// assert_eq!(path.strip_prefix("/test" ), Ok(Path::new("haha/foo.txt" ))); |
313 | /// assert_eq!(path.strip_prefix("/test/" ), Ok(Path::new("haha/foo.txt" ))); |
314 | /// assert_eq!(path.strip_prefix("/test/haha/foo.txt" ), Ok(Path::new("" ))); |
315 | /// assert_eq!(path.strip_prefix("/test/haha/foo.txt/" ), Ok(Path::new("" ))); |
316 | /// assert_eq!(path.strip_prefix("test" ).is_ok(), false); |
317 | /// assert_eq!(path.strip_prefix("/haha" ).is_ok(), false); |
318 | /// |
319 | /// let prefix = PathBuf::from("/test/" ); |
320 | /// assert_eq!(path.strip_prefix(prefix), Ok(Path::new("haha/foo.txt" ))); |
321 | /// ``` |
322 | pub fn strip_prefix<P>(&self, base: P) -> Result<&Path, StripPrefixError> |
323 | where |
324 | P: AsRef<Path>, |
325 | { |
326 | Ok(self.inner.strip_prefix(base.as_ref())?.into()) |
327 | } |
328 | |
329 | /// Determines whether `base` is a prefix of `self`. |
330 | /// |
331 | /// Only considers whole path components to match. |
332 | /// |
333 | /// # Examples |
334 | /// |
335 | /// ``` |
336 | /// use async_std::path::Path; |
337 | /// |
338 | /// let path = Path::new("/etc/passwd" ); |
339 | /// |
340 | /// assert!(path.starts_with("/etc" )); |
341 | /// assert!(path.starts_with("/etc/" )); |
342 | /// assert!(path.starts_with("/etc/passwd" )); |
343 | /// assert!(path.starts_with("/etc/passwd/" )); |
344 | /// |
345 | /// assert!(!path.starts_with("/e" )); |
346 | /// ``` |
347 | pub fn starts_with<P: AsRef<Path>>(&self, base: P) -> bool { |
348 | self.inner.starts_with(base.as_ref()) |
349 | } |
350 | |
351 | /// Determines whether `child` is a suffix of `self`. |
352 | /// |
353 | /// Only considers whole path components to match. |
354 | /// |
355 | /// # Examples |
356 | /// |
357 | /// ``` |
358 | /// use async_std::path::Path; |
359 | /// |
360 | /// let path = Path::new("/etc/passwd" ); |
361 | /// |
362 | /// assert!(path.ends_with("passwd" )); |
363 | /// ``` |
364 | pub fn ends_with<P: AsRef<Path>>(&self, child: P) -> bool { |
365 | self.inner.ends_with(child.as_ref()) |
366 | } |
367 | |
368 | /// Extracts the stem (non-extension) portion of [`file_name`]. |
369 | /// |
370 | /// [`file_name`]: struct.Path.html#method.file_name |
371 | /// |
372 | /// The stem is: |
373 | /// |
374 | /// * [`None`], if there is no file name |
375 | /// * The entire file name if there is no embedded `.` |
376 | /// * The entire file name if the file name begins with `.` and has no other `.`s within |
377 | /// * Otherwise, the portion of the file name before the final `.` |
378 | /// |
379 | /// [`None`]: https://doc.rust-lang.org/std/option/enum.Option.html#variant.None |
380 | /// |
381 | /// # Examples |
382 | /// |
383 | /// ``` |
384 | /// use async_std::path::Path; |
385 | /// |
386 | /// let path = Path::new("foo.rs" ); |
387 | /// |
388 | /// assert_eq!("foo" , path.file_stem().unwrap()); |
389 | /// ``` |
390 | pub fn file_stem(&self) -> Option<&OsStr> { |
391 | self.inner.file_stem() |
392 | } |
393 | |
394 | /// Extracts the extension of [`file_name`], if possible. |
395 | /// |
396 | /// The extension is: |
397 | /// |
398 | /// * [`None`], if there is no file name |
399 | /// * [`None`], if there is no embedded `.` |
400 | /// * [`None`], if the file name begins with `.` and has no other `.`s within |
401 | /// * Otherwise, the portion of the file name after the final `.` |
402 | /// |
403 | /// [`file_name`]: struct.Path.html#method.file_name |
404 | /// [`None`]: https://doc.rust-lang.org/std/option/enum.Option.html#variant.None |
405 | /// |
406 | /// # Examples |
407 | /// |
408 | /// ``` |
409 | /// use async_std::path::Path; |
410 | /// |
411 | /// let path = Path::new("foo.rs" ); |
412 | /// |
413 | /// assert_eq!("rs" , path.extension().unwrap()); |
414 | /// ``` |
415 | pub fn extension(&self) -> Option<&OsStr> { |
416 | self.inner.extension() |
417 | } |
418 | |
419 | /// Creates an owned [`PathBuf`] with `path` adjoined to `self`. |
420 | /// |
421 | /// See [`PathBuf::push`] for more details on what it means to adjoin a path. |
422 | /// |
423 | /// [`PathBuf`]: struct.PathBuf.html |
424 | /// [`PathBuf::push`]: struct.PathBuf.html#method.push |
425 | /// |
426 | /// # Examples |
427 | /// |
428 | /// ``` |
429 | /// use async_std::path::{Path, PathBuf}; |
430 | /// |
431 | /// assert_eq!(Path::new("/etc" ).join("passwd" ), PathBuf::from("/etc/passwd" )); |
432 | /// ``` |
433 | pub fn join<P: AsRef<Path>>(&self, path: P) -> PathBuf { |
434 | self.inner.join(path.as_ref()).into() |
435 | } |
436 | |
437 | /// Creates an owned [`PathBuf`] like `self` but with the given file name. |
438 | /// |
439 | /// See [`PathBuf::set_file_name`] for more details. |
440 | /// |
441 | /// [`PathBuf`]: struct.PathBuf.html |
442 | /// [`PathBuf::set_file_name`]: struct.PathBuf.html#method.set_file_name |
443 | /// |
444 | /// # Examples |
445 | /// |
446 | /// ``` |
447 | /// use async_std::path::{Path, PathBuf}; |
448 | /// |
449 | /// let path = Path::new("/tmp/foo.txt" ); |
450 | /// assert_eq!(path.with_file_name("bar.txt" ), PathBuf::from("/tmp/bar.txt" )); |
451 | /// |
452 | /// let path = Path::new("/tmp" ); |
453 | /// assert_eq!(path.with_file_name("var" ), PathBuf::from("/var" )); |
454 | /// ``` |
455 | pub fn with_file_name<S: AsRef<OsStr>>(&self, file_name: S) -> PathBuf { |
456 | self.inner.with_file_name(file_name).into() |
457 | } |
458 | |
459 | /// Creates an owned [`PathBuf`] like `self` but with the given extension. |
460 | /// |
461 | /// See [`PathBuf::set_extension`] for more details. |
462 | /// |
463 | /// [`PathBuf`]: struct.PathBuf.html |
464 | /// [`PathBuf::set_extension`]: struct.PathBuf.html#method.set_extension |
465 | /// |
466 | /// # Examples |
467 | /// |
468 | /// ``` |
469 | /// use async_std::path::{Path, PathBuf}; |
470 | /// |
471 | /// let path = Path::new("foo.rs" ); |
472 | /// assert_eq!(path.with_extension("txt" ), PathBuf::from("foo.txt" )); |
473 | /// ``` |
474 | pub fn with_extension<S: AsRef<OsStr>>(&self, extension: S) -> PathBuf { |
475 | self.inner.with_extension(extension).into() |
476 | } |
477 | |
478 | /// Produces an iterator over the [`Component`]s of the path. |
479 | /// |
480 | /// When parsing the path, there is a small amount of normalization: |
481 | /// |
482 | /// * Repeated separators are ignored, so `a/b` and `a//b` both have |
483 | /// `a` and `b` as components. |
484 | /// |
485 | /// * Occurrences of `.` are normalized away, except if they are at the |
486 | /// beginning of the path. For example, `a/./b`, `a/b/`, `a/b/.` and |
487 | /// `a/b` all have `a` and `b` as components, but `./a/b` starts with |
488 | /// an additional [`CurDir`] component. |
489 | /// |
490 | /// * A trailing slash is normalized away, `/a/b` and `/a/b/` are equivalent. |
491 | /// |
492 | /// Note that no other normalization takes place; in particular, `a/c` |
493 | /// and `a/b/../c` are distinct, to account for the possibility that `b` |
494 | /// is a symbolic link (so its parent isn't `a`). |
495 | /// |
496 | /// [`Component`]: enum.Component.html |
497 | /// [`CurDir`]: enum.Component.html#variant.CurDir |
498 | /// |
499 | /// # Examples |
500 | /// |
501 | /// ``` |
502 | /// use std::ffi::OsStr; |
503 | /// |
504 | /// use async_std::path::{Path, Component}; |
505 | /// |
506 | /// let mut components = Path::new("/tmp/foo.txt" ).components(); |
507 | /// |
508 | /// assert_eq!(components.next(), Some(Component::RootDir)); |
509 | /// assert_eq!(components.next(), Some(Component::Normal(OsStr::new("tmp" )))); |
510 | /// assert_eq!(components.next(), Some(Component::Normal(OsStr::new("foo.txt" )))); |
511 | /// assert_eq!(components.next(), None); |
512 | /// ``` |
513 | pub fn components(&self) -> Components<'_> { |
514 | Components { |
515 | inner: self.inner.components(), |
516 | } |
517 | } |
518 | |
519 | /// Produces an iterator over the path's components viewed as [`OsStr`] |
520 | /// slices. |
521 | /// |
522 | /// For more information about the particulars of how the path is separated |
523 | /// into components, see [`components`]. |
524 | /// |
525 | /// [`components`]: #method.components |
526 | /// [`OsStr`]: https://doc.rust-lang.org/std/ffi/struct.OsStr.html |
527 | /// |
528 | /// # Examples |
529 | /// |
530 | /// ``` |
531 | /// use std::ffi::OsStr; |
532 | /// |
533 | /// use async_std::path::{self, Path}; |
534 | /// |
535 | /// let mut it = Path::new("/tmp/foo.txt" ).iter(); |
536 | /// assert_eq!(it.next(), Some(OsStr::new(&path::MAIN_SEPARATOR.to_string()))); |
537 | /// assert_eq!(it.next(), Some(OsStr::new("tmp" ))); |
538 | /// assert_eq!(it.next(), Some(OsStr::new("foo.txt" ))); |
539 | /// assert_eq!(it.next(), None) |
540 | /// ``` |
541 | pub fn iter(&self) -> Iter<'_> { |
542 | Iter { |
543 | inner: self.components(), |
544 | } |
545 | } |
546 | |
547 | /// Returns an object that implements [`Display`] for safely printing paths |
548 | /// that may contain non-Unicode data. |
549 | /// |
550 | /// [`Display`]: https://doc.rust-lang.org/std/fmt/trait.Display.html |
551 | /// |
552 | /// # Examples |
553 | /// |
554 | /// ``` |
555 | /// use async_std::path::Path; |
556 | /// |
557 | /// let path = Path::new("/tmp/foo.rs" ); |
558 | /// |
559 | /// println!("{}" , path.display()); |
560 | /// ``` |
561 | pub fn display(&self) -> Display<'_> { |
562 | self.inner.display() |
563 | } |
564 | |
565 | /// Reads the metadata of a file or directory. |
566 | /// |
567 | /// This function will traverse symbolic links to query information about the |
568 | /// destination file. |
569 | /// |
570 | /// This is an alias to [`fs::metadata`]. |
571 | /// |
572 | /// [`fs::metadata`]: ../fs/fn.metadata.html |
573 | /// |
574 | /// # Examples |
575 | /// |
576 | /// ```no_run |
577 | /// # fn main() -> std::io::Result<()> { async_std::task::block_on(async { |
578 | /// # |
579 | /// use async_std::path::Path; |
580 | /// |
581 | /// let path = Path::new("/Minas/tirith" ); |
582 | /// let metadata = path.metadata().await?; |
583 | /// println!("{:?}" , metadata.file_type()); |
584 | /// # |
585 | /// # Ok(()) }) } |
586 | /// ``` |
587 | #[cfg (not(target_os = "unknown" ))] |
588 | pub async fn metadata(&self) -> io::Result<fs::Metadata> { |
589 | fs::metadata(self).await |
590 | } |
591 | |
592 | /// Reads the metadata of a file or directory without following symbolic links. |
593 | /// |
594 | /// This is an alias to [`fs::symlink_metadata`]. |
595 | /// |
596 | /// [`fs::symlink_metadata`]: ../fs/fn.symlink_metadata.html |
597 | /// |
598 | /// # Examples |
599 | /// |
600 | /// ```no_run |
601 | /// # fn main() -> std::io::Result<()> { async_std::task::block_on(async { |
602 | /// # |
603 | /// use async_std::path::Path; |
604 | /// |
605 | /// let path = Path::new("/Minas/tirith" ); |
606 | /// let metadata = path.symlink_metadata().await?; |
607 | /// println!("{:?}" , metadata.file_type()); |
608 | /// # |
609 | /// # Ok(()) }) } |
610 | /// ``` |
611 | #[cfg (not(target_os = "unknown" ))] |
612 | pub async fn symlink_metadata(&self) -> io::Result<fs::Metadata> { |
613 | fs::symlink_metadata(self).await |
614 | } |
615 | |
616 | /// Returns the canonical form of a path. |
617 | /// |
618 | /// The returned path is in absolute form with all intermediate components normalized and |
619 | /// symbolic links resolved. |
620 | /// |
621 | /// This is an alias to [`fs::canonicalize`]. |
622 | /// |
623 | /// [`fs::canonicalize`]: ../fs/fn.canonicalize.html |
624 | /// |
625 | /// # Examples |
626 | /// |
627 | /// ```no_run |
628 | /// # fn main() -> std::io::Result<()> { async_std::task::block_on(async { |
629 | /// # |
630 | /// use async_std::path::{Path, PathBuf}; |
631 | /// |
632 | /// let path = Path::new("/foo/test/../test/bar.rs" ); |
633 | /// assert_eq!(path.canonicalize().await?, PathBuf::from("/foo/test/bar.rs" )); |
634 | /// # |
635 | /// # Ok(()) }) } |
636 | /// ``` |
637 | #[cfg (not(target_os = "unknown" ))] |
638 | pub async fn canonicalize(&self) -> io::Result<PathBuf> { |
639 | fs::canonicalize(self).await |
640 | } |
641 | |
642 | /// Reads a symbolic link, returning the file that the link points to. |
643 | /// |
644 | /// This is an alias to [`fs::read_link`]. |
645 | /// |
646 | /// [`fs::read_link`]: ../fs/fn.read_link.html |
647 | /// |
648 | /// # Examples |
649 | /// |
650 | /// ```no_run |
651 | /// # fn main() -> std::io::Result<()> { async_std::task::block_on(async { |
652 | /// # |
653 | /// use async_std::path::Path; |
654 | /// |
655 | /// let path = Path::new("/laputa/sky_castle.rs" ); |
656 | /// let path_link = path.read_link().await?; |
657 | /// # |
658 | /// # Ok(()) }) } |
659 | /// ``` |
660 | #[cfg (not(target_os = "unknown" ))] |
661 | pub async fn read_link(&self) -> io::Result<PathBuf> { |
662 | fs::read_link(self).await |
663 | } |
664 | |
665 | /// Returns a stream over the entries within a directory. |
666 | /// |
667 | /// The stream will yield instances of [`io::Result`]`<`[`DirEntry`]`>`. New |
668 | /// errors may be encountered after an iterator is initially constructed. |
669 | /// |
670 | /// This is an alias to [`fs::read_dir`]. |
671 | /// |
672 | /// [`io::Result`]: ../io/type.Result.html |
673 | /// [`DirEntry`]: ../fs/struct.DirEntry.html |
674 | /// [`fs::read_dir`]: ../fs/fn.read_dir.html |
675 | /// |
676 | /// # Examples |
677 | /// |
678 | /// ```no_run |
679 | /// # fn main() -> std::io::Result<()> { async_std::task::block_on(async { |
680 | /// # |
681 | /// use async_std::fs; |
682 | /// use async_std::path::Path; |
683 | /// use async_std::prelude::*; |
684 | /// |
685 | /// let path = Path::new("/laputa" ); |
686 | /// let mut dir = fs::read_dir(&path).await?; |
687 | /// |
688 | /// while let Some(res) = dir.next().await { |
689 | /// let entry = res?; |
690 | /// println!("{}" , entry.file_name().to_string_lossy()); |
691 | /// } |
692 | /// # |
693 | /// # Ok(()) }) } |
694 | /// ``` |
695 | #[cfg (not(target_os = "unknown" ))] |
696 | pub async fn read_dir(&self) -> io::Result<fs::ReadDir> { |
697 | fs::read_dir(self).await |
698 | } |
699 | |
700 | /// Returns `true` if the path points at an existing entity. |
701 | /// |
702 | /// This function will traverse symbolic links to query information about the |
703 | /// destination file. In case of broken symbolic links this will return `false`. |
704 | /// |
705 | /// If you cannot access the directory containing the file, e.g., because of a |
706 | /// permission error, this will return `false`. |
707 | /// |
708 | /// # Examples |
709 | /// |
710 | /// ```no_run |
711 | /// # fn main() -> std::io::Result<()> { async_std::task::block_on(async { |
712 | /// # |
713 | /// use async_std::path::Path; |
714 | /// assert_eq!(Path::new("does_not_exist.txt" ).exists().await, false); |
715 | /// # |
716 | /// # Ok(()) }) } |
717 | /// ``` |
718 | /// |
719 | /// # See Also |
720 | /// |
721 | /// This is a convenience function that coerces errors to false. If you want to |
722 | /// check errors, call [fs::metadata]. |
723 | /// |
724 | /// [fs::metadata]: ../fs/fn.metadata.html |
725 | #[cfg (not(target_os = "unknown" ))] |
726 | pub async fn exists(&self) -> bool { |
727 | fs::metadata(self).await.is_ok() |
728 | } |
729 | |
730 | /// Returns `true` if the path exists on disk and is pointing at a regular file. |
731 | /// |
732 | /// This function will traverse symbolic links to query information about the |
733 | /// destination file. In case of broken symbolic links this will return `false`. |
734 | /// |
735 | /// If you cannot access the directory containing the file, e.g., because of a |
736 | /// permission error, this will return `false`. |
737 | /// |
738 | /// # Examples |
739 | /// |
740 | /// ```no_run |
741 | /// # fn main() -> std::io::Result<()> { async_std::task::block_on(async { |
742 | /// # |
743 | /// use async_std::path::Path; |
744 | /// assert_eq!(Path::new("./is_a_directory/" ).is_file().await, false); |
745 | /// assert_eq!(Path::new("a_file.txt" ).is_file().await, true); |
746 | /// # |
747 | /// # Ok(()) }) } |
748 | /// ``` |
749 | /// |
750 | /// # See Also |
751 | /// |
752 | /// This is a convenience function that coerces errors to false. If you want to |
753 | /// check errors, call [fs::metadata] and handle its Result. Then call |
754 | /// [fs::Metadata::is_file] if it was Ok. |
755 | /// |
756 | /// [fs::metadata]: ../fs/fn.metadata.html |
757 | /// [fs::Metadata::is_file]: ../fs/struct.Metadata.html#method.is_file |
758 | #[cfg (not(target_os = "unknown" ))] |
759 | pub async fn is_file(&self) -> bool { |
760 | fs::metadata(self) |
761 | .await |
762 | .map(|m| m.is_file()) |
763 | .unwrap_or(false) |
764 | } |
765 | |
766 | /// Returns `true` if the path exists on disk and is pointing at a directory. |
767 | /// |
768 | /// This function will traverse symbolic links to query information about the |
769 | /// destination file. In case of broken symbolic links this will return `false`. |
770 | /// |
771 | /// If you cannot access the directory containing the file, e.g., because of a |
772 | /// permission error, this will return `false`. |
773 | /// |
774 | /// # Examples |
775 | /// |
776 | /// ```no_run |
777 | /// # fn main() -> std::io::Result<()> { async_std::task::block_on(async { |
778 | /// # |
779 | /// use async_std::path::Path; |
780 | /// |
781 | /// assert_eq!(Path::new("./is_a_directory/" ).is_dir().await, true); |
782 | /// assert_eq!(Path::new("a_file.txt" ).is_dir().await, false); |
783 | /// # |
784 | /// # Ok(()) }) } |
785 | /// ``` |
786 | /// |
787 | /// # See Also |
788 | /// |
789 | /// This is a convenience function that coerces errors to false. If you want to |
790 | /// check errors, call [fs::metadata] and handle its Result. Then call |
791 | /// [fs::Metadata::is_dir] if it was Ok. |
792 | /// |
793 | /// [fs::metadata]: ../fs/fn.metadata.html |
794 | /// [fs::Metadata::is_dir]: ../fs/struct.Metadata.html#method.is_dir |
795 | #[cfg (not(target_os = "unknown" ))] |
796 | pub async fn is_dir(&self) -> bool { |
797 | fs::metadata(self) |
798 | .await |
799 | .map(|m| m.is_dir()) |
800 | .unwrap_or(false) |
801 | } |
802 | |
803 | /// Converts a [`Box<Path>`][`Box`] into a [`PathBuf`] without copying or |
804 | /// allocating. |
805 | /// |
806 | /// [`Box`]: https://doc.rust-lang.org/std/boxed/struct.Box.html |
807 | /// [`PathBuf`]: struct.PathBuf.html |
808 | /// |
809 | /// # Examples |
810 | /// |
811 | /// ``` |
812 | /// use async_std::path::Path; |
813 | /// |
814 | /// let path: Box<Path> = Path::new("foo.txt" ).into(); |
815 | /// let path_buf = path.into_path_buf(); |
816 | /// ``` |
817 | pub fn into_path_buf(self: Box<Path>) -> PathBuf { |
818 | let rw = Box::into_raw(self) as *mut std::path::Path; |
819 | let inner = unsafe { Box::from_raw(rw) }; |
820 | inner.into_path_buf().into() |
821 | } |
822 | } |
823 | |
824 | impl From<&Path> for Box<Path> { |
825 | fn from(path: &Path) -> Box<Path> { |
826 | let boxed: Box<std::path::Path> = path.inner.into(); |
827 | let rw: *mut Path = Box::into_raw(boxed) as *mut Path; |
828 | unsafe { Box::from_raw(rw) } |
829 | } |
830 | } |
831 | |
832 | impl From<&Path> for Arc<Path> { |
833 | /// Converts a Path into a Rc by copying the Path data into a new Rc buffer. |
834 | #[inline ] |
835 | fn from(s: &Path) -> Arc<Path> { |
836 | let arc: Arc<OsStr> = Arc::from(s.as_os_str()); |
837 | unsafe { Arc::from_raw(ptr:Arc::into_raw(this:arc) as *const Path) } |
838 | } |
839 | } |
840 | |
841 | impl From<&Path> for Rc<Path> { |
842 | #[inline ] |
843 | fn from(s: &Path) -> Rc<Path> { |
844 | let rc: Rc<OsStr> = Rc::from(s.as_os_str()); |
845 | unsafe { Rc::from_raw(ptr:Rc::into_raw(this:rc) as *const Path) } |
846 | } |
847 | } |
848 | |
849 | impl ToOwned for Path { |
850 | type Owned = PathBuf; |
851 | |
852 | fn to_owned(&self) -> PathBuf { |
853 | self.to_path_buf() |
854 | } |
855 | } |
856 | |
857 | impl AsRef<OsStr> for Path { |
858 | fn as_ref(&self) -> &OsStr { |
859 | self.inner.as_ref() |
860 | } |
861 | } |
862 | |
863 | impl AsRef<Path> for Path { |
864 | fn as_ref(&self) -> &Path { |
865 | self |
866 | } |
867 | } |
868 | |
869 | impl AsRef<Path> for OsStr { |
870 | fn as_ref(&self) -> &Path { |
871 | Path::new(self) |
872 | } |
873 | } |
874 | |
875 | impl<'a> From<&'a Path> for Cow<'a, Path> { |
876 | #[inline ] |
877 | fn from(s: &'a Path) -> Cow<'a, Path> { |
878 | Cow::Borrowed(s) |
879 | } |
880 | } |
881 | |
882 | impl AsRef<Path> for Cow<'_, OsStr> { |
883 | fn as_ref(&self) -> &Path { |
884 | Path::new(self) |
885 | } |
886 | } |
887 | |
888 | impl AsRef<Path> for OsString { |
889 | fn as_ref(&self) -> &Path { |
890 | Path::new(self) |
891 | } |
892 | } |
893 | |
894 | impl AsRef<Path> for str { |
895 | fn as_ref(&self) -> &Path { |
896 | Path::new(self) |
897 | } |
898 | } |
899 | |
900 | impl AsRef<Path> for String { |
901 | fn as_ref(&self) -> &Path { |
902 | Path::new(self) |
903 | } |
904 | } |
905 | |
906 | impl AsRef<Path> for PathBuf { |
907 | fn as_ref(&self) -> &Path { |
908 | self |
909 | } |
910 | } |
911 | |
912 | impl<'a> IntoIterator for &'a PathBuf { |
913 | type Item = &'a OsStr; |
914 | type IntoIter = Iter<'a>; |
915 | |
916 | fn into_iter(self) -> Iter<'a> { |
917 | self.iter() |
918 | } |
919 | } |
920 | |
921 | impl<'a> IntoIterator for &'a Path { |
922 | type Item = &'a OsStr; |
923 | type IntoIter = Iter<'a>; |
924 | |
925 | fn into_iter(self) -> Iter<'a> { |
926 | self.iter() |
927 | } |
928 | } |
929 | |
930 | macro_rules! impl_cmp { |
931 | ($lhs:ty, $rhs: ty) => { |
932 | impl<'a, 'b> PartialEq<$rhs> for $lhs { |
933 | #[inline] |
934 | fn eq(&self, other: &$rhs) -> bool { |
935 | <Path as PartialEq>::eq(self, other) |
936 | } |
937 | } |
938 | |
939 | impl<'a, 'b> PartialEq<$lhs> for $rhs { |
940 | #[inline] |
941 | fn eq(&self, other: &$lhs) -> bool { |
942 | <Path as PartialEq>::eq(self, other) |
943 | } |
944 | } |
945 | |
946 | impl<'a, 'b> PartialOrd<$rhs> for $lhs { |
947 | #[inline] |
948 | fn partial_cmp(&self, other: &$rhs) -> Option<Ordering> { |
949 | <Path as PartialOrd>::partial_cmp(self, other) |
950 | } |
951 | } |
952 | |
953 | impl<'a, 'b> PartialOrd<$lhs> for $rhs { |
954 | #[inline] |
955 | fn partial_cmp(&self, other: &$lhs) -> Option<Ordering> { |
956 | <Path as PartialOrd>::partial_cmp(self, other) |
957 | } |
958 | } |
959 | }; |
960 | } |
961 | |
962 | impl_cmp!(PathBuf, Path); |
963 | impl_cmp!(PathBuf, &'a Path); |
964 | impl_cmp!(Cow<'a, Path>, Path); |
965 | impl_cmp!(Cow<'a, Path>, &'b Path); |
966 | impl_cmp!(Cow<'a, Path>, PathBuf); |
967 | |
968 | macro_rules! impl_cmp_os_str { |
969 | ($lhs:ty, $rhs: ty) => { |
970 | impl<'a, 'b> PartialEq<$rhs> for $lhs { |
971 | #[inline] |
972 | fn eq(&self, other: &$rhs) -> bool { |
973 | <Path as PartialEq>::eq(self, other.as_ref()) |
974 | } |
975 | } |
976 | |
977 | impl<'a, 'b> PartialEq<$lhs> for $rhs { |
978 | #[inline] |
979 | fn eq(&self, other: &$lhs) -> bool { |
980 | <Path as PartialEq>::eq(self.as_ref(), other) |
981 | } |
982 | } |
983 | |
984 | impl<'a, 'b> PartialOrd<$rhs> for $lhs { |
985 | #[inline] |
986 | fn partial_cmp(&self, other: &$rhs) -> Option<Ordering> { |
987 | <Path as PartialOrd>::partial_cmp(self, other.as_ref()) |
988 | } |
989 | } |
990 | |
991 | impl<'a, 'b> PartialOrd<$lhs> for $rhs { |
992 | #[inline] |
993 | fn partial_cmp(&self, other: &$lhs) -> Option<Ordering> { |
994 | <Path as PartialOrd>::partial_cmp(self.as_ref(), other) |
995 | } |
996 | } |
997 | }; |
998 | } |
999 | |
1000 | impl_cmp_os_str!(PathBuf, OsStr); |
1001 | impl_cmp_os_str!(PathBuf, &'a OsStr); |
1002 | impl_cmp_os_str!(PathBuf, Cow<'a, OsStr>); |
1003 | impl_cmp_os_str!(PathBuf, OsString); |
1004 | impl_cmp_os_str!(Path, OsStr); |
1005 | impl_cmp_os_str!(Path, &'a OsStr); |
1006 | impl_cmp_os_str!(Path, Cow<'a, OsStr>); |
1007 | impl_cmp_os_str!(Path, OsString); |
1008 | impl_cmp_os_str!(&'a Path, OsStr); |
1009 | impl_cmp_os_str!(&'a Path, Cow<'b, OsStr>); |
1010 | impl_cmp_os_str!(&'a Path, OsString); |
1011 | |
1012 | impl<'a> From<&'a std::path::Path> for &'a Path { |
1013 | fn from(path: &'a std::path::Path) -> &'a Path { |
1014 | &Path::new(path.as_os_str()) |
1015 | } |
1016 | } |
1017 | |
1018 | impl<'a> Into<&'a std::path::Path> for &'a Path { |
1019 | fn into(self) -> &'a std::path::Path { |
1020 | std::path::Path::new(&self.inner) |
1021 | } |
1022 | } |
1023 | |
1024 | impl AsRef<std::path::Path> for Path { |
1025 | fn as_ref(&self) -> &std::path::Path { |
1026 | self.into() |
1027 | } |
1028 | } |
1029 | |
1030 | impl AsRef<Path> for std::path::Path { |
1031 | fn as_ref(&self) -> &Path { |
1032 | self.into() |
1033 | } |
1034 | } |
1035 | |
1036 | impl AsRef<Path> for std::path::PathBuf { |
1037 | fn as_ref(&self) -> &Path { |
1038 | let p: &std::path::Path = self.as_ref(); |
1039 | p.into() |
1040 | } |
1041 | } |
1042 | |