fut_compat/fs/
mod.rs

1use std::path::{Path, PathBuf};
2use std::fs::{Metadata, Permissions, FileType};
3use std::ffi::OsString;
4
5use futures::stream::Stream;
6
7use async_trait::async_trait;
8
9
10
11/// Contains the compatibility objects for the [`tokio`](https://docs.rs/tokio) runtime.
12#[cfg(feature = "tokio-rt")]
13#[cfg_attr(docsrs, doc(cfg(feature = "tokio-rt")))]
14mod tokio;
15#[cfg(feature = "tokio-rt")]
16#[cfg_attr(docsrs, doc(cfg(feature = "tokio-rt")))]
17pub use self::tokio::*;
18
19/// Contains the compatibility objects for the [`async_std`](https://docs.rs/async-std) runtime.
20#[cfg(feature = "async-std-rt")]
21#[cfg_attr(docsrs, doc(cfg(feature = "async-std-rt")))]
22mod async_std;
23#[cfg(feature = "async-std-rt")]
24#[cfg_attr(docsrs, doc(cfg(feature = "async-std-rt")))]
25pub use self::async_std::*;
26
27
28
29/// An async abstraction over the functions in [`std::fs`].
30#[async_trait]
31pub trait Filesystem {
32    type ReadDir: Stream<Item = std::io::Result<Self::DirEntry>>;
33    type DirEntry: DirEntry;
34
35    /// Returns the canonical form of a path.
36    ///
37    /// The returned path is in absolute form with all intermediate components normalized and symbolic
38    /// links resolved.
39    ///
40    /// This function is an async version of [`std::fs::canonicalize`].
41    ///
42    /// [`std::fs::canonicalize`]: https://doc.rust-lang.org/std/fs/fn.canonicalize.html
43    ///
44    /// # Errors
45    ///
46    /// An error will be returned in the following situations:
47    ///
48    /// * `path` does not point to an existing file or directory.
49    /// * A non-final component in `path` is not a directory.
50    /// * Some other I/O error occurred.
51    ///
52    /// # Examples
53    ///
54    /// Using the [`tokio`](https://docs.rs/tokio) runtime:
55    ///
56    /// ```no_run
57    /// # #[tokio::main]
58    /// # async fn main() -> std::io::Result<()> {
59    /// #
60    /// use fut_compat::fs::Filesystem;
61    /// use fut_compat::fs::TokioFs;
62    ///
63    /// let path = TokioFs::canonicalize(".").await?;
64    /// #
65    /// # Ok(())
66    /// # }
67    /// ```
68    ///
69    /// Using the [`async_std`](https://docs.rs/async-std) runtime:
70    ///
71    /// ```no_run
72    /// # fn main() -> std::io::Result<()> { async_std::task::block_on(async {
73    /// #
74    /// use fut_compat::fs::Filesystem;
75    /// use fut_compat::fs::AsyncStdFs;
76    ///
77    /// let path = AsyncStdFs::canonicalize(".").await?;
78    /// #
79    /// # Ok(()) }) }
80    /// ```
81    async fn canonicalize<P: AsRef<Path> + Send>(path: P) -> std::io::Result<PathBuf>;
82
83    /// Copies the contents and permissions of a file to a new location.
84    ///
85    /// On success, the total number of bytes copied is returned and equals the length of the `to` file
86    /// after this operation.
87    ///
88    /// The old contents of `to` will be overwritten. If `from` and `to` both point to the same file,
89    /// then the file will likely get truncated as a result of this operation.
90    ///
91    /// If you're working with open [`File`]s and want to copy contents through those types, use the
92    /// [`io::copy`] function.
93    ///
94    /// This function is an async version of [`std::fs::copy`].
95    ///
96    /// [`File`]: struct.File.html
97    /// [`io::copy`]: ../io/fn.copy.html
98    /// [`std::fs::copy`]: https://doc.rust-lang.org/std/fs/fn.copy.html
99    ///
100    /// # Errors
101    ///
102    /// An error will be returned in the following situations:
103    ///
104    /// * `from` does not point to an existing file.
105    /// * The current process lacks permissions to read `from` or write `to`.
106    /// * Some other I/O error occurred.
107    ///
108    /// # Examples
109    ///
110    /// Using the [`tokio`](https://docs.rs/tokio) runtime:
111    ///
112    /// ```no_run
113    /// # #[tokio::main]
114    /// # async fn main() -> std::io::Result<()> {
115    /// #
116    /// use fut_compat::fs::Filesystem;
117    /// use fut_compat::fs::TokioFs;
118    ///
119    /// let num_bytes = TokioFs::copy("a.txt", "b.txt").await?;
120    /// #
121    /// # Ok(())
122    /// # }
123    /// ```
124    ///
125    /// Using the [`async_std`](https://docs.rs/async-std) runtime:
126    ///
127    /// ```no_run
128    /// # fn main() -> std::io::Result<()> { async_std::task::block_on(async {
129    /// #
130    /// use fut_compat::fs::Filesystem;
131    /// use fut_compat::fs::AsyncStdFs;
132    ///
133    /// let num_bytes = AsyncStdFs::copy("a.txt", "b.txt").await?;
134    /// #
135    /// # Ok(()) }) }
136    /// ```
137    async fn copy<S: AsRef<Path> + Send, D: AsRef<Path> + Send>(
138        from: S,
139        to: D,
140    ) -> std::io::Result<u64>;
141
142    /// Creates a new directory.
143    ///
144    /// Note that this function will only create the final directory in `path`. If you want to create
145    /// all of its missing parent directories too, use the [`create_dir_all`] function instead.
146    ///
147    /// This function is an async version of [`std::fs::create_dir`].
148    ///
149    /// [`create_dir_all`]: fn.create_dir_all.html
150    /// [`std::fs::create_dir`]: https://doc.rust-lang.org/std/fs/fn.create_dir.html
151    ///
152    /// # Errors
153    ///
154    /// An error will be returned in the following situations:
155    ///
156    /// * `path` already points to an existing file or directory.
157    /// * A parent directory in `path` does not exist.
158    /// * The current process lacks permissions to create the directory.
159    /// * Some other I/O error occurred.
160    ///
161    /// # Examples
162    ///
163    /// Using the [`tokio`](https://docs.rs/tokio) runtime:
164    ///
165    /// ```no_run
166    /// # #[tokio::main]
167    /// # async fn main() -> std::io::Result<()> {
168    /// #
169    /// use fut_compat::fs::Filesystem;
170    /// use fut_compat::fs::TokioFs;
171    ///
172    /// TokioFs::create_dir("./some/directory").await?;
173    /// #
174    /// # Ok(())
175    /// # }
176    /// ```
177    ///
178    /// Using the [`async_std`](https://docs.rs/async-std) runtime:
179    ///
180    /// ```no_run
181    /// # fn main() -> std::io::Result<()> { async_std::task::block_on(async {
182    /// #
183    /// use fut_compat::fs::Filesystem;
184    /// use fut_compat::fs::AsyncStdFs;
185    ///
186    /// AsyncStdFs::create_dir("./some/directory").await?;
187    /// #
188    /// # Ok(()) }) }
189    /// ```
190    async fn create_dir<P: AsRef<Path> + Send>(path: P) -> std::io::Result<()>;
191
192    /// Creates a new directory and all of its parents if they are missing.
193    ///
194    /// This function is an async version of [`std::fs::create_dir_all`].
195    ///
196    /// [`std::fs::create_dir_all`]: https://doc.rust-lang.org/std/fs/fn.create_dir_all.html
197    ///
198    /// # Errors
199    ///
200    /// An error will be returned in the following situations:
201    ///
202    /// * `path` already points to an existing file or directory.
203    /// * The current process lacks permissions to create the directory or its missing parents.
204    /// * Some other I/O error occurred.
205    ///
206    /// # Examples
207    ///
208    /// Using the [`tokio`](https://docs.rs/tokio) runtime:
209    ///
210    /// ```no_run
211    /// # #[tokio::main]
212    /// # async fn main() -> std::io::Result<()> {
213    /// #
214    /// use fut_compat::fs::Filesystem;
215    /// use fut_compat::fs::TokioFs;
216    ///
217    /// TokioFs::create_dir_all("./some/directory").await?;
218    /// #
219    /// # Ok(())
220    /// # }
221    /// ```
222    ///
223    /// Using the [`async_std`](https://docs.rs/async-std) runtime:
224    ///
225    /// ```no_run
226    /// # fn main() -> std::io::Result<()> { async_std::task::block_on(async {
227    /// #
228    /// use fut_compat::fs::Filesystem;
229    /// use fut_compat::fs::AsyncStdFs;
230    ///
231    /// AsyncStdFs::create_dir_all("./some/directory").await?;
232    /// #
233    /// # Ok(()) }) }
234    /// ```
235    async fn create_dir_all<P: AsRef<Path> + Send>(path: P) -> std::io::Result<()>;
236
237    /// Creates a hard link on the filesystem.
238    ///
239    /// The `dst` path will be a link pointing to the `src` path. Note that operating systems often
240    /// require these two paths to be located on the same filesystem.
241    ///
242    /// This function is an async version of [`std::fs::hard_link`].
243    ///
244    /// [`std::fs::hard_link`]: https://doc.rust-lang.org/std/fs/fn.hard_link.html
245    ///
246    /// # Errors
247    ///
248    /// An error will be returned in the following situations:
249    ///
250    /// * `src` does not point to an existing file.
251    /// * Some other I/O error occurred.
252    ///
253    /// # Examples
254    ///
255    /// Using the [`tokio`](https://docs.rs/tokio) runtime:
256    ///
257    /// ```no_run
258    /// # #[tokio::main]
259    /// # async fn main() -> std::io::Result<()> {
260    /// #
261    /// use fut_compat::fs::Filesystem;
262    /// use fut_compat::fs::TokioFs;
263    ///
264    /// TokioFs::hard_link("a.txt", "b.txt").await?;
265    /// #
266    /// # Ok(())
267    /// # }
268    /// ```
269    ///
270    /// Using the [`async_std`](https://docs.rs/async-std) runtime:
271    ///
272    /// ```no_run
273    /// # fn main() -> std::io::Result<()> { async_std::task::block_on(async {
274    /// #
275    /// use fut_compat::fs::Filesystem;
276    /// use fut_compat::fs::AsyncStdFs;
277    ///
278    /// AsyncStdFs::hard_link("a.txt", "b.txt").await?;
279    /// #
280    /// # Ok(()) }) }
281    /// ```
282    async fn hard_link<S: AsRef<Path> + Send, D: AsRef<Path> + Send>(
283        from: S,
284        to: D,
285    ) -> std::io::Result<()>;
286
287    /// Reads metadata for a path.
288    ///
289    /// This function will traverse symbolic links to read metadata for the target file or directory.
290    /// If you want to read metadata without following symbolic links, use [`symlink_metadata`]
291    /// instead.
292    ///
293    /// This function is an async version of [`std::fs::metadata`].
294    ///
295    /// [`symlink_metadata`]: fn.symlink_metadata.html
296    /// [`std::fs::metadata`]: https://doc.rust-lang.org/std/fs/fn.metadata.html
297    ///
298    /// # Errors
299    ///
300    /// An error will be returned in the following situations:
301    ///
302    /// * `path` does not point to an existing file or directory.
303    /// * The current process lacks permissions to read metadata for the path.
304    /// * Some other I/O error occurred.
305    ///
306    /// # Examples
307    ///
308    /// Using the [`tokio`](https://docs.rs/tokio) runtime:
309    ///
310    /// ```no_run
311    /// # #[tokio::main]
312    /// # async fn main() -> std::io::Result<()> {
313    /// #
314    /// use fut_compat::fs::Filesystem;
315    /// use fut_compat::fs::TokioFs;
316    ///
317    /// let meta = TokioFs::metadata("a.txt").await?;
318    /// #
319    /// # Ok(())
320    /// # }
321    /// ```
322    ///
323    /// Using the [`async_std`](https://docs.rs/async-std) runtime:
324    ///
325    /// ```no_run
326    /// # fn main() -> std::io::Result<()> { async_std::task::block_on(async {
327    /// #
328    /// use fut_compat::fs::Filesystem;
329    /// use fut_compat::fs::AsyncStdFs;
330    ///
331    /// let meta = AsyncStdFs::metadata("a.txt").await?;
332    /// #
333    /// # Ok(()) }) }
334    /// ```
335    async fn metadata<P: AsRef<Path> + Send>(path: P) -> std::io::Result<Metadata>;
336
337    /// Reads the entire contents of a file as raw bytes.
338    ///
339    /// This is a convenience function for reading entire files. It pre-allocates a buffer based on the
340    /// file size when available, so it is typically faster than manually opening a file and reading
341    /// from it.
342    ///
343    /// If you want to read the contents as a string, use [`read_to_string`] instead.
344    ///
345    /// This function is an async version of [`std::fs::read`].
346    ///
347    /// [`read_to_string`]: fn.read_to_string.html
348    /// [`std::fs::read`]: https://doc.rust-lang.org/std/fs/fn.read.html
349    ///
350    /// # Errors
351    ///
352    /// An error will be returned in the following situations:
353    ///
354    /// * `path` does not point to an existing file.
355    /// * The current process lacks permissions to read the file.
356    /// * Some other I/O error occurred.
357    ///
358    /// # Examples
359    ///
360    /// Using the [`tokio`](https://docs.rs/tokio) runtime:
361    ///
362    /// ```no_run
363    /// # #[tokio::main]
364    /// # async fn main() -> std::io::Result<()> {
365    /// #
366    /// use fut_compat::fs::Filesystem;
367    /// use fut_compat::fs::TokioFs;
368    ///
369    /// let contents = TokioFs::read("a.txt").await?;
370    /// #
371    /// # Ok(())
372    /// # }
373    /// ```
374    ///
375    /// Using the [`async_std`](https://docs.rs/async-std) runtime:
376    ///
377    /// ```no_run
378    /// # fn main() -> std::io::Result<()> { async_std::task::block_on(async {
379    /// #
380    /// use fut_compat::fs::Filesystem;
381    /// use fut_compat::fs::AsyncStdFs;
382    ///
383    /// let contents = AsyncStdFs::read("a.txt").await?;
384    /// #
385    /// # Ok(()) }) }
386    /// ```
387    async fn read<P: AsRef<Path> + Send>(path: P) -> std::io::Result<Vec<u8>>;
388
389    /// Returns a stream of entries in a directory.
390    ///
391    /// The stream yields items of type [`io::Result`]`<`[`DirEntry`]`>`. Note that I/O errors can
392    /// occur while reading from the stream.
393    ///
394    /// This function is an async version of [`std::fs::read_dir`].
395    ///
396    /// [`io::Result`]: ../io/type.Result.html
397    /// [`DirEntry`]: struct.DirEntry.html
398    /// [`std::fs::read_dir`]: https://doc.rust-lang.org/std/fs/fn.read_dir.html
399    ///
400    /// # Errors
401    ///
402    /// An error will be returned in the following situations:
403    ///
404    /// * `path` does not point to an existing directory.
405    /// * The current process lacks permissions to read the contents of the directory.
406    /// * Some other I/O error occurred.
407    ///
408    /// # Examples
409    ///
410    /// Using the [`tokio`](https://docs.rs/tokio) runtime:
411    ///
412    /// ```no_run
413    /// # #[tokio::main]
414    /// # async fn main() -> std::io::Result<()> {
415    /// #
416    /// use futures::stream::StreamExt;
417    /// use fut_compat::fs::Filesystem;
418    /// use fut_compat::fs::TokioFs;
419    ///
420    /// let mut entries = TokioFs::read_dir(".").await?;
421    ///
422    /// while let Some(res) = entries.next().await {
423    ///     let entry = res?;
424    ///     println!("{}", entry.file_name().to_string_lossy());
425    /// }
426    /// #
427    /// # Ok(())
428    /// # }
429    /// ```
430    ///
431    /// Using the [`async_std`](https://docs.rs/async-std) runtime:
432    ///
433    /// ```no_run
434    /// # fn main() -> std::io::Result<()> { async_std::task::block_on(async {
435    /// #
436    /// use futures::stream::StreamExt;
437    /// use fut_compat::fs::Filesystem;
438    /// use fut_compat::fs::AsyncStdFs;
439    ///
440    /// let mut entries = AsyncStdFs::read_dir(".").await?;
441    ///
442    /// while let Some(res) = entries.next().await {
443    ///     let entry = res?;
444    ///     println!("{}", entry.file_name().to_string_lossy());
445    /// }
446    /// #
447    /// # Ok(()) }) }
448    /// ```
449    async fn read_dir<P: AsRef<Path> + Send>(path: P) -> std::io::Result<Self::ReadDir>;
450
451    /// Reads a symbolic link and returns the path it points to.
452    ///
453    /// This function is an async version of [`std::fs::read_link`].
454    ///
455    /// [`std::fs::read_link`]: https://doc.rust-lang.org/std/fs/fn.read_link.html
456    ///
457    /// # Errors
458    ///
459    /// An error will be returned in the following situations:
460    ///
461    /// * `path` does not point to an existing link.
462    /// * Some other I/O error occurred.
463    ///
464    /// # Examples
465    ///
466    /// Using the [`tokio`](https://docs.rs/tokio) runtime:
467    ///
468    /// ```no_run
469    /// # #[tokio::main]
470    /// # async fn main() -> std::io::Result<()> {
471    /// #
472    /// use fut_compat::fs::Filesystem;
473    /// use fut_compat::fs::TokioFs;
474    ///
475    /// let path = TokioFs::read_link("a.txt").await?;
476    /// #
477    /// # Ok(())
478    /// # }
479    /// ```
480    ///
481    /// Using the [`async_std`](https://docs.rs/async-std) runtime:
482    ///
483    /// ```no_run
484    /// # fn main() -> std::io::Result<()> { async_std::task::block_on(async {
485    /// #
486    /// use fut_compat::fs::Filesystem;
487    /// use fut_compat::fs::AsyncStdFs;
488    ///
489    /// let path = AsyncStdFs::read_link("a.txt").await?;
490    /// #
491    /// # Ok(()) }) }
492    /// ```
493    async fn read_link<P: AsRef<Path> + Send>(path: P) -> std::io::Result<PathBuf>;
494
495    /// Reads the entire contents of a file as a string.
496    ///
497    /// This is a convenience function for reading entire files. It pre-allocates a string based on the
498    /// file size when available, so it is typically faster than manually opening a file and reading
499    /// from it.
500    ///
501    /// If you want to read the contents as raw bytes, use [`read`] instead.
502    ///
503    /// This function is an async version of [`std::fs::read_to_string`].
504    ///
505    /// [`read`]: #tymethod.read
506    /// [`std::fs::read_to_string`]: https://doc.rust-lang.org/std/fs/fn.read_to_string.html
507    ///
508    /// # Errors
509    ///
510    /// An error will be returned in the following situations:
511    ///
512    /// * `path` does not point to an existing file.
513    /// * The current process lacks permissions to read the file.
514    /// * The contents of the file cannot be read as a UTF-8 string.
515    /// * Some other I/O error occurred.
516    ///
517    /// # Examples
518    ///
519    /// Using the [`tokio`](https://docs.rs/tokio) runtime:
520    ///
521    /// ```no_run
522    /// # #[tokio::main]
523    /// # async fn main() -> std::io::Result<()> {
524    /// #
525    /// use fut_compat::fs::Filesystem;
526    /// use fut_compat::fs::TokioFs;
527    ///
528    /// let contents = TokioFs::read_to_string("a.txt").await?;
529    /// #
530    /// # Ok(())
531    /// # }
532    /// ```
533    ///
534    /// Using the [`async_std`](https://docs.rs/async-std) runtime:
535    ///
536    /// ```no_run
537    /// # fn main() -> std::io::Result<()> { async_std::task::block_on(async {
538    /// #
539    /// use fut_compat::fs::Filesystem;
540    /// use fut_compat::fs::AsyncStdFs;
541    ///
542    /// let contents = AsyncStdFs::read_to_string("a.txt").await?;
543    /// #
544    /// # Ok(()) }) }
545    /// ```
546    async fn read_to_string<P: AsRef<Path> + Send>(path: P) -> std::io::Result<String>;
547
548    /// Removes an empty directory.
549    ///
550    /// This function is an async version of [`std::fs::remove_dir`].
551    ///
552    /// [`std::fs::remove_dir`]: https://doc.rust-lang.org/std/fs/fn.remove_dir.html
553    ///
554    /// # Errors
555    ///
556    /// An error will be returned in the following situations:
557    ///
558    /// * `path` is not an existing and empty directory.
559    /// * The current process lacks permissions to remove the directory.
560    /// * Some other I/O error occurred.
561    ///
562    /// # Examples
563    ///
564    /// Using the [`tokio`](https://docs.rs/tokio) runtime:
565    ///
566    /// ```no_run
567    /// # #[tokio::main]
568    /// # async fn main() -> std::io::Result<()> {
569    /// #
570    /// use fut_compat::fs::Filesystem;
571    /// use fut_compat::fs::TokioFs;
572    ///
573    /// TokioFs::remove_dir("./some/directory").await?;
574    /// #
575    /// # Ok(())
576    /// # }
577    /// ```
578    ///
579    /// Using the [`async_std`](https://docs.rs/async-std) runtime:
580    ///
581    /// ```no_run
582    /// # fn main() -> std::io::Result<()> { async_std::task::block_on(async {
583    /// #
584    /// use fut_compat::fs::Filesystem;
585    /// use fut_compat::fs::AsyncStdFs;
586    ///
587    /// AsyncStdFs::remove_dir("./some/directory").await?;
588    /// #
589    /// # Ok(()) }) }
590    /// ```
591    async fn remove_dir<P: AsRef<Path> + Send>(path: P) -> std::io::Result<()>;
592
593    /// Removes a directory and all of its contents.
594    ///
595    /// This function is an async version of [`std::fs::remove_dir_all`].
596    ///
597    /// [`std::fs::remove_dir_all`]: https://doc.rust-lang.org/std/fs/fn.remove_dir_all.html
598    ///
599    /// # Errors
600    ///
601    /// An error will be returned in the following situations:
602    ///
603    /// * `path` is not an existing and empty directory.
604    /// * The current process lacks permissions to remove the directory.
605    /// * Some other I/O error occurred.
606    ///
607    /// # Examples
608    ///
609    /// Using the [`tokio`](https://docs.rs/tokio) runtime:
610    ///
611    /// ```no_run
612    /// # #[tokio::main]
613    /// # async fn main() -> std::io::Result<()> {
614    /// #
615    /// use fut_compat::fs::Filesystem;
616    /// use fut_compat::fs::TokioFs;
617    ///
618    /// TokioFs::remove_dir_all("./some/directory").await?;
619    /// #
620    /// # Ok(())
621    /// # }
622    /// ```
623    ///
624    /// Using the [`async_std`](https://docs.rs/async-std) runtime:
625    ///
626    /// ```no_run
627    /// # fn main() -> std::io::Result<()> { async_std::task::block_on(async {
628    /// #
629    /// use fut_compat::fs::Filesystem;
630    /// use fut_compat::fs::AsyncStdFs;
631    ///
632    /// AsyncStdFs::remove_dir_all("./some/directory").await?;
633    /// #
634    /// # Ok(()) }) }
635    /// ```
636    async fn remove_dir_all<P: AsRef<Path> + Send>(path: P) -> std::io::Result<()>;
637
638    /// Removes a file.
639    ///
640    /// This function is an async version of [`std::fs::remove_file`].
641    ///
642    /// [`std::fs::remove_file`]: https://doc.rust-lang.org/std/fs/fn.remove_file.html
643    ///
644    /// # Errors
645    ///
646    /// An error will be returned in the following situations:
647    ///
648    /// * `path` does not point to an existing file.
649    /// * The current process lacks permissions to remove the file.
650    /// * Some other I/O error occurred.
651    ///
652    /// # Examples
653    ///
654    /// Using the [`tokio`](https://docs.rs/tokio) runtime:
655    ///
656    /// ```no_run
657    /// # #[tokio::main]
658    /// # async fn main() -> std::io::Result<()> {
659    /// #
660    /// use fut_compat::fs::Filesystem;
661    /// use fut_compat::fs::TokioFs;
662    ///
663    /// TokioFs::remove_file("a.txt").await?;
664    /// #
665    /// # Ok(())
666    /// # }
667    /// ```
668    ///
669    /// Using the [`async_std`](https://docs.rs/async-std) runtime:
670    ///
671    /// ```no_run
672    /// # fn main() -> std::io::Result<()> { async_std::task::block_on(async {
673    /// #
674    /// use fut_compat::fs::Filesystem;
675    /// use fut_compat::fs::AsyncStdFs;
676    ///
677    /// AsyncStdFs::remove_file("a.txt").await?;
678    /// #
679    /// # Ok(()) }) }
680    /// ```
681    async fn remove_file<P: AsRef<Path> + Send>(path: P) -> std::io::Result<()>;
682
683    /// Renames a file or directory to a new location.
684    ///
685    /// If a file or directory already exists at the target location, it will be overwritten by this
686    /// operation.
687    ///
688    /// This function is an async version of [`std::fs::rename`].
689    ///
690    /// [`std::fs::rename`]: https://doc.rust-lang.org/std/fs/fn.rename.html
691    ///
692    /// # Errors
693    ///
694    /// An error will be returned in the following situations:
695    ///
696    /// * `from` does not point to an existing file or directory.
697    /// * `from` and `to` are on different filesystems.
698    /// * The current process lacks permissions to do the rename operation.
699    /// * Some other I/O error occurred.
700    ///
701    /// # Examples
702    ///
703    /// Using the [`tokio`](https://docs.rs/tokio) runtime:
704    ///
705    /// ```no_run
706    /// # #[tokio::main]
707    /// # async fn main() -> std::io::Result<()> {
708    /// #
709    /// use fut_compat::fs::Filesystem;
710    /// use fut_compat::fs::TokioFs;
711    ///
712    /// TokioFs::rename("a.txt", "b.txt").await?;
713    /// #
714    /// # Ok(())
715    /// # }
716    /// ```
717    ///
718    /// Using the [`async_std`](https://docs.rs/async-std) runtime:
719    ///
720    /// ```no_run
721    /// # fn main() -> std::io::Result<()> { async_std::task::block_on(async {
722    /// #
723    /// use fut_compat::fs::Filesystem;
724    /// use fut_compat::fs::AsyncStdFs;
725    ///
726    /// AsyncStdFs::rename("a.txt", "b.txt").await?;
727    /// #
728    /// # Ok(()) }) }
729    /// ```
730    async fn rename<O: AsRef<Path> + Send, N: AsRef<Path> + Send>(
731        from: O,
732        to: N,
733    ) -> std::io::Result<()>;
734
735    /// Changes the permissions of a file or directory.
736    ///
737    /// This function is an async version of [`std::fs::set_permissions`].
738    ///
739    /// [`std::fs::set_permissions`]: https://doc.rust-lang.org/std/fs/fn.set_permissions.html
740    ///
741    /// # Errors
742    ///
743    /// An error will be returned in the following situations:
744    ///
745    /// * `path` does not point to an existing file or directory.
746    /// * The current process lacks permissions to change attributes on the file or directory.
747    /// * Some other I/O error occurred.
748    ///
749    /// # Examples
750    ///
751    /// Using the [`tokio`](https://docs.rs/tokio) runtime:
752    ///
753    /// ```no_run
754    /// # #[tokio::main]
755    /// # async fn main() -> std::io::Result<()> {
756    /// #
757    /// use fut_compat::fs::Filesystem;
758    /// use fut_compat::fs::TokioFs;
759    ///
760    /// let mut perm = TokioFs::metadata("a.txt").await?.permissions();
761    /// perm.set_readonly(true);
762    /// TokioFs::set_permissions("a.txt", perm).await?;
763    /// #
764    /// # Ok(())
765    /// # }
766    /// ```
767    ///
768    /// Using the [`async_std`](https://docs.rs/async-std) runtime:
769    ///
770    /// ```no_run
771    /// # fn main() -> std::io::Result<()> { async_std::task::block_on(async {
772    /// #
773    /// use fut_compat::fs::Filesystem;
774    /// use fut_compat::fs::AsyncStdFs;
775    ///
776    /// let mut perm = AsyncStdFs::metadata("a.txt").await?.permissions();
777    /// perm.set_readonly(true);
778    /// AsyncStdFs::set_permissions("a.txt", perm).await?;
779    /// #
780    /// # Ok(()) }) }
781    /// ```
782    async fn set_permissions<P: AsRef<Path> + Send>(
783        path: P,
784        perm: Permissions,
785    ) -> std::io::Result<()>;
786
787    /// Reads metadata for a path without following symbolic links.
788    ///
789    /// If you want to follow symbolic links before reading metadata of the target file or directory,
790    /// use [`metadata`] instead.
791    ///
792    /// This function is an async version of [`std::fs::symlink_metadata`].
793    ///
794    /// [`metadata`]: fn.metadata.html
795    /// [`std::fs::symlink_metadata`]: https://doc.rust-lang.org/std/fs/fn.symlink_metadata.html
796    ///
797    /// # Errors
798    ///
799    /// An error will be returned in the following situations:
800    ///
801    /// * `path` does not point to an existing file or directory.
802    /// * The current process lacks permissions to read metadata for the path.
803    /// * Some other I/O error occurred.
804    ///
805    /// # Examples
806    ///
807    /// Using the [`tokio`](https://docs.rs/tokio) runtime:
808    ///
809    /// ```no_run
810    /// # #[tokio::main]
811    /// # async fn main() -> std::io::Result<()> {
812    /// #
813    /// use fut_compat::fs::Filesystem;
814    /// use fut_compat::fs::TokioFs;
815    ///
816    /// let meta = TokioFs::symlink_metadata("a.txt").await?;
817    /// #
818    /// # Ok(())
819    /// # }
820    /// ```
821    ///
822    /// Using the [`async_std`](https://docs.rs/async-std) runtime:
823    ///
824    /// ```no_run
825    /// # fn main() -> std::io::Result<()> { async_std::task::block_on(async {
826    /// #
827    /// use fut_compat::fs::Filesystem;
828    /// use fut_compat::fs::AsyncStdFs;
829    ///
830    /// let meta = AsyncStdFs::symlink_metadata("a.txt").await?;
831    /// #
832    /// # Ok(()) }) }
833    /// ```
834    async fn symlink_metadata<P: AsRef<Path> + Send>(path: P) -> std::io::Result<Metadata>;
835
836    /// Writes a slice of bytes as the new contents of a file.
837    ///
838    /// This function will create a file if it does not exist, and will entirely replace its contents
839    /// if it does.
840    ///
841    /// This function is an async version of [`std::fs::write`].
842    ///
843    /// [`std::fs::write`]: https://doc.rust-lang.org/std/fs/fn.write.html
844    ///
845    /// # Errors
846    ///
847    /// An error will be returned in the following situations:
848    ///
849    /// * The file's parent directory does not exist.
850    /// * The current process lacks permissions to write to the file.
851    /// * Some other I/O error occurred.
852    ///
853    /// # Examples
854    ///
855    /// Using the [`tokio`](https://docs.rs/tokio) runtime:
856    ///
857    /// ```no_run
858    /// # #[tokio::main]
859    /// # async fn main() -> std::io::Result<()> {
860    /// #
861    /// use fut_compat::fs::Filesystem;
862    /// use fut_compat::fs::TokioFs;
863    ///
864    /// TokioFs::write("a.txt", b"Hello world!").await?;
865    /// #
866    /// # Ok(())
867    /// # }
868    /// ```
869    ///
870    /// Using the [`async_std`](https://docs.rs/async-std) runtime:
871    ///
872    /// ```no_run
873    /// # fn main() -> std::io::Result<()> { async_std::task::block_on(async {
874    /// #
875    /// use fut_compat::fs::Filesystem;
876    /// use fut_compat::fs::AsyncStdFs;
877    ///
878    /// AsyncStdFs::write("a.txt", b"Hello world!").await?;
879    /// #
880    /// # Ok(()) }) }
881    /// ```
882    async fn write<P: AsRef<Path> + Send, C: AsRef<[u8]> + Send>(
883        path: P,
884        contents: C
885    ) -> std::io::Result<()>;
886}
887
888
889
890/// An async abstraction over [`std::fs::DirEntry`].
891#[async_trait]
892pub trait DirEntry {
893    /// Returns the full path to this entry.
894    ///
895    /// The full path is created by joining the original path passed to [`read_dir`] with the name
896    /// of this entry.
897    ///
898    /// [`read_dir`]: trait.Filesystem.html#tymethod.read_dir
899    ///
900    /// # Examples
901    ///
902    /// Using the [`tokio`](https://docs.rs/tokio) runtime:
903    ///
904    /// ```no_run
905    /// # #[tokio::main]
906    /// # async fn main() -> std::io::Result<()> {
907    /// #
908    /// use futures::stream::StreamExt;
909    /// use fut_compat::fs::Filesystem;
910    /// use fut_compat::fs::TokioFs;
911    ///
912    /// let mut entries = TokioFs::read_dir(".").await?;
913    ///
914    /// while let Some(res) = entries.next().await {
915    ///     let entry = res?;
916    ///     println!("{:?}", entry.path());
917    /// }
918    /// #
919    /// # Ok(())
920    /// # }
921    /// ```
922    ///
923    /// Using the [`async_std`](https://docs.rs/async-std) runtime:
924    ///
925    /// ```no_run
926    /// # fn main() -> std::io::Result<()> { async_std::task::block_on(async {
927    /// #
928    /// use futures::stream::StreamExt;
929    /// use fut_compat::fs::Filesystem;
930    /// use fut_compat::fs::AsyncStdFs;
931    ///
932    /// let mut entries = AsyncStdFs::read_dir(".").await?;
933    ///
934    /// while let Some(res) = entries.next().await {
935    ///     let entry = res?;
936    ///     println!("{:?}", entry.path());
937    /// }
938    /// #
939    /// # Ok(()) }) }
940    /// ```
941    fn path(&self) -> PathBuf;
942
943    /// Returns the bare name of this entry without the leading path.
944    ///
945    /// # Examples
946    ///
947    /// Using the [`tokio`](https://docs.rs/tokio) runtime:
948    ///
949    /// ```no_run
950    /// # #[tokio::main]
951    /// # async fn main() -> std::io::Result<()> {
952    /// #
953    /// use futures::stream::StreamExt;
954    /// use fut_compat::fs::Filesystem;
955    /// use fut_compat::fs::TokioFs;
956    ///
957    /// let mut entries = TokioFs::read_dir(".").await?;
958    ///
959    /// while let Some(res) = entries.next().await {
960    ///     let entry = res?;
961    ///     println!("{}", entry.file_name().to_string_lossy());
962    /// }
963    /// #
964    /// # Ok(())
965    /// # }
966    /// ```
967    ///
968    /// Using the [`async_std`](https://docs.rs/async-std) runtime:
969    ///
970    /// ```no_run
971    /// # fn main() -> std::io::Result<()> { async_std::task::block_on(async {
972    /// #
973    /// use futures::stream::StreamExt;
974    /// use fut_compat::fs::Filesystem;
975    /// use fut_compat::fs::AsyncStdFs;
976    ///
977    /// let mut entries = AsyncStdFs::read_dir(".").await?;
978    ///
979    /// while let Some(res) = entries.next().await {
980    ///     let entry = res?;
981    ///     println!("{}", entry.file_name().to_string_lossy());
982    /// }
983    /// #
984    /// # Ok(()) }) }
985    /// ```
986    fn file_name(&self) -> OsString;
987
988    /// Reads the metadata for this entry.
989    ///
990    /// This function will traverse symbolic links to read the metadata.
991    ///
992    /// If you want to read metadata without following symbolic links, use [`symlink_metadata`]
993    /// instead.
994    ///
995    /// [`symlink_metadata`]: trait.Filesystem.html#tymethod.symlink_metadata
996    ///
997    /// # Errors
998    ///
999    /// An error will be returned in the following situations:
1000    ///
1001    /// * This entry does not point to an existing file or directory anymore.
1002    /// * The current process lacks permissions to read the metadata.
1003    /// * Some other I/O error occurred.
1004    ///
1005    /// # Examples
1006    ///
1007    /// Using the [`tokio`](https://docs.rs/tokio) runtime:
1008    ///
1009    /// ```no_run
1010    /// # #[tokio::main]
1011    /// # async fn main() -> std::io::Result<()> {
1012    /// #
1013    /// use futures::stream::StreamExt;
1014    /// use fut_compat::fs::Filesystem;
1015    /// use fut_compat::fs::TokioFs;
1016    ///
1017    /// let mut entries = TokioFs::read_dir(".").await?;
1018    ///
1019    /// while let Some(res) = entries.next().await {
1020    ///     let entry = res?;
1021    ///     println!("{:?}", entry.metadata().await?);
1022    /// }
1023    /// #
1024    /// # Ok(())
1025    /// # }
1026    /// ```
1027    ///
1028    /// Using the [`async_std`](https://docs.rs/async-std) runtime:
1029    ///
1030    /// ```no_run
1031    /// # fn main() -> std::io::Result<()> { async_std::task::block_on(async {
1032    /// #
1033    /// use futures::stream::StreamExt;
1034    /// use fut_compat::fs::Filesystem;
1035    /// use fut_compat::fs::AsyncStdFs;
1036    ///
1037    /// let mut entries = AsyncStdFs::read_dir(".").await?;
1038    ///
1039    /// while let Some(res) = entries.next().await {
1040    ///     let entry = res?;
1041    ///     println!("{:?}", entry.metadata().await?);
1042    /// }
1043    /// #
1044    /// # Ok(()) }) }
1045    /// ```
1046    async fn metadata(&self) -> std::io::Result<Metadata>;
1047
1048    /// Reads the file type for this entry.
1049    ///
1050    /// This function will not traverse symbolic links if this entry points at one.
1051    ///
1052    /// If you want to read metadata with following symbolic links, use [`metadata`] instead.
1053    ///
1054    /// [`metadata`]: #tymethod.metadata
1055    ///
1056    /// # Errors
1057    ///
1058    /// An error will be returned in the following situations:
1059    ///
1060    /// * This entry does not point to an existing file or directory anymore.
1061    /// * The current process lacks permissions to read this entry's metadata.
1062    /// * Some other I/O error occurred.
1063    ///
1064    /// # Examples
1065    ///
1066    /// Using the [`tokio`](https://docs.rs/tokio) runtime:
1067    ///
1068    /// ```no_run
1069    /// # #[tokio::main]
1070    /// # async fn main() -> std::io::Result<()> {
1071    /// #
1072    /// use futures::stream::StreamExt;
1073    /// use fut_compat::fs::Filesystem;
1074    /// use fut_compat::fs::TokioFs;
1075    ///
1076    /// let mut entries = TokioFs::read_dir(".").await?;
1077    ///
1078    /// while let Some(res) = entries.next().await {
1079    ///     let entry = res?;
1080    ///     println!("{:?}", entry.file_type().await?);
1081    /// }
1082    /// #
1083    /// # Ok(())
1084    /// # }
1085    /// ```
1086    ///
1087    /// Using the [`async_std`](https://docs.rs/async-std) runtime:
1088    ///
1089    /// ```no_run
1090    /// # fn main() -> std::io::Result<()> { async_std::task::block_on(async {
1091    /// #
1092    /// use futures::stream::StreamExt;
1093    /// use fut_compat::fs::Filesystem;
1094    /// use fut_compat::fs::AsyncStdFs;
1095    ///
1096    /// let mut entries = AsyncStdFs::read_dir(".").await?;
1097    ///
1098    /// while let Some(res) = entries.next().await {
1099    ///     let entry = res?;
1100    ///     println!("{:?}", entry.file_type().await?);
1101    /// }
1102    /// #
1103    /// # Ok(()) }) }
1104    /// ```
1105    async fn file_type(&self) -> std::io::Result<FileType>;
1106}
1107
1108
1109
1110/// An async abstraction over [`std::fs::File`].
1111#[async_trait]
1112pub trait File: Sized {
1113    /// Opens a file in read-only mode.
1114    ///
1115    /// See the [`OpenOptions::open`] function for more options.
1116    ///
1117    /// # Errors
1118    ///
1119    /// An error will be returned in the following situations:
1120    ///
1121    /// * `path` does not point to an existing file.
1122    /// * The current process lacks permissions to read the file.
1123    /// * Some other I/O error occurred.
1124    ///
1125    /// For more details, see the list of errors documented by [`OpenOptions::open`].
1126    ///
1127    /// [`OpenOptions::open`]: trait.OpenOptions.html#tymethod.open
1128    async fn open<P: AsRef<Path> + Send>(path: P) -> std::io::Result<Self>;
1129
1130    /// Opens a file in write-only mode.
1131    ///
1132    /// This function will create a file if it does not exist, and will truncate it if it does.
1133    ///
1134    /// See the [`OpenOptions::open`] function for more options.
1135    ///
1136    /// # Errors
1137    ///
1138    /// An error will be returned in the following situations:
1139    ///
1140    /// * The file's parent directory does not exist.
1141    /// * The current process lacks permissions to write to the file.
1142    /// * Some other I/O error occurred.
1143    ///
1144    /// For more details, see the list of errors documented by [`OpenOptions::open`].
1145    ///
1146    /// [`OpenOptions::open`]: trait.OpenOptions.html#tymethod.open
1147    async fn create<P: AsRef<Path> + Send>(path: P) -> std::io::Result<Self>;
1148
1149    /// Synchronizes OS-internal buffered contents and metadata to disk.
1150    ///
1151    /// This function will ensure that all in-memory data reaches the filesystem.
1152    ///
1153    /// This can be used to handle errors that would otherwise only be caught when the file is
1154    /// closed. When a file is dropped, errors in synchronizing this in-memory data are ignored.
1155    async fn sync_all(&self) -> std::io::Result<()>;
1156
1157    /// Synchronizes OS-internal buffered contents to disk.
1158    ///
1159    /// This is similar to [`sync_all`], except that file metadata may not be synchronized.
1160    ///
1161    /// This is intended for use cases that must synchronize the contents of the file, but don't
1162    /// need the file metadata synchronized to disk.
1163    ///
1164    /// Note that some platforms may simply implement this in terms of [`sync_all`].
1165    ///
1166    /// [`sync_all`]: #tymethod.sync_all
1167    async fn sync_data(&self) -> std::io::Result<()>;
1168
1169    /// Truncates or extends the file.
1170    ///
1171    /// If `size` is less than the current file size, then the file will be truncated. If it is
1172    /// greater than the current file size, then the file will be extended to `size` and have all
1173    /// intermediate data filled with zeros.
1174    ///
1175    /// The file's cursor stays at the same position, even if the cursor ends up being past the end
1176    /// of the file after this operation.
1177    async fn set_len(&self, size: u64) -> std::io::Result<()>;
1178
1179    /// Reads the file's metadata.
1180    async fn metadata(&self) -> std::io::Result<Metadata>;
1181
1182    /// Changes the permissions on the file.
1183    ///
1184    /// # Errors
1185    ///
1186    /// An error will be returned in the following situations:
1187    ///
1188    /// * The current process lacks permissions to change attributes on the file.
1189    /// * Some other I/O error occurred.
1190    async fn set_permissions(&self, perm: Permissions) -> std::io::Result<()>;
1191}
1192
1193/// An async abstraction over [`std::fs::OpenOptions`].
1194///
1195/// A builder for opening files with configurable options.
1196///
1197/// Files can be opened in [`read`] and/or [`write`] mode.
1198///
1199/// The [`append`] option opens files in a special writing mode that moves the file cursor to the
1200/// end of file before every write operation.
1201///
1202/// It is also possible to [`truncate`] the file right after opening, to [`create`] a file if it
1203/// doesn't exist yet, or to always create a new file with [`create_new`].
1204///
1205/// [`read`]: #tymethod.read
1206/// [`write`]: #tymethod.write
1207/// [`append`]: #tymethod.append
1208/// [`truncate`]: #tymethod.truncate
1209/// [`create`]: #tymethod.create
1210/// [`create_new`]: #tymethod.create_new
1211/// [`std::fs::OpenOptions`]: https://doc.rust-lang.org/std/fs/struct.OpenOptions.html
1212///
1213/// # Examples
1214///
1215/// Open a file for reading using the [`tokio`](https://docs.rs/tokio) runtime:
1216///
1217/// ```no_run
1218/// # #[tokio::main]
1219/// # async fn main() -> std::io::Result<()> {
1220/// #
1221/// use tokio::fs::OpenOptions;
1222///
1223/// let file = OpenOptions::new()
1224///     .read(true)
1225///     .open("a.txt")
1226///     .await?;
1227/// #
1228/// # Ok(())
1229/// # }
1230/// ```
1231///
1232/// Open a file for reading using the [`async_std`](https://docs.rs/async-std) runtime:
1233///
1234/// ```no_run
1235/// # fn main() -> std::io::Result<()> { async_std::task::block_on(async {
1236/// #
1237/// use async_std::fs::OpenOptions;
1238///
1239/// let file = OpenOptions::new()
1240///     .read(true)
1241///     .open("a.txt")
1242///     .await?;
1243/// #
1244/// # Ok(()) }) }
1245/// ```
1246///
1247/// Open a file for both reading and writing, and create it if it doesn't exist yet
1248/// using the [`tokio`](https://docs.rs/tokio) runtime:
1249///
1250/// ```no_run
1251/// # #[tokio::main]
1252/// # async fn main() -> std::io::Result<()> {
1253/// #
1254/// use tokio::fs::OpenOptions;
1255///
1256/// let file = OpenOptions::new()
1257///     .read(true)
1258///     .write(true)
1259///     .create(true)
1260///     .open("a.txt")
1261///     .await?;
1262/// #
1263/// # Ok(())
1264/// # }
1265/// ```
1266///
1267/// Open a file for both reading and writing, and create it if it doesn't exist yet
1268/// using the [`async_std`](https://docs.rs/async-std) runtime:
1269///
1270/// ```no_run
1271/// # fn main() -> std::io::Result<()> { async_std::task::block_on(async {
1272/// #
1273/// use async_std::fs::OpenOptions;
1274///
1275/// let file = OpenOptions::new()
1276///     .read(true)
1277///     .write(true)
1278///     .create(true)
1279///     .open("a.txt")
1280///     .await?;
1281/// #
1282/// # Ok(()) }) }
1283/// ```
1284#[async_trait]
1285pub trait OpenOptions: Sized {
1286    /// The file object which gets returned by the [`open`](#tymethod.open) method.
1287    type File: File;
1288
1289    /// Creates a blank set of options.
1290    ///
1291    /// All options are initially set to `false`.
1292    fn new() -> Self;
1293
1294    /// Configures the option for read mode.
1295    ///
1296    /// When set to `true`, this option means the file will be readable after opening.
1297    fn read(&mut self, read: bool) -> &mut Self;
1298
1299    /// Configures the option for write mode.
1300    ///
1301    /// When set to `true`, this option means the file will be writable after opening.
1302    ///
1303    /// If the file already exists, write calls on it will overwrite the previous contents without
1304    /// truncating it.
1305    fn write(&mut self, write: bool) -> &mut Self;
1306
1307    /// Configures the option for append mode.
1308    ///
1309    /// When set to `true`, this option means the file will be writable after opening and the file
1310    /// cursor will be moved to the end of file before every write operaiton.
1311    fn append(&mut self, append: bool) -> &mut Self;
1312
1313    /// Configures the option for truncating the previous file.
1314    ///
1315    /// When set to `true`, the file will be truncated to the length of 0 bytes.
1316    ///
1317    /// The file must be opened in [`write`] or [`append`] mode for truncation to work.
1318    ///
1319    /// [`write`]: #tymethod.write
1320    /// [`append`]: #tymethod.append
1321    fn truncate(&mut self, truncate: bool) -> &mut Self;
1322
1323    /// Configures the option for creating a new file if it doesn't exist.
1324    ///
1325    /// When set to `true`, this option means a new file will be created if it doesn't exist.
1326    ///
1327    /// The file must be opened in [`write`] or [`append`] mode for file creation to work.
1328    ///
1329    /// [`write`]: #tymethod.write
1330    /// [`append`]: #tymethod.append
1331    fn create(&mut self, create: bool) -> &mut Self;
1332
1333    /// Configures the option for creating a new file or failing if it already exists.
1334    ///
1335    /// When set to `true`, this option means a new file will be created, or the open operation
1336    /// will fail if the file already exists.
1337    ///
1338    /// The file must be opened in [`write`] or [`append`] mode for file creation to work.
1339    ///
1340    /// [`write`]: #tymethod.write
1341    /// [`append`]: #tymethod.append
1342    fn create_new(&mut self, create_new: bool) -> &mut Self;
1343
1344    /// Opens a file with the configured options.
1345    ///
1346    /// # Errors
1347    ///
1348    /// An error will be returned in the following situations:
1349    ///
1350    /// * The file does not exist and neither [`create`] nor [`create_new`] were set.
1351    /// * The file's parent directory does not exist.
1352    /// * The current process lacks permissions to open the file in the configured mode.
1353    /// * The file already exists and [`create_new`] was set.
1354    /// * Invalid combination of options was used, like [`truncate`] was set but [`write`] wasn't,
1355    ///   or none of [`read`], [`write`], and [`append`] modes was set.
1356    /// * An OS-level occurred, like too many files are open or the file name is too long.
1357    /// * Some other I/O error occurred.
1358    ///
1359    /// [`read`]: #tymethod.read
1360    /// [`write`]: #tymethod.write
1361    /// [`append`]: #tymethod.append
1362    /// [`truncate`]: #tymethod.truncate
1363    /// [`create`]: #tymethod.create
1364    /// [`create_new`]: #tymethod.create_new
1365    async fn open<P: AsRef<Path> + Send>(&self, path: P) -> std::io::Result<Self::File>;
1366}
1367
1368/// An async abstraction over [`std::fs::DirBuilder`].
1369#[async_trait]
1370pub trait DirBuilder: Sized {
1371    /// Creates a blank set of options.
1372    ///
1373    /// The [`recursive`] option is initially set to `false`.
1374    ///
1375    /// [`recursive`]: #tymethod.recursive
1376    fn new() -> Self;
1377
1378    /// Sets the option for recursive mode.
1379    ///
1380    /// When set to `true`, this option means all parent directories should be created recursively
1381    /// if they don't exist. Parents are created with the same permissions as the final directory.
1382    ///
1383    /// This option is initially set to `false`.
1384    fn recursive(&mut self, recursive: bool) -> &mut Self;
1385
1386    /// Creates a directory with the configured options.
1387    ///
1388    /// It is considered an error if the directory already exists unless recursive mode is enabled.
1389    async fn create<P: AsRef<Path> + Send>(&self, path: P) -> std::io::Result<()>;
1390}