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}