Skip to main content

arta/
fs.rs

1//! Filesystem manipulation operations.
2
3mod dir_entry;
4mod file;
5
6pub use dir_entry::*;
7pub use file::*;
8
9use futures::{AsyncReadExt, AsyncWriteExt, Stream};
10use std::{
11    fs::{Metadata, OpenOptions, Permissions},
12    future::Future,
13    path::{Path, PathBuf},
14    pin::pin,
15};
16
17/// Represents an async runtime that supports asynchronous access to filesystem.
18pub trait FSRuntime: Send + Sync {
19    /// Runtime's file.
20    type File: RuntimeFile<Runtime = Self>;
21    /// Runtime's dir entry.
22    type DirEntry: RuntimeDirEntry;
23
24    /// Returns the canonical, absolute form of a path with all intermediate
25    /// components normalized and symbolic links resolved.
26    ///
27    /// This is an async version of [`std::fs::canonicalize`]
28    fn canonicalize(
29        &self,
30        path: impl AsRef<Path> + Send,
31    ) -> impl Future<Output = std::io::Result<PathBuf>> + Send;
32
33    /// Copies the contents of one file to another. This function will also
34    /// copy the permission bits of the original file to the destination file.
35    ///
36    /// This is an async version of [`std::fs::copy`]
37    fn copy(
38        &self,
39        from: impl AsRef<Path> + Send,
40        to: impl AsRef<Path> + Send,
41    ) -> impl Future<Output = std::io::Result<u64>> + Send;
42
43    /// Creates a new, empty directory at the provided path.
44    ///
45    /// This is an async version of [`std::fs::create_dir`]
46    fn create_dir(
47        &self,
48        path: impl AsRef<Path> + Send,
49    ) -> impl Future<Output = std::io::Result<()>> + Send;
50
51    /// Recursively create a directory and all of its parent components if they
52    /// are missing.
53    ///
54    /// This is an async version of [`std::fs::create_dir_all`]
55    fn create_dir_all(
56        &self,
57        path: impl AsRef<Path> + Send,
58    ) -> impl Future<Output = std::io::Result<()>> + Send;
59
60    /// Removes an empty directory.
61    ///
62    /// This is an async version of [`std::fs::remove_dir`]
63    fn remove_dir(
64        &self,
65        path: impl AsRef<Path> + Send,
66    ) -> impl Future<Output = std::io::Result<()>> + Send;
67
68    /// Returns an iterator over the entries within a directory.
69    ///
70    /// This is an async version of [`std::fs::remove_dir_all`]
71    fn remove_dir_all(
72        &self,
73        path: impl AsRef<Path> + Send,
74    ) -> impl Future<Output = std::io::Result<()>> + Send;
75
76    /// Returns a stream over the entries within a directory.
77    ///
78    /// This is an async version of [`std::fs::read_dir`]
79    fn read_dir(
80        &self,
81        path: impl AsRef<Path> + Send,
82    ) -> impl Future<
83        Output = std::io::Result<impl Stream<Item = std::io::Result<Self::DirEntry>> + Send>,
84    > + Send;
85
86    /// Reads a symbolic link, returning the file that the link points to.
87    ///
88    /// This is an async version of [`std::fs::read_link`]
89    fn read_link(
90        &self,
91        path: impl AsRef<Path> + Send,
92    ) -> impl Future<Output = std::io::Result<PathBuf>> + Send;
93
94    /// Creates a new symbolic link on the filesystem.
95    ///
96    /// This is an async version of [`std::os::unix::fs::symlink`]
97    #[cfg(any(unix, doc))]
98    #[cfg_attr(docsrs, doc(cfg(unix)))]
99    fn symlink(
100        &self,
101        from: impl AsRef<Path> + Send,
102        to: impl AsRef<Path> + Send,
103    ) -> impl Future<Output = std::io::Result<()>> + Send;
104
105    /// Creates a new symlink to a directory on the filesystem.
106    ///
107    /// This is async version of [`std::os::windows::fs::symlink_dir`].
108    #[cfg(any(windows, doc))]
109    #[cfg_attr(docsrs, doc(cfg(windows)))]
110    fn symlink_dir(
111        &self,
112        from: impl AsRef<Path> + Send,
113        to: impl AsRef<Path> + Send,
114    ) -> impl Future<Output = std::io::Result<()>> + Send;
115
116    /// Creates a new symlink to a non-directory file on the filesystem.
117    ///
118    /// This is async version of [`std::os::windows::fs::symlink_file`].
119    #[cfg(any(windows, doc))]
120    #[cfg_attr(docsrs, doc(cfg(windows)))]
121    fn symlink_file(
122        &self,
123        from: impl AsRef<Path>,
124        to: impl AsRef<Path> + Send,
125    ) -> impl Future<Output = std::io::Result<()>> + Send;
126
127    /// Creates a new hard link on the filesystem.
128    ///
129    /// This is an async version of [`std::fs::hard_link`]
130    fn hard_link(
131        &self,
132        from: impl AsRef<Path> + Send,
133        to: impl AsRef<Path> + Send,
134    ) -> impl Future<Output = std::io::Result<()>> + Send;
135
136    /// Given a path, query the file system to get information about a file,
137    /// directory, etc.
138    ///
139    /// This is an async version of [`std::fs::metadata`]
140    fn metadata(
141        &self,
142        path: impl AsRef<Path> + Send,
143    ) -> impl Future<Output = std::io::Result<Metadata>> + Send;
144
145    /// Read the entire contents of a file into a bytes vector.
146    ///
147    /// This is an async version of [`std::fs::read`]
148    fn read(
149        &self,
150        path: impl AsRef<Path> + Send,
151    ) -> impl Future<Output = std::io::Result<Vec<u8>>> + Send {
152        async {
153            let mut file = pin!(Self::File::open(self, OpenOptions::new().read(true), path).await?);
154            let file_size: usize = file
155                .metadata()
156                .await?
157                .len()
158                .try_into()
159                .map_err(|err| std::io::Error::new(std::io::ErrorKind::InvalidInput, err))?;
160
161            let mut buffer = Vec::with_capacity(file_size);
162            file.read_to_end(&mut buffer).await?;
163
164            Ok(buffer)
165        }
166    }
167
168    /// Read the entire contents of a file into a string.
169    ///
170    /// This is an async version of [`std::fs::read_to_string`]
171    fn read_to_string(
172        &self,
173        path: impl AsRef<Path> + Send,
174    ) -> impl Future<Output = std::io::Result<String>> + Send {
175        async {
176            let mut file = pin!(Self::File::open(self, OpenOptions::new().read(true), path).await?);
177            let file_size: usize = file
178                .metadata()
179                .await?
180                .len()
181                .try_into()
182                .map_err(|err| std::io::Error::new(std::io::ErrorKind::InvalidInput, err))?;
183
184            let mut buffer = String::with_capacity(file_size);
185            file.read_to_string(&mut buffer).await?;
186
187            Ok(buffer)
188        }
189    }
190
191    /// Write a slice as the entire contents of a file.
192    ///
193    /// This is an async version of [`std::fs::write`]
194    fn write(
195        &self,
196        path: impl AsRef<Path> + Send,
197        content: &[u8],
198    ) -> impl Future<Output = std::io::Result<()>> + Send {
199        async {
200            let mut file =
201                pin!(Self::File::open(self, OpenOptions::new().create(true), path).await?);
202            file.write_all(content).await
203        }
204    }
205
206    /// Removes a file from the filesystem.
207    ///
208    /// This is an async version of [`std::fs::remove_file`]
209    fn remove_file(
210        &self,
211        path: impl AsRef<Path> + Send,
212    ) -> impl Future<Output = std::io::Result<()>> + Send;
213
214    /// Rename a file or directory to a new name, replacing the original file if
215    /// `to` already exists.
216    ///
217    /// This is an async version of [`std::fs::rename`]
218    fn rename(
219        &self,
220        from: impl AsRef<Path> + Send,
221        to: impl AsRef<Path> + Send,
222    ) -> impl Future<Output = std::io::Result<()>> + Send;
223
224    /// Changes the permissions found on a file or a directory.
225    ///
226    /// This is an async version of [`std::fs::set_permissions`]
227    fn set_permissions(
228        &self,
229        path: impl AsRef<Path> + Send,
230        permissions: Permissions,
231    ) -> impl Future<Output = std::io::Result<()>> + Send;
232
233    /// Query the metadata about a file without following symlinks.
234    ///
235    /// This is an async version of [`std::fs::symlink_metadata`]
236    fn symlink_metadata(
237        &self,
238        path: impl AsRef<Path> + Send,
239    ) -> impl Future<Output = std::io::Result<Metadata>> + Send;
240}