async_std/fs/open_options.rs
1use std::future::Future;
2
3use crate::fs::File;
4use crate::io;
5use crate::path::Path;
6use crate::task::spawn_blocking;
7
8/// A builder for opening files with configurable options.
9///
10/// Files can be opened in [`read`] and/or [`write`] mode.
11///
12/// The [`append`] option opens files in a special writing mode that moves the file cursor to the
13/// end of file before every write operation.
14///
15/// It is also possible to [`truncate`] the file right after opening, to [`create`] a file if it
16/// doesn't exist yet, or to always create a new file with [`create_new`].
17///
18/// This type is an async version of [`std::fs::OpenOptions`].
19///
20/// [`read`]: #method.read
21/// [`write`]: #method.write
22/// [`append`]: #method.append
23/// [`truncate`]: #method.truncate
24/// [`create`]: #method.create
25/// [`create_new`]: #method.create_new
26/// [`std::fs::OpenOptions`]: https://doc.rust-lang.org/std/fs/struct.OpenOptions.html
27///
28/// # Examples
29///
30/// Open a file for reading:
31///
32/// ```no_run
33/// # fn main() -> std::io::Result<()> { async_std::task::block_on(async {
34/// #
35/// use async_std::fs::OpenOptions;
36///
37/// let file = OpenOptions::new()
38/// .read(true)
39/// .open("a.txt")
40/// .await?;
41/// #
42/// # Ok(()) }) }
43/// ```
44///
45/// Open a file for both reading and writing, and create it if it doesn't exist yet:
46///
47/// ```no_run
48/// # fn main() -> std::io::Result<()> { async_std::task::block_on(async {
49/// #
50/// use async_std::fs::OpenOptions;
51///
52/// let file = OpenOptions::new()
53/// .read(true)
54/// .write(true)
55/// .create(true)
56/// .open("a.txt")
57/// .await?;
58/// #
59/// # Ok(()) }) }
60/// ```
61#[derive(Clone, Debug)]
62pub struct OpenOptions(std::fs::OpenOptions);
63
64impl OpenOptions {
65 /// Creates a blank set of options.
66 ///
67 /// All options are initially set to `false`.
68 ///
69 /// # Examples
70 ///
71 /// ```no_run
72 /// # fn main() -> std::io::Result<()> { async_std::task::block_on(async {
73 /// #
74 /// use async_std::fs::OpenOptions;
75 ///
76 /// let file = OpenOptions::new()
77 /// .read(true)
78 /// .open("a.txt")
79 /// .await?;
80 /// #
81 /// # Ok(()) }) }
82 /// ```
83 pub fn new() -> OpenOptions {
84 OpenOptions(std::fs::OpenOptions::new())
85 }
86
87 /// Configures the option for read mode.
88 ///
89 /// When set to `true`, this option means the file will be readable after opening.
90 ///
91 /// # Examples
92 ///
93 /// ```no_run
94 /// # fn main() -> std::io::Result<()> { async_std::task::block_on(async {
95 /// #
96 /// use async_std::fs::OpenOptions;
97 ///
98 /// let file = OpenOptions::new()
99 /// .read(true)
100 /// .open("a.txt")
101 /// .await?;
102 /// #
103 /// # Ok(()) }) }
104 /// ```
105 pub fn read(&mut self, read: bool) -> &mut OpenOptions {
106 self.0.read(read);
107 self
108 }
109
110 /// Configures the option for write mode.
111 ///
112 /// When set to `true`, this option means the file will be writable after opening.
113 ///
114 /// If the file already exists, write calls on it will overwrite the previous contents without
115 /// truncating it.
116 ///
117 /// # Examples
118 ///
119 /// ```no_run
120 /// # fn main() -> std::io::Result<()> { async_std::task::block_on(async {
121 /// #
122 /// use async_std::fs::OpenOptions;
123 ///
124 /// let file = OpenOptions::new()
125 /// .write(true)
126 /// .open("a.txt")
127 /// .await?;
128 /// #
129 /// # Ok(()) }) }
130 /// ```
131 pub fn write(&mut self, write: bool) -> &mut OpenOptions {
132 self.0.write(write);
133 self
134 }
135
136 /// Configures the option for append mode.
137 ///
138 /// When set to `true`, this option means the file will be writable after opening and the file
139 /// cursor will be moved to the end of file before every write operation.
140 ///
141 /// # Examples
142 ///
143 /// ```no_run
144 /// # fn main() -> std::io::Result<()> { async_std::task::block_on(async {
145 /// #
146 /// use async_std::fs::OpenOptions;
147 ///
148 /// let file = OpenOptions::new()
149 /// .append(true)
150 /// .open("a.txt")
151 /// .await?;
152 /// #
153 /// # Ok(()) }) }
154 /// ```
155 pub fn append(&mut self, append: bool) -> &mut OpenOptions {
156 self.0.append(append);
157 self
158 }
159
160 /// Configures the option for truncating the previous file.
161 ///
162 /// When set to `true`, the file will be truncated to the length of 0 bytes.
163 ///
164 /// The file must be opened in [`write`] or [`append`] mode for truncation to work.
165 ///
166 /// [`write`]: #method.write
167 /// [`append`]: #method.append
168 ///
169 /// # Examples
170 ///
171 /// ```no_run
172 /// # fn main() -> std::io::Result<()> { async_std::task::block_on(async {
173 /// #
174 /// use async_std::fs::OpenOptions;
175 ///
176 /// let file = OpenOptions::new()
177 /// .write(true)
178 /// .truncate(true)
179 /// .open("a.txt")
180 /// .await?;
181 /// #
182 /// # Ok(()) }) }
183 /// ```
184 pub fn truncate(&mut self, truncate: bool) -> &mut OpenOptions {
185 self.0.truncate(truncate);
186 self
187 }
188
189 /// Configures the option for creating a new file if it doesn't exist.
190 ///
191 /// When set to `true`, this option means a new file will be created if it doesn't exist.
192 ///
193 /// The file must be opened in [`write`] or [`append`] mode for file creation to work.
194 ///
195 /// [`write`]: #method.write
196 /// [`append`]: #method.append
197 ///
198 /// # Examples
199 ///
200 /// ```no_run
201 /// # fn main() -> std::io::Result<()> { async_std::task::block_on(async {
202 /// #
203 /// use async_std::fs::OpenOptions;
204 ///
205 /// let file = OpenOptions::new()
206 /// .write(true)
207 /// .create(true)
208 /// .open("a.txt")
209 /// .await?;
210 /// #
211 /// # Ok(()) }) }
212 /// ```
213 pub fn create(&mut self, create: bool) -> &mut OpenOptions {
214 self.0.create(create);
215 self
216 }
217
218 /// Configures the option for creating a new file or failing if it already exists.
219 ///
220 /// When set to `true`, this option means a new file will be created, or the open operation
221 /// will fail if the file already exists.
222 ///
223 /// The file must be opened in [`write`] or [`append`] mode for file creation to work.
224 ///
225 /// [`write`]: #method.write
226 /// [`append`]: #method.append
227 ///
228 /// # Examples
229 ///
230 /// ```no_run
231 /// # fn main() -> std::io::Result<()> { async_std::task::block_on(async {
232 /// #
233 /// use async_std::fs::OpenOptions;
234 ///
235 /// let file = OpenOptions::new()
236 /// .write(true)
237 /// .create_new(true)
238 /// .open("a.txt")
239 /// .await?;
240 /// #
241 /// # Ok(()) }) }
242 /// ```
243 pub fn create_new(&mut self, create_new: bool) -> &mut OpenOptions {
244 self.0.create_new(create_new);
245 self
246 }
247
248 /// Opens a file with the configured options.
249 ///
250 /// # Errors
251 ///
252 /// An error will be returned in the following situations:
253 ///
254 /// * The file does not exist and neither [`create`] nor [`create_new`] were set.
255 /// * The file's parent directory does not exist.
256 /// * The current process lacks permissions to open the file in the configured mode.
257 /// * The file already exists and [`create_new`] was set.
258 /// * Invalid combination of options was used, like [`truncate`] was set but [`write`] wasn't,
259 /// or none of [`read`], [`write`], and [`append`] modes was set.
260 /// * An OS-level occurred, like too many files are open or the file name is too long.
261 /// * Some other I/O error occurred.
262 ///
263 /// [`read`]: #method.read
264 /// [`write`]: #method.write
265 /// [`append`]: #method.append
266 /// [`truncate`]: #method.truncate
267 /// [`create`]: #method.create
268 /// [`create_new`]: #method.create_new
269 ///
270 /// # Examples
271 ///
272 /// ```no_run
273 /// # fn main() -> std::io::Result<()> { async_std::task::block_on(async {
274 /// #
275 /// use async_std::fs::OpenOptions;
276 ///
277 /// let file = OpenOptions::new()
278 /// .read(true)
279 /// .open("a.txt")
280 /// .await?;
281 /// #
282 /// # Ok(()) }) }
283 /// ```
284 pub fn open<P: AsRef<Path>>(&self, path: P) -> impl Future<Output = io::Result<File>> {
285 let path = path.as_ref().to_owned();
286 let options = self.0.clone();
287 async move {
288 let file = spawn_blocking(move || options.open(path)).await?;
289 Ok(File::new(file, true))
290 }
291 }
292}
293
294impl Default for OpenOptions {
295 fn default() -> Self {
296 Self::new()
297 }
298}
299
300cfg_unix! {
301 use crate::os::unix::fs::OpenOptionsExt;
302
303 impl OpenOptionsExt for OpenOptions {
304 fn mode(&mut self, mode: u32) -> &mut Self {
305 self.0.mode(mode);
306 self
307 }
308
309 fn custom_flags(&mut self, flags: i32) -> &mut Self {
310 self.0.custom_flags(flags);
311 self
312 }
313 }
314}