Skip to main content

path_extra/tokio/
path.rs

1#[cfg(unix)]
2use std::os::unix::{self, fs::PermissionsExt as _};
3use std::{
4    borrow::Cow,
5    ffi::OsStr,
6    fs::{Metadata, Permissions},
7    io,
8    path::{self, Path, PathBuf},
9};
10
11#[cfg(unix)]
12use pathdiff::diff_paths;
13#[cfg(unix)]
14use tokio::task;
15use tokio::{
16    fs::{self, File, ReadDir},
17    io::{AsyncBufReadExt as _, AsyncWriteExt as _, BufReader, Lines},
18};
19
20use super::{fs::FileExt as _, temp_path::TempPath};
21
22#[trait_variant::make(Send)]
23pub trait PathExt {
24    fn base(&self) -> io::Result<&Path>;
25    fn with_base(&self, base: impl AsRef<Path>) -> Cow<'_, Path>;
26
27    fn file_suffix(&self) -> Option<&OsStr>;
28
29    fn absolute(&self) -> io::Result<PathBuf>;
30
31    async fn metadata_async(&self) -> io::Result<Metadata>;
32    async fn symlink_metadata_async(&self) -> io::Result<Metadata>;
33    async fn canonicalize_async(&self) -> io::Result<PathBuf>;
34    async fn read_link_async(&self) -> io::Result<PathBuf>;
35    async fn read_dir_async(&self) -> io::Result<ReadDir>;
36
37    async fn exists_async(&self) -> bool;
38    async fn is_file_async(&self) -> bool;
39    async fn is_dir_async(&self) -> bool;
40    async fn is_symlink_async(&self) -> bool;
41
42    async fn try_exists_async(&self) -> io::Result<bool>;
43
44    async fn try_is_file(&self) -> io::Result<bool>;
45    async fn try_is_dir(&self) -> io::Result<bool>;
46    async fn try_is_symlink(&self) -> io::Result<bool>;
47
48    async fn metadata_if_exists(&self) -> io::Result<Option<Metadata>>;
49    async fn symlink_metadata_if_exists(&self) -> io::Result<Option<Metadata>>;
50    async fn canonicalize_if_exists(&self) -> io::Result<Option<PathBuf>>;
51    async fn read_link_if_exists(&self) -> io::Result<Option<PathBuf>>;
52    async fn read_dir_if_exists(&self) -> io::Result<Option<ReadDir>>;
53
54    async fn exists_nofollow(&self) -> bool;
55    async fn is_file_nofollow(&self) -> bool;
56    async fn is_dir_nofollow(&self) -> bool;
57
58    async fn try_exists_nofollow(&self) -> io::Result<bool>;
59    async fn try_is_file_nofollow(&self) -> io::Result<bool>;
60    async fn try_is_dir_nofollow(&self) -> io::Result<bool>;
61
62    async fn try_is_read_dir_empty(&self) -> io::Result<bool>;
63    async fn try_is_read_dir_empty_if_exists(&self) -> io::Result<Option<bool>>;
64
65    async fn create_new(&self) -> io::Result<File>;
66    async fn create_new_if_not_exists(&self) -> io::Result<Option<File>>;
67
68    async fn create(&self) -> io::Result<File>;
69    async fn create_if_not_exists(&self) -> io::Result<Option<File>>;
70
71    async fn open(&self) -> io::Result<File>;
72    async fn open_if_exists(&self) -> io::Result<Option<File>>;
73
74    async fn read(&self) -> io::Result<Vec<u8>>;
75    async fn read_if_exists(&self) -> io::Result<Option<Vec<u8>>>;
76
77    async fn read_to_string(&self) -> io::Result<String>;
78    async fn read_to_string_if_exists(&self) -> io::Result<Option<String>>;
79
80    async fn read_lines(&self) -> io::Result<Lines<BufReader<File>>>;
81    async fn read_lines_if_exists(&self) -> io::Result<Option<Lines<BufReader<File>>>>;
82
83    async fn create_dir_all(self) -> io::Result<Self>
84    where
85        Self: Sized;
86
87    async fn create_dir(self) -> io::Result<Self>
88    where
89        Self: Sized;
90    async fn create_dir_if_not_exists(self) -> io::Result<Option<Self>>
91    where
92        Self: Sized;
93
94    async fn write_new(self, contents: impl AsRef<[u8]> + Send) -> io::Result<Self>
95    where
96        Self: Sized;
97    async fn write_new_if_not_exists(
98        self,
99        contents: impl AsRef<[u8]> + Send,
100    ) -> io::Result<Option<Self>>
101    where
102        Self: Sized;
103
104    async fn write(self, contents: impl AsRef<[u8]> + Send) -> io::Result<Self>
105    where
106        Self: Sized;
107    async fn write_if_exists(self, contents: impl AsRef<[u8]> + Send) -> io::Result<Option<Self>>
108    where
109        Self: Sized;
110
111    async fn append(self, contents: impl AsRef<[u8]> + Send) -> io::Result<Self>
112    where
113        Self: Sized;
114    async fn append_if_exists(self, contents: impl AsRef<[u8]> + Send) -> io::Result<Option<Self>>
115    where
116        Self: Sized;
117
118    async fn copy(self, to: impl AsRef<Path> + Send) -> io::Result<Self>
119    where
120        Self: Sized;
121    async fn copy_if_exists(self, to: impl AsRef<Path> + Send) -> io::Result<Option<Self>>
122    where
123        Self: Sized;
124
125    async fn rename(self, to: impl AsRef<Path> + Send) -> io::Result<Self>
126    where
127        Self: Sized;
128    async fn rename_if_exists(self, to: impl AsRef<Path> + Send) -> io::Result<Option<Self>>
129    where
130        Self: Sized;
131
132    async fn remove_file(self) -> io::Result<Self>
133    where
134        Self: Sized;
135    async fn remove_file_if_exists(self) -> io::Result<Option<Self>>
136    where
137        Self: Sized;
138
139    async fn remove_dir(self) -> io::Result<Self>
140    where
141        Self: Sized;
142    async fn remove_dir_if_exists(self) -> io::Result<Option<Self>>
143    where
144        Self: Sized;
145
146    async fn remove_dir_all(self) -> io::Result<Self>
147    where
148        Self: Sized;
149    async fn remove_dir_all_if_exists(self) -> io::Result<Option<Self>>
150    where
151        Self: Sized;
152
153    async fn hard_link(self, link: impl AsRef<Path> + Send) -> io::Result<Self>
154    where
155        Self: Sized;
156    async fn hard_link_if_exists(self, link: impl AsRef<Path> + Send) -> io::Result<Option<Self>>
157    where
158        Self: Sized;
159    async fn hard_link_atomic(self, link: impl AsRef<Path> + Send) -> io::Result<Self>
160    where
161        Self: Sized;
162    async fn hard_link_atomic_if_exists(
163        self,
164        link: impl AsRef<Path> + Send,
165    ) -> io::Result<Option<Self>>
166    where
167        Self: Sized;
168
169    #[cfg(unix)]
170    async fn symlink(self, link: impl AsRef<Path> + Send) -> io::Result<Self>
171    where
172        Self: Sized;
173    #[cfg(unix)]
174    async fn symlink_atomic(self, link: impl AsRef<Path> + Send) -> io::Result<Self>
175    where
176        Self: Sized;
177
178    #[cfg(unix)]
179    async fn symlink_absolute(self, link: impl AsRef<Path> + Send) -> io::Result<Self>
180    where
181        Self: Sized;
182    #[cfg(unix)]
183    async fn symlink_absolute_atomic(self, link: impl AsRef<Path> + Send) -> io::Result<Self>
184    where
185        Self: Sized;
186
187    #[cfg(unix)]
188    async fn symlink_relative(self, link: impl AsRef<Path> + Send + Sync) -> io::Result<Self>
189    where
190        Self: Sized;
191    #[cfg(unix)]
192    async fn symlink_relative_atomic(
193        self,
194        link: impl AsRef<Path> + Send + Sync,
195    ) -> io::Result<Self>
196    where
197        Self: Sized;
198
199    async fn set_permissions(self, perm: Permissions) -> io::Result<Self>
200    where
201        Self: Sized;
202    async fn set_permissions_if_exists(self, perm: Permissions) -> io::Result<Option<Self>>
203    where
204        Self: Sized;
205
206    async fn set_permissions_readonly(self, readonly: bool) -> io::Result<Self>
207    where
208        Self: Sized;
209    async fn set_permissions_readonly_if_exists(self, readonly: bool) -> io::Result<Option<Self>>
210    where
211        Self: Sized;
212
213    #[cfg(unix)]
214    async fn set_permissions_mode(self, mode: u32) -> io::Result<Self>
215    where
216        Self: Sized;
217    #[cfg(unix)]
218    async fn set_permissions_mode_if_exists(self, mode: u32) -> io::Result<Option<Self>>
219    where
220        Self: Sized;
221    #[cfg(unix)]
222    async fn add_permissions_mode(self, mode: u32) -> io::Result<Self>
223    where
224        Self: Sized;
225    #[cfg(unix)]
226    async fn add_permissions_mode_if_exists(self, mode: u32) -> io::Result<Option<Self>>
227    where
228        Self: Sized;
229    #[cfg(unix)]
230    async fn remove_permissions_mode(self, mode: u32) -> io::Result<Self>
231    where
232        Self: Sized;
233    #[cfg(unix)]
234    async fn remove_permissions_mode_if_exists(self, mode: u32) -> io::Result<Option<Self>>
235    where
236        Self: Sized;
237
238    #[cfg(unix)]
239    async fn chown(self, uid: Option<u32>, gid: Option<u32>) -> io::Result<Self>
240    where
241        Self: Sized;
242    #[cfg(unix)]
243    async fn chown_if_exists(self, uid: Option<u32>, gid: Option<u32>) -> io::Result<Option<Self>>
244    where
245        Self: Sized;
246
247    #[cfg(unix)]
248    async fn chown_nofollow(self, uid: Option<u32>, gid: Option<u32>) -> io::Result<Self>
249    where
250        Self: Sized;
251    #[cfg(unix)]
252    async fn chown_nofollow_if_exists(
253        self,
254        uid: Option<u32>,
255        gid: Option<u32>,
256    ) -> io::Result<Option<Self>>
257    where
258        Self: Sized;
259
260    #[cfg(all(unix, not(target_os = "fuchsia")))]
261    async fn chroot(self) -> io::Result<Self>
262    where
263        Self: Sized;
264    #[cfg(all(unix, not(target_os = "fuchsia")))]
265    async fn chroot_if_exists(self) -> io::Result<Option<Self>>
266    where
267        Self: Sized;
268}
269
270impl<T: AsRef<Path> + Send + Sync> PathExt for T {
271    #[inline]
272    fn base(&self) -> io::Result<&Path> {
273        self.as_ref()
274            .parent()
275            .ok_or_else(|| io::Error::new(io::ErrorKind::InvalidInput, "Path has no parent"))
276    }
277
278    #[inline]
279    fn with_base(&self, base: impl AsRef<Path>) -> Cow<'_, Path> {
280        if self.as_ref().is_relative() {
281            let path = base.as_ref().join(self);
282
283            Cow::Owned(path)
284        } else {
285            Cow::Borrowed(self.as_ref())
286        }
287    }
288
289    #[inline]
290    fn file_suffix(&self) -> Option<&OsStr> {
291        let file_name = self.as_ref().file_name()?;
292        let file_prefix = self.as_ref().file_prefix()?;
293
294        let bytes = file_name.as_encoded_bytes();
295
296        let start = file_prefix.as_encoded_bytes().len() + 1;
297
298        if start <= bytes.len() {
299            let slice = &bytes[start..];
300
301            let os_str = unsafe { OsStr::from_encoded_bytes_unchecked(slice) };
302
303            Some(os_str)
304        } else {
305            None
306        }
307    }
308
309    #[inline]
310    fn absolute(&self) -> io::Result<PathBuf> {
311        path::absolute(self)
312    }
313
314    #[inline]
315    async fn metadata_async(&self) -> io::Result<Metadata> {
316        fs::metadata(self).await
317    }
318
319    #[inline]
320    async fn symlink_metadata_async(&self) -> io::Result<Metadata> {
321        fs::symlink_metadata(self).await
322    }
323
324    #[inline]
325    async fn canonicalize_async(&self) -> io::Result<PathBuf> {
326        fs::canonicalize(self).await
327    }
328
329    #[inline]
330    async fn read_link_async(&self) -> io::Result<PathBuf> {
331        fs::read_link(self).await
332    }
333
334    #[inline]
335    async fn read_dir_async(&self) -> io::Result<ReadDir> {
336        fs::read_dir(self).await
337    }
338
339    #[inline]
340    async fn exists_async(&self) -> bool {
341        self.metadata_async().await.is_ok()
342    }
343
344    #[inline]
345    async fn is_file_async(&self) -> bool {
346        self.metadata_async()
347            .await
348            .map(|meta| meta.is_file())
349            .unwrap_or(false)
350    }
351
352    #[inline]
353    async fn is_dir_async(&self) -> bool {
354        self.metadata_async()
355            .await
356            .map(|meta| meta.is_dir())
357            .unwrap_or(false)
358    }
359
360    #[inline]
361    async fn is_symlink_async(&self) -> bool {
362        self.symlink_metadata_async()
363            .await
364            .map(|meta| meta.is_symlink())
365            .unwrap_or(false)
366    }
367
368    #[inline]
369    async fn try_exists_async(&self) -> io::Result<bool> {
370        fs::try_exists(self).await
371    }
372
373    #[inline]
374    async fn try_is_file(&self) -> io::Result<bool> {
375        self.metadata_if_exists()
376            .await
377            .map(|meta_opt| meta_opt.map(|meta| meta.is_file()).unwrap_or(false))
378    }
379
380    #[inline]
381    async fn try_is_dir(&self) -> io::Result<bool> {
382        self.metadata_if_exists()
383            .await
384            .map(|meta_opt| meta_opt.map(|meta| meta.is_dir()).unwrap_or(false))
385    }
386
387    #[inline]
388    async fn try_is_symlink(&self) -> io::Result<bool> {
389        self.symlink_metadata_if_exists()
390            .await
391            .map(|meta_opt| meta_opt.map(|meta| meta.is_symlink()).unwrap_or(false))
392    }
393
394    #[inline]
395    async fn metadata_if_exists(&self) -> io::Result<Option<Metadata>> {
396        match self.metadata_async().await {
397            Ok(meta) => Ok(Some(meta)),
398            Err(err) if err.kind() == io::ErrorKind::NotFound => Ok(None),
399            Err(err) => Err(err),
400        }
401    }
402
403    #[inline]
404    async fn symlink_metadata_if_exists(&self) -> io::Result<Option<Metadata>> {
405        match self.symlink_metadata_async().await {
406            Ok(meta) => Ok(Some(meta)),
407            Err(err) if err.kind() == io::ErrorKind::NotFound => Ok(None),
408            Err(err) => Err(err),
409        }
410    }
411
412    #[inline]
413    async fn canonicalize_if_exists(&self) -> io::Result<Option<PathBuf>> {
414        match self.canonicalize_async().await {
415            Ok(path) => Ok(Some(path)),
416            Err(err) if err.kind() == io::ErrorKind::NotFound => Ok(None),
417            Err(err) => Err(err),
418        }
419    }
420
421    #[inline]
422    async fn read_link_if_exists(&self) -> io::Result<Option<PathBuf>> {
423        match self.read_link_async().await {
424            Ok(path) => Ok(Some(path)),
425            Err(err) if err.kind() == io::ErrorKind::NotFound => Ok(None),
426            Err(err) => Err(err),
427        }
428    }
429
430    #[inline]
431    async fn read_dir_if_exists(&self) -> io::Result<Option<ReadDir>> {
432        match self.read_dir_async().await {
433            Ok(entries) => Ok(Some(entries)),
434            Err(err) if err.kind() == io::ErrorKind::NotFound => Ok(None),
435            Err(err) => Err(err),
436        }
437    }
438
439    #[inline]
440    async fn exists_nofollow(&self) -> bool {
441        self.symlink_metadata_async().await.is_ok()
442    }
443
444    #[inline]
445    async fn is_file_nofollow(&self) -> bool {
446        self.symlink_metadata_async()
447            .await
448            .map(|meta| meta.is_file())
449            .unwrap_or(false)
450    }
451
452    #[inline]
453    async fn is_dir_nofollow(&self) -> bool {
454        self.symlink_metadata_async()
455            .await
456            .map(|meta| meta.is_dir())
457            .unwrap_or(false)
458    }
459
460    #[inline]
461    async fn try_exists_nofollow(&self) -> io::Result<bool> {
462        self.symlink_metadata_if_exists()
463            .await
464            .map(|meta_opt| meta_opt.is_some())
465    }
466
467    #[inline]
468    async fn try_is_file_nofollow(&self) -> io::Result<bool> {
469        self.symlink_metadata_if_exists()
470            .await
471            .map(|meta_opt| meta_opt.map(|meta| meta.is_file()).unwrap_or(false))
472    }
473
474    #[inline]
475    async fn try_is_dir_nofollow(&self) -> io::Result<bool> {
476        self.symlink_metadata_if_exists()
477            .await
478            .map(|meta_opt| meta_opt.map(|meta| meta.is_dir()).unwrap_or(false))
479    }
480
481    #[inline]
482    async fn try_is_read_dir_empty(&self) -> io::Result<bool> {
483        let mut entries = self.read_dir_async().await?;
484
485        entries
486            .next_entry()
487            .await
488            .map(|entry_opt| entry_opt.is_none())
489    }
490
491    #[inline]
492    async fn try_is_read_dir_empty_if_exists(&self) -> io::Result<Option<bool>> {
493        match self.try_is_read_dir_empty().await {
494            Ok(is_empty) => Ok(Some(is_empty)),
495            Err(err) if err.kind() == io::ErrorKind::NotFound => Ok(None),
496            Err(err) => Err(err),
497        }
498    }
499
500    #[inline]
501    async fn create_new(&self) -> io::Result<File> {
502        File::create_new(self).await
503    }
504
505    #[inline]
506    async fn create_new_if_not_exists(&self) -> io::Result<Option<File>> {
507        File::create_new_if_not_exists(self).await
508    }
509
510    #[inline]
511    async fn create(&self) -> io::Result<File> {
512        File::create(self).await
513    }
514
515    #[inline]
516    async fn create_if_not_exists(&self) -> io::Result<Option<File>> {
517        File::create_if_not_exists(self).await
518    }
519
520    #[inline]
521    async fn open(&self) -> io::Result<File> {
522        File::open(self).await
523    }
524
525    #[inline]
526    async fn open_if_exists(&self) -> io::Result<Option<File>> {
527        File::open_if_exists(self).await
528    }
529
530    #[inline]
531    async fn read(&self) -> io::Result<Vec<u8>> {
532        fs::read(self).await
533    }
534
535    #[inline]
536    async fn read_if_exists(&self) -> io::Result<Option<Vec<u8>>> {
537        match self.read().await {
538            Ok(bytes) => Ok(Some(bytes)),
539            Err(err) if err.kind() == io::ErrorKind::NotFound => Ok(None),
540            Err(err) => Err(err),
541        }
542    }
543
544    #[inline]
545    async fn read_to_string(&self) -> io::Result<String> {
546        fs::read_to_string(self).await
547    }
548
549    #[inline]
550    async fn read_to_string_if_exists(&self) -> io::Result<Option<String>> {
551        match self.read_to_string().await {
552            Ok(string) => Ok(Some(string)),
553            Err(err) if err.kind() == io::ErrorKind::NotFound => Ok(None),
554            Err(err) => Err(err),
555        }
556    }
557
558    #[inline]
559    async fn read_lines(&self) -> io::Result<Lines<BufReader<File>>> {
560        let file = self.open().await?;
561
562        let buf_reader = BufReader::new(file);
563
564        let lines = buf_reader.lines();
565
566        Ok(lines)
567    }
568
569    #[inline]
570    async fn read_lines_if_exists(&self) -> io::Result<Option<Lines<BufReader<File>>>> {
571        match self.read_lines().await {
572            Ok(lines) => Ok(Some(lines)),
573            Err(err) if err.kind() == io::ErrorKind::NotFound => Ok(None),
574            Err(err) => Err(err),
575        }
576    }
577
578    #[inline]
579    async fn create_dir_all(self) -> io::Result<Self> {
580        fs::create_dir_all(self.as_ref()).await?;
581
582        Ok(self)
583    }
584
585    #[inline]
586    async fn create_dir(self) -> io::Result<Self> {
587        fs::create_dir(self.as_ref()).await?;
588
589        Ok(self)
590    }
591
592    #[inline]
593    async fn create_dir_if_not_exists(self) -> io::Result<Option<Self>> {
594        match self.as_ref().create_dir().await {
595            Ok(_) => Ok(Some(self)),
596            Err(err) if err.kind() == io::ErrorKind::AlreadyExists => Ok(None),
597            Err(err) => Err(err),
598        }
599    }
600
601    #[inline]
602    async fn write_new(self, contents: impl AsRef<[u8]> + Send) -> io::Result<Self> {
603        let mut options = File::options();
604
605        options.write(true).create_new(true);
606
607        let mut file = options.open(self.as_ref()).await?;
608
609        file.write_all(contents.as_ref()).await?;
610
611        Ok(self)
612    }
613
614    #[inline]
615    async fn write_new_if_not_exists(
616        self,
617        contents: impl AsRef<[u8]> + Send,
618    ) -> io::Result<Option<Self>> {
619        match self.as_ref().write_new(contents).await {
620            Ok(_) => Ok(Some(self)),
621            Err(err) if err.kind() == io::ErrorKind::AlreadyExists => Ok(None),
622            Err(err) => Err(err),
623        }
624    }
625
626    #[inline]
627    async fn write(self, contents: impl AsRef<[u8]> + Send) -> io::Result<Self> {
628        fs::write(self.as_ref(), contents).await?;
629
630        Ok(self)
631    }
632
633    #[inline]
634    async fn write_if_exists(self, contents: impl AsRef<[u8]> + Send) -> io::Result<Option<Self>> {
635        let mut options = File::options();
636
637        options.write(true).truncate(true);
638
639        match options.open(self.as_ref()).await {
640            Ok(mut file) => {
641                file.write_all(contents.as_ref()).await?;
642
643                Ok(Some(self))
644            },
645            Err(err) if err.kind() == io::ErrorKind::NotFound => Ok(None),
646            Err(err) => Err(err),
647        }
648    }
649
650    #[inline]
651    async fn append(self, contents: impl AsRef<[u8]> + Send) -> io::Result<Self> {
652        let mut options = File::options();
653
654        options.append(true).create(true);
655
656        let mut file = options.open(self.as_ref()).await?;
657
658        file.write_all(contents.as_ref()).await?;
659
660        Ok(self)
661    }
662
663    #[inline]
664    async fn append_if_exists(self, contents: impl AsRef<[u8]> + Send) -> io::Result<Option<Self>> {
665        let mut options = File::options();
666
667        options.append(true);
668
669        match options.open(self.as_ref()).await {
670            Ok(mut file) => {
671                file.write_all(contents.as_ref()).await?;
672
673                Ok(Some(self))
674            },
675            Err(err) if err.kind() == io::ErrorKind::NotFound => Ok(None),
676            Err(err) => Err(err),
677        }
678    }
679
680    #[inline]
681    async fn copy(self, to: impl AsRef<Path> + Send) -> io::Result<Self> {
682        fs::copy(self.as_ref(), to).await?;
683
684        Ok(self)
685    }
686
687    #[inline]
688    async fn copy_if_exists(self, to: impl AsRef<Path> + Send) -> io::Result<Option<Self>> {
689        match self.as_ref().copy(to).await {
690            Ok(_) => Ok(Some(self)),
691            Err(err) if err.kind() == io::ErrorKind::NotFound => {
692                if !self.try_exists_async().await? {
693                    Ok(None)
694                } else {
695                    Err(err)
696                }
697            },
698            Err(err) => Err(err),
699        }
700    }
701
702    #[inline]
703    async fn rename(self, to: impl AsRef<Path> + Send) -> io::Result<Self> {
704        fs::rename(self.as_ref(), to).await?;
705
706        Ok(self)
707    }
708
709    #[inline]
710    async fn rename_if_exists(self, to: impl AsRef<Path> + Send) -> io::Result<Option<Self>> {
711        match self.as_ref().rename(to).await {
712            Ok(_) => Ok(Some(self)),
713            Err(err) if err.kind() == io::ErrorKind::NotFound => {
714                if !self.try_exists_nofollow().await? {
715                    Ok(None)
716                } else {
717                    Err(err)
718                }
719            },
720            Err(err) => Err(err),
721        }
722    }
723
724    #[inline]
725    async fn remove_file(self) -> io::Result<Self> {
726        fs::remove_file(self.as_ref()).await?;
727
728        Ok(self)
729    }
730
731    #[inline]
732    async fn remove_file_if_exists(self) -> io::Result<Option<Self>> {
733        match self.as_ref().remove_file().await {
734            Ok(_) => Ok(Some(self)),
735            Err(err) if err.kind() == io::ErrorKind::NotFound => Ok(None),
736            Err(err) => Err(err),
737        }
738    }
739
740    #[inline]
741    async fn remove_dir(self) -> io::Result<Self> {
742        fs::remove_dir(self.as_ref()).await?;
743
744        Ok(self)
745    }
746
747    #[inline]
748    async fn remove_dir_if_exists(self) -> io::Result<Option<Self>> {
749        match self.as_ref().remove_dir().await {
750            Ok(_) => Ok(Some(self)),
751            Err(err) if err.kind() == io::ErrorKind::NotFound => Ok(None),
752            Err(err) => Err(err),
753        }
754    }
755
756    #[inline]
757    async fn remove_dir_all(self) -> io::Result<Self> {
758        fs::remove_dir_all(self.as_ref()).await?;
759
760        Ok(self)
761    }
762
763    #[inline]
764    async fn remove_dir_all_if_exists(self) -> io::Result<Option<Self>> {
765        match self.as_ref().remove_dir_all().await {
766            Ok(_) => Ok(Some(self)),
767            Err(err) if err.kind() == io::ErrorKind::NotFound => Ok(None),
768            Err(err) => Err(err),
769        }
770    }
771
772    #[inline]
773    async fn hard_link(self, link: impl AsRef<Path> + Send) -> io::Result<Self> {
774        fs::hard_link(self.as_ref(), link).await?;
775
776        Ok(self)
777    }
778
779    #[inline]
780    async fn hard_link_if_exists(self, link: impl AsRef<Path> + Send) -> io::Result<Option<Self>> {
781        match self.as_ref().hard_link(link).await {
782            Ok(_) => Ok(Some(self)),
783            Err(err) if err.kind() == io::ErrorKind::NotFound => {
784                if !self.try_exists_nofollow().await? {
785                    Ok(None)
786                } else {
787                    Err(err)
788                }
789            },
790            Err(err) => Err(err),
791        }
792    }
793
794    #[inline]
795    async fn hard_link_atomic(self, link: impl AsRef<Path> + Send) -> io::Result<Self> {
796        let temp = TempPath::try_from_path(link.as_ref())?;
797
798        self.as_ref().hard_link(temp.path()).await?;
799
800        temp.persist(link).await?;
801
802        Ok(self)
803    }
804
805    #[inline]
806    async fn hard_link_atomic_if_exists(
807        self,
808        link: impl AsRef<Path> + Send,
809    ) -> io::Result<Option<Self>> {
810        match self.as_ref().hard_link_atomic(link).await {
811            Ok(_) => Ok(Some(self)),
812            Err(err) if err.kind() == io::ErrorKind::NotFound => {
813                if !self.try_exists_nofollow().await? {
814                    Ok(None)
815                } else {
816                    Err(err)
817                }
818            },
819            Err(err) => Err(err),
820        }
821    }
822
823    #[cfg(unix)]
824    #[inline]
825    async fn symlink(self, link: impl AsRef<Path> + Send) -> io::Result<Self> {
826        fs::symlink(self.as_ref(), link).await?;
827
828        Ok(self)
829    }
830
831    #[cfg(unix)]
832    #[inline]
833    async fn symlink_atomic(self, link: impl AsRef<Path> + Send) -> io::Result<Self> {
834        let temp = TempPath::try_from_path(link.as_ref())?;
835
836        self.as_ref().symlink(temp.path()).await?;
837
838        temp.persist(link).await?;
839
840        Ok(self)
841    }
842
843    #[cfg(unix)]
844    #[inline]
845    async fn symlink_absolute(self, link: impl AsRef<Path> + Send) -> io::Result<Self> {
846        #[expect(unstable_name_collisions)]
847        let absolute = self.as_ref().absolute()?;
848
849        absolute.symlink(link).await?;
850
851        Ok(self)
852    }
853
854    #[cfg(unix)]
855    #[inline]
856    async fn symlink_absolute_atomic(self, link: impl AsRef<Path> + Send) -> io::Result<Self> {
857        #[expect(unstable_name_collisions)]
858        let absolute = self.as_ref().absolute()?;
859
860        absolute.symlink_atomic(link).await?;
861
862        Ok(self)
863    }
864
865    #[cfg(unix)]
866    #[inline]
867    async fn symlink_relative(self, link: impl AsRef<Path> + Send + Sync) -> io::Result<Self> {
868        let base = link.base()?;
869
870        let relative = diff_paths(self.as_ref(), base)
871            .ok_or_else(|| io::Error::new(io::ErrorKind::InvalidInput, "Failed to diff paths"))?;
872
873        relative.symlink(link).await?;
874
875        Ok(self)
876    }
877
878    #[cfg(unix)]
879    #[inline]
880    async fn symlink_relative_atomic(
881        self,
882        link: impl AsRef<Path> + Send + Sync,
883    ) -> io::Result<Self> {
884        let base = link.base()?;
885
886        let relative = diff_paths(self.as_ref(), base)
887            .ok_or_else(|| io::Error::new(io::ErrorKind::InvalidInput, "Failed to diff paths"))?;
888
889        relative.symlink_atomic(link).await?;
890
891        Ok(self)
892    }
893
894    #[inline]
895    async fn set_permissions(self, perm: Permissions) -> io::Result<Self> {
896        fs::set_permissions(self.as_ref(), perm).await?;
897
898        Ok(self)
899    }
900
901    #[inline]
902    async fn set_permissions_if_exists(self, perm: Permissions) -> io::Result<Option<Self>> {
903        match self.as_ref().set_permissions(perm).await {
904            Ok(_) => Ok(Some(self)),
905            Err(err) if err.kind() == io::ErrorKind::NotFound => Ok(None),
906            Err(err) => Err(err),
907        }
908    }
909
910    #[inline]
911    async fn set_permissions_readonly(self, readonly: bool) -> io::Result<Self> {
912        let meta = self.metadata_async().await?;
913
914        let mut perm = meta.permissions();
915
916        perm.set_readonly(readonly);
917
918        self.set_permissions(perm).await
919    }
920
921    #[inline]
922    async fn set_permissions_readonly_if_exists(self, readonly: bool) -> io::Result<Option<Self>> {
923        match self.as_ref().set_permissions_readonly(readonly).await {
924            Ok(_) => Ok(Some(self)),
925            Err(err) if err.kind() == io::ErrorKind::NotFound => Ok(None),
926            Err(err) => Err(err),
927        }
928    }
929
930    #[cfg(unix)]
931    #[inline]
932    async fn set_permissions_mode(self, mode: u32) -> io::Result<Self> {
933        let perm = Permissions::from_mode(mode);
934
935        self.set_permissions(perm).await
936    }
937
938    #[cfg(unix)]
939    #[inline]
940    async fn set_permissions_mode_if_exists(self, mode: u32) -> io::Result<Option<Self>> {
941        match self.as_ref().set_permissions_mode(mode).await {
942            Ok(_) => Ok(Some(self)),
943            Err(err) if err.kind() == io::ErrorKind::NotFound => Ok(None),
944            Err(err) => Err(err),
945        }
946    }
947
948    #[cfg(unix)]
949    #[inline]
950    async fn add_permissions_mode(self, mode: u32) -> io::Result<Self> {
951        let meta = self.metadata_async().await?;
952
953        let perm = meta.permissions();
954
955        self.set_permissions_mode(perm.mode() | mode).await
956    }
957
958    #[cfg(unix)]
959    #[inline]
960    async fn add_permissions_mode_if_exists(self, mode: u32) -> io::Result<Option<Self>> {
961        match self.as_ref().add_permissions_mode(mode).await {
962            Ok(_) => Ok(Some(self)),
963            Err(err) if err.kind() == io::ErrorKind::NotFound => Ok(None),
964            Err(err) => Err(err),
965        }
966    }
967
968    #[cfg(unix)]
969    #[inline]
970    async fn remove_permissions_mode(self, mode: u32) -> io::Result<Self> {
971        let meta = self.metadata_async().await?;
972
973        let perm = meta.permissions();
974
975        self.set_permissions_mode(perm.mode() & !mode).await
976    }
977
978    #[cfg(unix)]
979    #[inline]
980    async fn remove_permissions_mode_if_exists(self, mode: u32) -> io::Result<Option<Self>> {
981        match self.as_ref().remove_permissions_mode(mode).await {
982            Ok(_) => Ok(Some(self)),
983            Err(err) if err.kind() == io::ErrorKind::NotFound => Ok(None),
984            Err(err) => Err(err),
985        }
986    }
987
988    #[cfg(unix)]
989    #[inline]
990    async fn chown(self, uid: Option<u32>, gid: Option<u32>) -> io::Result<Self> {
991        let this = self.as_ref().to_owned();
992
993        task::spawn_blocking(move || unix::fs::chown(this, uid, gid)).await??;
994
995        Ok(self)
996    }
997
998    #[cfg(unix)]
999    #[inline]
1000    async fn chown_if_exists(self, uid: Option<u32>, gid: Option<u32>) -> io::Result<Option<Self>> {
1001        match self.as_ref().chown(uid, gid).await {
1002            Ok(_) => Ok(Some(self)),
1003            Err(err) if err.kind() == io::ErrorKind::NotFound => Ok(None),
1004            Err(err) => Err(err),
1005        }
1006    }
1007
1008    #[cfg(unix)]
1009    #[inline]
1010    async fn chown_nofollow(self, uid: Option<u32>, gid: Option<u32>) -> io::Result<Self> {
1011        let this = self.as_ref().to_owned();
1012
1013        task::spawn_blocking(move || unix::fs::lchown(this, uid, gid)).await??;
1014
1015        Ok(self)
1016    }
1017
1018    #[cfg(unix)]
1019    #[inline]
1020    async fn chown_nofollow_if_exists(
1021        self,
1022        uid: Option<u32>,
1023        gid: Option<u32>,
1024    ) -> io::Result<Option<Self>> {
1025        match self.as_ref().chown_nofollow(uid, gid).await {
1026            Ok(_) => Ok(Some(self)),
1027            Err(err) if err.kind() == io::ErrorKind::NotFound => Ok(None),
1028            Err(err) => Err(err),
1029        }
1030    }
1031
1032    #[cfg(all(unix, not(target_os = "fuchsia")))]
1033    #[inline]
1034    async fn chroot(self) -> io::Result<Self> {
1035        let this = self.as_ref().to_owned();
1036
1037        task::spawn_blocking(|| unix::fs::chroot(this)).await??;
1038
1039        Ok(self)
1040    }
1041
1042    #[cfg(all(unix, not(target_os = "fuchsia")))]
1043    #[inline]
1044    async fn chroot_if_exists(self) -> io::Result<Option<Self>> {
1045        match self.as_ref().chroot().await {
1046            Ok(_) => Ok(Some(self)),
1047            Err(err) if err.kind() == io::ErrorKind::NotFound => Ok(None),
1048            Err(err) => Err(err),
1049        }
1050    }
1051}
1052
1053macro_rules! define_option_path_ext {
1054    (
1055        $(
1056            $(#[$meta:meta])*
1057            async fn $method:ident(self $(, $arg:ident: $ty:ty)* $(,)*) -> $ret:ty;
1058        )*
1059    ) => {
1060        #[trait_variant::make(Send)]
1061        pub trait OptionPathExt<T> {
1062            $(
1063                $(#[$meta])*
1064                async fn $method(self $(, $arg: $ty)*) -> $ret;
1065            )*
1066        }
1067
1068        impl<T: PathExt> OptionPathExt<T> for Option<T> {
1069            $(
1070                #[inline]
1071                $(#[$meta])*
1072                async fn $method(self $(, $arg: $ty)*) -> $ret {
1073                    match self {
1074                        Some(path) => path.$method($($arg),*).await.map(Some),
1075                        None => Ok(None),
1076                    }
1077                }
1078            )*
1079        }
1080    };
1081}
1082
1083define_option_path_ext! {
1084    async fn metadata_async(self) -> io::Result<Option<Metadata>>;
1085    async fn symlink_metadata_async(self) -> io::Result<Option<Metadata>>;
1086    async fn canonicalize_async(self) -> io::Result<Option<PathBuf>>;
1087    async fn read_link_async(self) -> io::Result<Option<PathBuf>>;
1088    async fn read_dir_async(self) -> io::Result<Option<ReadDir>>;
1089
1090    async fn try_exists_async(self) -> io::Result<Option<bool>>;
1091
1092    async fn try_is_file(self) -> io::Result<Option<bool>>;
1093    async fn try_is_dir(self) -> io::Result<Option<bool>>;
1094    async fn try_is_symlink(self) -> io::Result<Option<bool>>;
1095
1096    async fn try_exists_nofollow(self) -> io::Result<Option<bool>>;
1097    async fn try_is_file_nofollow(self) -> io::Result<Option<bool>>;
1098    async fn try_is_dir_nofollow(self) -> io::Result<Option<bool>>;
1099
1100    async fn try_is_read_dir_empty(self) -> io::Result<Option<bool>>;
1101
1102    async fn create_new(self) -> io::Result<Option<File>>;
1103
1104    async fn create(self) -> io::Result<Option<File>>;
1105
1106    async fn open(self) -> io::Result<Option<File>>;
1107
1108    async fn read(self) -> io::Result<Option<Vec<u8>>>;
1109
1110    async fn read_to_string(self) -> io::Result<Option<String>>;
1111
1112    async fn read_lines(self) -> io::Result<Option<Lines<BufReader<File>>>>;
1113
1114    async fn create_dir_all(self) -> io::Result<Option<T>>;
1115
1116    async fn create_dir(self) -> io::Result<Option<T>>;
1117
1118    async fn write_new(self, contents: impl AsRef<[u8]> + Send) -> io::Result<Option<T>>;
1119
1120    async fn write(self, contents: impl AsRef<[u8]> + Send) -> io::Result<Option<T>>;
1121
1122    async fn append(self, contents: impl AsRef<[u8]> + Send) -> io::Result<Option<T>>;
1123
1124    async fn copy(self, to: impl AsRef<Path> + Send) -> io::Result<Option<T>>;
1125
1126    async fn rename(self, to: impl AsRef<Path> + Send) -> io::Result<Option<T>>;
1127
1128    async fn remove_file(self) -> io::Result<Option<T>>;
1129
1130    async fn remove_dir(self) -> io::Result<Option<T>>;
1131
1132    async fn remove_dir_all(self) -> io::Result<Option<T>>;
1133
1134    async fn hard_link(self, link: impl AsRef<Path> + Send) -> io::Result<Option<T>>;
1135    async fn hard_link_atomic(self, link: impl AsRef<Path> + Send) -> io::Result<Option<T>>;
1136
1137    #[cfg(unix)]
1138    async fn symlink(self, link: impl AsRef<Path> + Send) -> io::Result<Option<T>>;
1139    #[cfg(unix)]
1140    async fn symlink_atomic(self, link: impl AsRef<Path> + Send) -> io::Result<Option<T>>;
1141
1142    #[cfg(unix)]
1143    async fn symlink_absolute(self, link: impl AsRef<Path> + Send) -> io::Result<Option<T>>;
1144    #[cfg(unix)]
1145    async fn symlink_absolute_atomic(self, link: impl AsRef<Path> + Send) -> io::Result<Option<T>>;
1146
1147    #[cfg(unix)]
1148    async fn symlink_relative(self, link: impl AsRef<Path> + Send + Sync) -> io::Result<Option<T>>;
1149    #[cfg(unix)]
1150    async fn symlink_relative_atomic(
1151        self,
1152        link: impl AsRef<Path> + Send + Sync,
1153    ) -> io::Result<Option<T>>;
1154
1155    async fn set_permissions(self, perm: Permissions) -> io::Result<Option<T>>;
1156
1157    async fn set_permissions_readonly(self, readonly: bool) -> io::Result<Option<T>>;
1158
1159    #[cfg(unix)]
1160    async fn set_permissions_mode(self, mode: u32) -> io::Result<Option<T>>;
1161    #[cfg(unix)]
1162    async fn add_permissions_mode(self, mode: u32) -> io::Result<Option<T>>;
1163    #[cfg(unix)]
1164    async fn remove_permissions_mode(self, mode: u32) -> io::Result<Option<T>>;
1165
1166    #[cfg(unix)]
1167    async fn chown(self, uid: Option<u32>, gid: Option<u32>) -> io::Result<Option<T>>;
1168
1169    #[cfg(unix)]
1170    async fn chown_nofollow(self, uid: Option<u32>, gid: Option<u32>) -> io::Result<Option<T>>;
1171
1172    #[cfg(all(unix, not(target_os = "fuchsia")))]
1173    async fn chroot(self) -> io::Result<Option<T>>;
1174}
1175
1176macro_rules! define_async_path_ext {
1177    (
1178        $(
1179            $(#[$meta:meta])*
1180            async fn $method:ident(self $(, $arg:ident: $ty:ty)* $(,)*) -> $ret:ty;
1181        )*
1182    ) => {
1183        #[trait_variant::make(Send)]
1184        pub trait AsyncPathExt<T: PathExt>: Future<Output = io::Result<T>> {
1185            $(
1186                $(#[$meta])*
1187                async fn $method(self $(, $arg: $ty)*) -> $ret;
1188            )*
1189        }
1190
1191        impl<T: PathExt, F: Future<Output = io::Result<T>> + Send> AsyncPathExt<T> for F {
1192            $(
1193                #[inline]
1194                $(#[$meta])*
1195                async fn $method(self $(, $arg: $ty)*) -> $ret {
1196                    let path = self.await?;
1197
1198                    path.$method($($arg),*).await
1199                }
1200            )*
1201        }
1202    };
1203}
1204
1205define_async_path_ext! {
1206    async fn metadata_async(self) -> io::Result<Metadata>;
1207    async fn symlink_metadata_async(self) -> io::Result<Metadata>;
1208    async fn canonicalize_async(self) -> io::Result<PathBuf>;
1209    async fn read_link_async(self) -> io::Result<PathBuf>;
1210    async fn read_dir_async(self) -> io::Result<ReadDir>;
1211
1212    async fn try_exists_async(self) -> io::Result<bool>;
1213
1214    async fn try_is_file(self) -> io::Result<bool>;
1215    async fn try_is_dir(self) -> io::Result<bool>;
1216    async fn try_is_symlink(self) -> io::Result<bool>;
1217
1218    async fn metadata_if_exists(self) -> io::Result<Option<Metadata>>;
1219    async fn symlink_metadata_if_exists(self) -> io::Result<Option<Metadata>>;
1220    async fn canonicalize_if_exists(self) -> io::Result<Option<PathBuf>>;
1221    async fn read_link_if_exists(self) -> io::Result<Option<PathBuf>>;
1222    async fn read_dir_if_exists(self) -> io::Result<Option<ReadDir>>;
1223
1224    async fn try_exists_nofollow(self) -> io::Result<bool>;
1225    async fn try_is_file_nofollow(self) -> io::Result<bool>;
1226    async fn try_is_dir_nofollow(self) -> io::Result<bool>;
1227
1228    async fn try_is_read_dir_empty(self) -> io::Result<bool>;
1229    async fn try_is_read_dir_empty_if_exists(self) -> io::Result<Option<bool>>;
1230
1231    async fn create_new(self) -> io::Result<File>;
1232    async fn create_new_if_not_exists(self) -> io::Result<Option<File>>;
1233
1234    async fn create(self) -> io::Result<File>;
1235    async fn create_if_not_exists(self) -> io::Result<Option<File>>;
1236
1237    async fn open(self) -> io::Result<File>;
1238    async fn open_if_exists(self) -> io::Result<Option<File>>;
1239
1240    async fn read(self) -> io::Result<Vec<u8>>;
1241    async fn read_if_exists(self) -> io::Result<Option<Vec<u8>>>;
1242
1243    async fn read_to_string(self) -> io::Result<String>;
1244    async fn read_to_string_if_exists(self) -> io::Result<Option<String>>;
1245
1246    async fn read_lines(self) -> io::Result<Lines<BufReader<File>>>;
1247    async fn read_lines_if_exists(self) -> io::Result<Option<Lines<BufReader<File>>>>;
1248
1249    async fn create_dir_all(self) -> io::Result<T>;
1250
1251    async fn create_dir(self) -> io::Result<T>;
1252    async fn create_dir_if_not_exists(self) -> io::Result<Option<T>>;
1253
1254    async fn write_new(self, contents: impl AsRef<[u8]> + Send) -> io::Result<T>;
1255    async fn write_new_if_not_exists(
1256        self,
1257        contents: impl AsRef<[u8]> + Send,
1258    ) -> io::Result<Option<T>>;
1259
1260    async fn write(self, contents: impl AsRef<[u8]> + Send) -> io::Result<T>;
1261    async fn write_if_exists(self, contents: impl AsRef<[u8]> + Send) -> io::Result<Option<T>>;
1262
1263    async fn append(self, contents: impl AsRef<[u8]> + Send) -> io::Result<T>;
1264    async fn append_if_exists(self, contents: impl AsRef<[u8]> + Send) -> io::Result<Option<T>>;
1265
1266    async fn copy(self, to: impl AsRef<Path> + Send) -> io::Result<T>;
1267    async fn copy_if_exists(self, to: impl AsRef<Path> + Send) -> io::Result<Option<T>>;
1268
1269    async fn rename(self, to: impl AsRef<Path> + Send) -> io::Result<T>;
1270    async fn rename_if_exists(self, to: impl AsRef<Path> + Send) -> io::Result<Option<T>>;
1271
1272    async fn remove_file(self) -> io::Result<T>;
1273    async fn remove_file_if_exists(self) -> io::Result<Option<T>>;
1274
1275    async fn remove_dir(self) -> io::Result<T>;
1276    async fn remove_dir_if_exists(self) -> io::Result<Option<T>>;
1277
1278    async fn remove_dir_all(self) -> io::Result<T>;
1279    async fn remove_dir_all_if_exists(self) -> io::Result<Option<T>>;
1280
1281    async fn hard_link(self, link: impl AsRef<Path> + Send) -> io::Result<T>;
1282    async fn hard_link_if_exists(self, link: impl AsRef<Path> + Send) -> io::Result<Option<T>>;
1283    async fn hard_link_atomic(self, link: impl AsRef<Path> + Send) -> io::Result<T>;
1284    async fn hard_link_atomic_if_exists(
1285        self,
1286        link: impl AsRef<Path> + Send,
1287    ) -> io::Result<Option<T>>;
1288
1289    #[cfg(unix)]
1290    async fn symlink(self, link: impl AsRef<Path> + Send) -> io::Result<T>;
1291    #[cfg(unix)]
1292    async fn symlink_atomic(self, link: impl AsRef<Path> + Send) -> io::Result<T>;
1293
1294    #[cfg(unix)]
1295    async fn symlink_absolute(self, link: impl AsRef<Path> + Send) -> io::Result<T>;
1296    #[cfg(unix)]
1297    async fn symlink_absolute_atomic(self, link: impl AsRef<Path> + Send) -> io::Result<T>;
1298
1299    #[cfg(unix)]
1300    async fn symlink_relative(self, link: impl AsRef<Path> + Send + Sync) -> io::Result<T>;
1301    #[cfg(unix)]
1302    async fn symlink_relative_atomic(self, link: impl AsRef<Path> + Send + Sync) -> io::Result<T>;
1303
1304    async fn set_permissions(self, perm: Permissions) -> io::Result<T>;
1305    async fn set_permissions_if_exists(self, perm: Permissions) -> io::Result<Option<T>>;
1306
1307    async fn set_permissions_readonly(self, readonly: bool) -> io::Result<T>;
1308    async fn set_permissions_readonly_if_exists(self, readonly: bool) -> io::Result<Option<T>>;
1309
1310    #[cfg(unix)]
1311    async fn set_permissions_mode(self, mode: u32) -> io::Result<T>;
1312    #[cfg(unix)]
1313    async fn set_permissions_mode_if_exists(self, mode: u32) -> io::Result<Option<T>>;
1314    #[cfg(unix)]
1315    async fn add_permissions_mode(self, mode: u32) -> io::Result<T>;
1316    #[cfg(unix)]
1317    async fn add_permissions_mode_if_exists(self, mode: u32) -> io::Result<Option<T>>;
1318    #[cfg(unix)]
1319    async fn remove_permissions_mode(self, mode: u32) -> io::Result<T>;
1320    #[cfg(unix)]
1321    async fn remove_permissions_mode_if_exists(self, mode: u32) -> io::Result<Option<T>>;
1322
1323    #[cfg(unix)]
1324    async fn chown(self, uid: Option<u32>, gid: Option<u32>) -> io::Result<T>;
1325    #[cfg(unix)]
1326    async fn chown_if_exists(self, uid: Option<u32>, gid: Option<u32>) -> io::Result<Option<T>>;
1327
1328    #[cfg(unix)]
1329    async fn chown_nofollow(self, uid: Option<u32>, gid: Option<u32>) -> io::Result<T>;
1330    #[cfg(unix)]
1331    async fn chown_nofollow_if_exists(
1332        self,
1333        uid: Option<u32>,
1334        gid: Option<u32>,
1335    ) -> io::Result<Option<T>>;
1336
1337    #[cfg(all(unix, not(target_os = "fuchsia")))]
1338    async fn chroot(self) -> io::Result<T>;
1339    #[cfg(all(unix, not(target_os = "fuchsia")))]
1340    async fn chroot_if_exists(self) -> io::Result<Option<T>>;
1341}
1342
1343macro_rules! define_async_option_path_ext {
1344    (
1345        $(
1346            $(#[$meta:meta])*
1347            async fn $method:ident(self $(, $arg:ident: $ty:ty)* $(,)*) -> $ret:ty;
1348        )*
1349    ) => {
1350        #[trait_variant::make(Send)]
1351        pub trait AsyncOptionPathExt<T: PathExt>: Future<Output = io::Result<Option<T>>>
1352        where
1353            Option<T>: OptionPathExt<T>,
1354        {
1355            $(
1356                $(#[$meta])*
1357                async fn $method(self $(, $arg: $ty)*) -> $ret;
1358            )*
1359        }
1360
1361        impl<T: PathExt, F: Future<Output = io::Result<Option<T>>> + Send> AsyncOptionPathExt<T>
1362            for F
1363        where
1364            Option<T>: OptionPathExt<T>,
1365        {
1366            $(
1367                #[inline]
1368                $(#[$meta])*
1369                async fn $method(self $(, $arg: $ty)*) -> $ret {
1370                    let path = self.await?;
1371
1372                    path.$method($($arg),*).await
1373                }
1374            )*
1375        }
1376    };
1377}
1378
1379define_async_option_path_ext! {
1380    async fn metadata_async(self) -> io::Result<Option<Metadata>>;
1381    async fn symlink_metadata_async(self) -> io::Result<Option<Metadata>>;
1382    async fn canonicalize_async(self) -> io::Result<Option<PathBuf>>;
1383    async fn read_link_async(self) -> io::Result<Option<PathBuf>>;
1384    async fn read_dir_async(self) -> io::Result<Option<ReadDir>>;
1385
1386    async fn try_exists_async(self) -> io::Result<Option<bool>>;
1387
1388    async fn try_is_file(self) -> io::Result<Option<bool>>;
1389    async fn try_is_dir(self) -> io::Result<Option<bool>>;
1390    async fn try_is_symlink(self) -> io::Result<Option<bool>>;
1391
1392    async fn try_exists_nofollow(self) -> io::Result<Option<bool>>;
1393    async fn try_is_file_nofollow(self) -> io::Result<Option<bool>>;
1394    async fn try_is_dir_nofollow(self) -> io::Result<Option<bool>>;
1395
1396    async fn try_is_read_dir_empty(self) -> io::Result<Option<bool>>;
1397
1398    async fn create_new(self) -> io::Result<Option<File>>;
1399
1400    async fn create(self) -> io::Result<Option<File>>;
1401
1402    async fn open(self) -> io::Result<Option<File>>;
1403
1404    async fn read(self) -> io::Result<Option<Vec<u8>>>;
1405
1406    async fn read_to_string(self) -> io::Result<Option<String>>;
1407
1408    async fn read_lines(self) -> io::Result<Option<Lines<BufReader<File>>>>;
1409
1410    async fn create_dir_all(self) -> io::Result<Option<T>>;
1411
1412    async fn create_dir(self) -> io::Result<Option<T>>;
1413
1414    async fn write_new(self, contents: impl AsRef<[u8]> + Send) -> io::Result<Option<T>>;
1415
1416    async fn write(self, contents: impl AsRef<[u8]> + Send) -> io::Result<Option<T>>;
1417
1418    async fn append(self, contents: impl AsRef<[u8]> + Send) -> io::Result<Option<T>>;
1419
1420    async fn copy(self, to: impl AsRef<Path> + Send) -> io::Result<Option<T>>;
1421
1422    async fn rename(self, to: impl AsRef<Path> + Send) -> io::Result<Option<T>>;
1423
1424    async fn remove_file(self) -> io::Result<Option<T>>;
1425
1426    async fn remove_dir(self) -> io::Result<Option<T>>;
1427
1428    async fn remove_dir_all(self) -> io::Result<Option<T>>;
1429
1430    async fn hard_link(self, link: impl AsRef<Path> + Send) -> io::Result<Option<T>>;
1431    async fn hard_link_atomic(self, link: impl AsRef<Path> + Send) -> io::Result<Option<T>>;
1432
1433    #[cfg(unix)]
1434    async fn symlink(self, link: impl AsRef<Path> + Send) -> io::Result<Option<T>>;
1435    #[cfg(unix)]
1436    async fn symlink_atomic(self, link: impl AsRef<Path> + Send) -> io::Result<Option<T>>;
1437
1438    #[cfg(unix)]
1439    async fn symlink_absolute(self, link: impl AsRef<Path> + Send) -> io::Result<Option<T>>;
1440    #[cfg(unix)]
1441    async fn symlink_absolute_atomic(self, link: impl AsRef<Path> + Send) -> io::Result<Option<T>>;
1442
1443    #[cfg(unix)]
1444    async fn symlink_relative(self, link: impl AsRef<Path> + Send + Sync) -> io::Result<Option<T>>;
1445    #[cfg(unix)]
1446    async fn symlink_relative_atomic(
1447        self,
1448        link: impl AsRef<Path> + Send + Sync,
1449    ) -> io::Result<Option<T>>;
1450
1451    async fn set_permissions(self, perm: Permissions) -> io::Result<Option<T>>;
1452
1453    async fn set_permissions_readonly(self, readonly: bool) -> io::Result<Option<T>>;
1454
1455    #[cfg(unix)]
1456    async fn set_permissions_mode(self, mode: u32) -> io::Result<Option<T>>;
1457    #[cfg(unix)]
1458    async fn add_permissions_mode(self, mode: u32) -> io::Result<Option<T>>;
1459    #[cfg(unix)]
1460    async fn remove_permissions_mode(self, mode: u32) -> io::Result<Option<T>>;
1461
1462    #[cfg(unix)]
1463    async fn chown(self, uid: Option<u32>, gid: Option<u32>) -> io::Result<Option<T>>;
1464
1465    #[cfg(unix)]
1466    async fn chown_nofollow(self, uid: Option<u32>, gid: Option<u32>) -> io::Result<Option<T>>;
1467
1468    #[cfg(all(unix, not(target_os = "fuchsia")))]
1469    async fn chroot(self) -> io::Result<Option<T>>;
1470}