fmmap/
options.rs

1macro_rules! declare_and_impl_options {
2    ($name: ident, $file_open_options: ident) => {
3        /// A memory map builder, providing advanced options and flags for specifying memory map file behavior.
4        ///
5        // TODO: support file lock options
6        #[derive(Clone)]
7        pub struct $name {
8            pub(crate) mmap_opts: MmapOptions,
9            pub(crate) file_opts: $file_open_options,
10            pub(crate) max_size: u64,
11        }
12
13        impl Default for $name {
14            fn default() -> Self {
15                Self::new()
16            }
17        }
18
19        impl $name {
20            /// Creates a new set of options for configuring and creating a memory map.
21            pub fn new() -> Self {
22                Self {
23                    mmap_opts: MmapOptions::new(),
24                    file_opts: <$file_open_options>::new(),
25                    max_size: 0,
26                }
27            }
28
29            /// Configures the memory map to start at byte offset from the beginning of the file.
30            /// This option has no effect on anonymous memory maps.
31            /// By default, the offset is 0.
32            pub fn offset(mut self, offset: u64) -> Self {
33                self.mmap_opts.offset(offset);
34                self
35            }
36
37            /// Configures the created memory mapped buffer to be len bytes long.
38            /// This option is mandatory for anonymous memory maps.
39            /// For file-backed memory maps, the length will default to the file length.
40            pub fn len(mut self, len: usize) -> Self {
41                self.mmap_opts.len(len);
42                self
43            }
44
45            /// Populate (prefault) page tables for a mapping.
46            /// For a file mapping, this causes read-ahead on the file. This will help to reduce blocking on page faults later.
47            /// This option corresponds to the MAP_POPULATE flag on Linux. It has no effect on Windows
48            pub fn populate(mut self) -> Self {
49                self.mmap_opts.populate();
50                self
51            }
52
53            /// Configures the anonymous memory map to be suitable for a process or thread stack.
54            /// This option corresponds to the MAP_STACK flag on Linux. It has no effect on Windows.
55            /// This option has no effect on file-backed memory maps
56            pub fn stack(mut self) -> Self {
57                self.mmap_opts.stack();
58                self
59            }
60
61            /// Configures the max size of the file.
62            ///
63            /// This option only has effect when mmaping a real file in write mode.
64            ///
65            /// This field is ignored when opening [`DiskMmapFile`], [`AsyncDiskMmapFile`], [`MmapFile`] and [`AsyncMmapFile`].
66            ///
67            /// [`DiskMmapFile`]: fmmap::raw::DiskMmapFile
68            /// [`AsyncDiskMmapFile`]: fmmap::raw::AsyncDiskMmapFile
69            /// [`MmapFile`]: struct.MmapFile.html
70            /// [`AsyncMmapFile`]: struct.AsyncMmapFile.html
71            pub fn max_size(mut self, max_sz: u64) -> Self {
72                self.max_size = max_sz;
73                self
74            }
75
76            /// Sets the option for read access. For details, please see [`std::fs::OpenOptions::read`]
77            ///
78            /// [`std::fs::OpenOptions::read`]: https://doc.rust-lang.org/std/fs/struct.OpenOptions.html#method.read
79            pub fn read(mut self, val: bool) -> Self {
80                self.file_opts.read(val);
81                self
82            }
83
84            /// Sets the option for write access. For details, please see [`std::fs::OpenOptions::write`].
85            ///
86            /// This field is ignored when opening [`DiskMmapFile`], [`AsyncDiskMmapFile`], [`MmapFile`] and [`AsyncMmapFile`].
87            ///
88            /// [`DiskMmapFile`]: fmmap::raw::DiskMmapFile
89            /// [`AsyncDiskMmapFile`]: fmmap::raw::AsyncDiskMmapFile
90            /// [`MmapFile`]: struct.MmapFile.html
91            /// [`AsyncMmapFile`]: struct.AsyncMmapFile.html
92            /// [`std::fs::OpenOptions::write`]: https://doc.rust-lang.org/std/fs/struct.OpenOptions.html#method.write
93            pub fn write(mut self, val: bool) -> Self {
94                self.file_opts.write(val);
95                self
96            }
97
98            /// Sets the option to create a new file, or open it if it already exists. For details, please see [`std::fs::OpenOptions::create`].
99            ///
100            /// This field is ignored when opening [`DiskMmapFile`], [`AsyncDiskMmapFile`], [`MmapFile`] and [`AsyncMmapFile`].
101            ///
102            /// [`DiskMmapFile`]: fmmap::raw::DiskMmapFile
103            /// [`AsyncDiskMmapFile`]: fmmap::raw::AsyncDiskMmapFile
104            /// [`MmapFile`]: struct.MmapFile.html
105            /// [`AsyncMmapFile`]: struct.AsyncMmapFile.html
106            /// [`std::fs::OpenOptions::create`]: https://doc.rust-lang.org/std/fs/struct.OpenOptions.html#method.create
107            pub fn create(mut self, val: bool) -> Self {
108                self.file_opts.create(val);
109                self
110            }
111
112            /// Sets the option to create a new file, failing if it already exists. For details, please see [`std::fs::OpenOptions::create_new`]
113            ///
114            /// This field is ignored when opening [`DiskMmapFile`], [`AsyncDiskMmapFile`], [`MmapFile`] and [`AsyncMmapFile`].
115            ///
116            /// [`DiskMmapFile`]: fmmap::raw::DiskMmapFile
117            /// [`AsyncDiskMmapFile`]: fmmap::raw::AsyncDiskMmapFile
118            /// [`MmapFile`]: struct.MmapFile.html
119            /// [`AsyncMmapFile`]: struct.AsyncMmapFile.html
120            /// [`std::fs::OpenOptions::create_new`]: https://doc.rust-lang.org/std/fs/struct.OpenOptions.html#method.create_new
121            pub fn create_new(mut self, val: bool) -> Self {
122                self.file_opts.create_new(val);
123                self
124            }
125
126            /// Sets the option for the append mode. For details, please see [`std::fs::OpenOptions::append`]
127            ///
128            /// This field is ignored when opening [`DiskMmapFile`], [`AsyncDiskMmapFile`], [`MmapFile`] and [`AsyncMmapFile`].
129            ///
130            /// [`DiskMmapFile`]: fmmap::raw::DiskMmapFile
131            /// [`AsyncDiskMmapFile`]: fmmap::raw::AsyncDiskMmapFile
132            /// [`MmapFile`]: struct.MmapFile.html
133            /// [`AsyncMmapFile`]: struct.AsyncMmapFile.html
134            /// [`std::fs::OpenOptions::append`]: https://doc.rust-lang.org/std/fs/struct.OpenOptions.html#method.append
135            pub fn append(mut self, val: bool) -> Self {
136                self.file_opts.append(val);
137                self
138            }
139
140            /// Sets the option for truncating a previous file. For details, please see [`std::fs::OpenOptions::truncate`]
141            ///
142            /// This field is ignored when opening [`DiskMmapFile`], [`AsyncDiskMmapFile`], [`MmapFile`] and [`AsyncMmapFile`].
143            ///
144            /// [`DiskMmapFile`]: fmmap::raw::DiskMmapFile
145            /// [`AsyncDiskMmapFile`]: fmmap::raw::AsyncDiskMmapFile
146            /// [`MmapFile`]: struct.MmapFile.html
147            /// [`AsyncMmapFile`]: struct.AsyncMmapFile.html
148            /// [`std::fs::OpenOptions::truncate`]: https://doc.rust-lang.org/std/fs/struct.OpenOptions.html#method.truncate
149            pub fn truncate(mut self, val: bool) -> Self {
150                self.file_opts.truncate(val);
151                self
152            }
153        }
154    };
155}
156
157#[cfg(unix)]
158macro_rules! impl_options_unix_ext {
159    ($name: ident) => {
160        #[cfg(unix)]
161        impl $name {
162            /// Sets the mode bits that a new file will be created with. [Read more]
163            ///
164            /// [Read more]: https://doc.rust-lang.org/std/os/unix/fs/trait.OpenOptionsExt.html#tymethod.mode
165            #[cfg(unix)]
166            pub fn mode(mut self, mode: u32) -> Self {
167                self.file_opts.mode(mode);
168                self
169            }
170
171            /// Pass custom flags to the `flags` argument of `open`. [Read more]
172            ///
173            /// [Read more]: https://doc.rust-lang.org/std/os/unix/fs/trait.OpenOptionsExt.html#tymethod.mode
174            #[cfg(unix)]
175            pub fn custom_flags(mut self, flags: i32) -> Self {
176                self.file_opts.custom_flags(flags);
177                self
178            }
179        }
180    };
181}
182
183#[cfg(windows)]
184macro_rules! impl_options_windows_ext {
185    ($name: ident) => {
186        #[cfg(windows)]
187        impl $name {
188            /// Overrides the `dwDesiredAccess` argument to the call to [`CreateFile`] with the specified value. [Read more]
189            ///
190            /// [`CreateFile`]: https://docs.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-createfilea
191            /// [Read more]: https://doc.rust-lang.org/std/os/windows/fs/trait.OpenOptionsExt.html#tymethod.security_qos_flags
192            #[cfg(windows)]
193            pub fn access_mode(mut self, access: u32) -> Self {
194                self.file_opts.access_mode(access);
195                self
196            }
197
198            /// Overrides the `dwShareMode` argument to the call to [`CreateFile`] with the specified value. [Read more]
199            ///
200            /// [`CreateFile`]: https://docs.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-createfilea
201            /// [Read more]: https://doc.rust-lang.org/std/os/windows/fs/trait.OpenOptionsExt.html#tymethod.security_qos_flags
202            #[cfg(windows)]
203            pub fn share_mode(mut self, val: u32) -> Self {
204                self.file_opts.share_mode(val);
205                self
206            }
207
208            /// Sets extra flags for the dwFileFlags argument to the
209            /// call to [`CreateFile2`] to the specified value (or combines
210            /// it with `attributes` and `security_qos_flags` to set the `dwFlagsAndAttributes` for [`CreateFile`]). [Read more]
211            ///
212            /// [`CreateFile2`]: https://docs.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-createfile2
213            /// [`CreateFile`]: https://docs.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-createfilea
214            /// [Read more]: https://doc.rust-lang.org/std/os/windows/fs/trait.OpenOptionsExt.html#tymethod.security_qos_flags
215            #[cfg(windows)]
216            pub fn custom_flags(mut self, flag: u32) -> Self {
217                self.file_opts.custom_flags(flag);
218                self
219            }
220
221            /// Overrides the `dwDesiredAccess` argument to the call to [`CreateFile`] with the specified value. [Read more]
222            ///
223            /// [`CreateFile`]: https://docs.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-createfilea
224            /// [Read more]: https://doc.rust-lang.org/std/os/windows/fs/trait.OpenOptionsExt.html#tymethod.security_qos_flags
225            #[cfg(windows)]
226            pub fn attributes(mut self, val: u32) -> Self {
227                self.file_opts.attributes(val);
228                self
229            }
230
231            /// Sets the `dwSecurityQosFlags` argument to the call to
232            /// [`CreateFile2`] to the specified value (or combines it with `custom_flags`
233            /// and `attributes` to set the `dwFlagsAndAttributes` for [`CreateFile`]). [Read more]
234            ///
235            /// [`CreateFile2`]: https://docs.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-createfile2
236            /// [`CreateFile`]: https://docs.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-createfilea
237            /// [Read more]: https://doc.rust-lang.org/std/os/windows/fs/trait.OpenOptionsExt.html#tymethod.security_qos_flags
238            #[cfg(windows)]
239            pub fn security_qos_flags(mut self, flags: u32) -> Self {
240                self.file_opts.security_qos_flags(flags);
241                self
242            }
243        }
244    };
245}
246
247cfg_sync!(
248    mod sync_impl;
249    pub use sync_impl::Options;
250);
251
252cfg_async! {
253    macro_rules! declare_and_impl_async_options {
254        ($filename_prefix: literal, $doc_test_runtime: literal, $path_str: literal) => {
255            declare_and_impl_options!(AsyncOptions, OpenOptions);
256
257            impl AsyncOptions {
258                /// Create a new file and mmap this file with [`AsyncOptions`]
259                ///
260                /// # Example
261                #[doc = "```ignore"]
262                #[doc = concat!("use fmmap::", $path_str, "::{AsyncOptions, AsyncMmapFileMut, AsyncMmapFileExt, AsyncMmapFileMutExt};")]
263                /// # use scopeguard::defer;
264                ///
265                #[doc = concat!("# ", $doc_test_runtime, "::block_on(async {")]
266                /// let mut file = AsyncOptions::new()
267                ///     // truncate to 100
268                ///     .max_size(100)
269                #[doc = concat!(".create_mmap_file_mut(\"", $filename_prefix, "_create_with_options_test.txt\").await.unwrap();")]
270                #[doc = concat!("# defer!(std::fs::remove_file(\"", $filename_prefix, "_create_with_options_test.txt\").unwrap());")]
271                /// assert!(!file.is_empty());
272                /// file.write_all("some data...".as_bytes(), 0).unwrap();
273                /// file.flush().unwrap();
274                /// # })
275                #[doc = "```"]
276                ///
277                /// [`AsyncOptions`]: struct.AsyncOptions.html
278                pub async fn create_mmap_file_mut<P: AsRef<Path>>(self, path: P) -> Result<AsyncMmapFileMut, Error> {
279                    Ok(AsyncMmapFileMut::from(AsyncDiskMmapFileMut::create_with_options(path, self).await?))
280                }
281
282                /// Open a readable memory map backed by a file with [`Options`]
283                ///
284                /// # Example
285                ///
286                #[doc = "```ignore"]
287                #[doc = concat!("use fmmap::", $path_str, "::{AsyncOptions, AsyncMmapFile, AsyncMmapFileExt};")]
288                #[doc = concat!("# use fmmap::", $path_str, "::{AsyncMmapFileMut, AsyncMmapFileMutExt};")]
289                /// # use scopeguard::defer;
290                ///
291                #[doc = concat!("# ", $doc_test_runtime, "::block_on(async {")]
292                #[doc = concat!("# let mut file = AsyncMmapFileMut::create(\"", $filename_prefix, "_open_with_options_test.txt\").await.unwrap();")]
293                #[doc = concat!("# defer!(std::fs::remove_file(\"", $filename_prefix, "_open_with_options_test.txt\").unwrap());")]
294                /// # file.truncate(23).await.unwrap();
295                /// # file.write_all("sanity text".as_bytes(), 0).unwrap();
296                /// # file.write_all("some data...".as_bytes(), "sanity text".as_bytes().len()).unwrap();
297                /// # file.flush().unwrap();
298                /// # drop(file);
299                ///
300                /// // mmap the file
301                /// let file = AsyncOptions::new()
302                ///     // mmap content after the sanity text
303                ///     .offset("sanity text".as_bytes().len() as u64)
304                #[doc = concat!(".open_mmap_file(\"", $filename_prefix, "_open_with_options_test.txt\").await.unwrap();")]
305                /// let mut buf = vec![0; "some data...".len()];
306                /// file.read_exact(buf.as_mut_slice(), 0).unwrap();
307                /// assert_eq!(buf.as_slice(), "some data...".as_bytes());
308                /// # })
309                #[doc = "```"]
310                ///
311                /// [`AsyncOptions`]: struct.AsyncOptions.html
312                pub async fn open_mmap_file<P: AsRef<Path>>(self, path: P) -> Result<AsyncMmapFile, Error> {
313                    Ok(AsyncMmapFile::from(AsyncDiskMmapFile::open_with_options(path, self).await?))
314                }
315
316                /// Open a readable and executable memory map backed by a file with [`AsyncOptions`].
317                ///
318                /// # Examples
319                ///
320                #[doc = "```ignore"]
321                #[doc = concat!("use fmmap::", $path_str, "::{AsyncOptions, AsyncMmapFile, AsyncMmapFileExt};")]
322                #[doc = concat!("# use fmmap::", $path_str, "::{AsyncMmapFileMut, AsyncMmapFileMutExt};")]
323                /// # use scopeguard::defer;
324                ///
325                #[doc = concat!("# ", $doc_test_runtime, "::block_on(async {")]
326                #[doc = concat!("# let mut file = AsyncMmapFileMut::create(\"", $filename_prefix, "_open_exec_with_options_test.txt\").await.unwrap();")]
327                #[doc = concat!(" # defer!(std::fs::remove_file(\"", $filename_prefix, "_open_exec_with_options_test.txt\").unwrap());")]
328                /// # file.truncate(23).await.unwrap();
329                /// # file.write_all("sanity text".as_bytes(), 0).unwrap();
330                /// # file.write_all("some data...".as_bytes(), "sanity text".as_bytes().len()).unwrap();
331                /// # file.flush().unwrap();
332                /// # drop(file);
333                ///
334                /// // mmap the file
335                /// let file = AsyncOptions::new()
336                ///     // mmap content after the sanity text
337                ///     .offset("sanity text".as_bytes().len() as u64)
338                #[doc = concat!(".open_exec_mmap_file(\"", $filename_prefix, "_open_exec_with_options_test.txt\").await.unwrap();")]
339                /// let mut buf = vec![0; "some data...".len()];
340                /// file.read_exact(buf.as_mut_slice(), 0).unwrap();
341                /// assert_eq!(buf.as_slice(), "some data...".as_bytes());
342                /// # })
343                #[doc = "```"]
344                ///
345                /// [`AsyncOptions`]: struct.AsyncOptions.html
346                pub async fn open_exec_mmap_file<P: AsRef<Path>>(self, path: P) -> Result<AsyncMmapFile, Error> {
347                    Ok(AsyncMmapFile::from(AsyncDiskMmapFile::open_exec_with_options(path, self).await?))
348                }
349
350                /// Open or Create(if not exists) a file and mmap this file with [`AsyncOptions`].
351                ///
352                /// # Examples
353                ///
354                /// File already exists
355                ///
356                /// ```ignore
357                #[doc = concat!("use fmmap::", $path_str, "::{AsyncMmapFileMut, AsyncMmapFileExt, AsyncMmapFileMutExt, AsyncOptions};")]
358                /// # use scopeguard::defer;
359                ///
360                #[doc = concat!("# ", $doc_test_runtime, "::block_on(async {")]
361                #[doc = concat!("# let mut file = AsyncMmapFileMut::create(\"", $filename_prefix, "_open_with_options_test.txt\").await.unwrap();")]
362                #[doc = concat!("# defer!(std::fs::remove_file(\"", $filename_prefix, "_open_with_options_test.txt\").unwrap());")]
363                /// # file.truncate(23).await.unwrap();
364                /// # file.write_all("sanity text".as_bytes(), 0).unwrap();
365                /// # file.write_all("some data...".as_bytes(), "sanity text".as_bytes().len()).unwrap();
366                /// # file.flush().unwrap();
367                /// # drop(file);
368                ///
369                /// let mut file = AsyncOptions::new()
370                ///     // allow read
371                ///     .read(true)
372                ///     // allow write
373                ///     .write(true)
374                ///     // allow append
375                ///     .append(true)
376                ///     // truncate to 100
377                ///     .max_size(100)
378                ///     // mmap content after the sanity text
379                ///     .offset("sanity text".as_bytes().len() as u64)
380                #[doc = concat!(".open_mmap_file_mut(\"", $filename_prefix, "_open_with_options_test.txt\").await.unwrap();")]
381                /// let mut buf = vec![0; "some data...".len()];
382                /// file.read_exact(buf.as_mut_slice(), 0).unwrap();
383                /// assert_eq!(buf.as_slice(), "some data...".as_bytes());
384                ///
385                /// // modify the file data
386                /// file.truncate(("some modified data...".len() + "sanity text".len()) as u64).await.unwrap();
387                /// file.write_all("some modified data...".as_bytes(), 0).unwrap();
388                /// file.flush().unwrap();
389                /// drop(file);
390                ///
391                /// // reopen to check content
392                /// let mut buf = vec![0; "some modified data...".len()];
393                #[doc = concat!("let mut file = AsyncMmapFileMut::open(\"", $filename_prefix, "_open_with_options_test.txt\").await.unwrap();")]
394                /// // skip the sanity text
395                /// file.read_exact(buf.as_mut_slice(), "sanity text".as_bytes().len()).unwrap();
396                /// assert_eq!(buf.as_slice(), "some modified data...".as_bytes());
397                /// # })
398                #[doc = "```"]
399                ///
400                /// File does not exists
401                ///
402                /// ```ignore
403                #[doc = concat!("use fmmap::", $path_str, "::{AsyncMmapFileMut, AsyncMmapFileExt, AsyncMmapFileMutExt, AsyncOptions};")]
404                /// # use scopeguard::defer;
405                ///
406                #[doc = concat!("# ", $doc_test_runtime, "::block_on(async {")]
407                /// // mmap the file with options
408                /// let mut file = AsyncOptions::new()
409                ///     // allow read
410                ///     .read(true)
411                ///     // allow write
412                ///     .write(true)
413                ///     // allow append
414                ///     .append(true)
415                ///     // truncate to 100
416                ///     .max_size(100)
417                #[doc = concat!(".open_mmap_file_mut(\"", $filename_prefix, "_open_with_options_test.txt\").await.unwrap();")]
418                #[doc = concat!("# defer!(std::fs::remove_file(\"", $filename_prefix, "_open_with_options_test.txt\").unwrap());")]
419                /// file.write_all("some data...".as_bytes(), 0).unwrap();
420                ///
421                /// let mut buf = vec![0; "some data...".len()];
422                /// file.read_exact(buf.as_mut_slice(), 0).unwrap();
423                /// assert_eq!(buf.as_slice(), "some data...".as_bytes());
424                ///
425                /// // modify the file data
426                /// file.truncate("some modified data...".len() as u64).await.unwrap();
427                /// file.write_all("some modified data...".as_bytes(), 0).unwrap();
428                /// file.flush().unwrap();
429                /// drop(file);
430                ///
431                /// // reopen to check content
432                /// let mut buf = vec![0; "some modified data...".len()];
433                #[doc = concat!("let mut file = AsyncMmapFileMut::open(\"", $filename_prefix, "_open_with_options_test.txt\").await.unwrap();")]
434                /// file.read_exact(buf.as_mut_slice(), 0).unwrap();
435                /// assert_eq!(buf.as_slice(), "some modified data...".as_bytes());
436                /// # })
437                #[doc = "```"]
438                ///
439                /// [`AsyncOptions`]: struct.AsyncOptions.html
440                pub async fn open_mmap_file_mut<P: AsRef<Path>>(self, path: P) -> Result<AsyncMmapFileMut, Error> {
441                    Ok(AsyncMmapFileMut::from(AsyncDiskMmapFileMut::open_with_options(path, self).await?))
442                }
443
444                /// Open an existing file and mmap this file with [`AsyncOptions`]
445                ///
446                /// # Example
447                ///
448                /// ```ignore
449                #[doc = concat!("use fmmap::", $path_str, "::{AsyncMmapFileMut, AsyncMmapFileExt, AsyncMmapFileMutExt, AsyncOptions};")]
450                /// # use scopeguard::defer;
451                ///
452                #[doc = concat!("# ", $doc_test_runtime, "::block_on(async {")]
453                /// // create a temp file
454                #[doc = concat!("let mut file = AsyncMmapFileMut::create(\"", $filename_prefix, "_open_existing_test_with_options.txt\").await.unwrap();")]
455                #[doc = concat!("# defer!(std::fs::remove_file(\"", $filename_prefix, "_open_existing_test_with_options.txt\").unwrap());")]
456                /// file.truncate(23).await.unwrap();
457                /// file.write_all("sanity text".as_bytes(), 0).unwrap();
458                /// file.write_all("some data...".as_bytes(), "sanity text".as_bytes().len()).unwrap();
459                /// file.flush().unwrap();
460                /// drop(file);
461                ///
462                /// // mmap the file
463                /// let mut file = AsyncOptions::new()
464                ///     // truncate to 100
465                ///     .max_size(100)
466                ///     // mmap content after the sanity text
467                ///     .offset("sanity text".as_bytes().len() as u64)
468                #[doc = concat!(".open_exist_mmap_file_mut(\"", $filename_prefix, "_open_existing_test_with_options.txt\").await.unwrap();")]
469                ///
470                /// let mut buf = vec![0; "some data...".len()];
471                /// file.read_exact(buf.as_mut_slice(), 0).unwrap();
472                /// assert_eq!(buf.as_slice(), "some data...".as_bytes());
473                ///
474                /// // modify the file data
475                /// file.truncate(("some modified data...".len() + "sanity text".len()) as u64).await.unwrap();
476                /// file.write_all("some modified data...".as_bytes(), 0).unwrap();
477                /// file.flush().unwrap();
478                ///
479                /// // reopen to check content, cow will not change the content.
480                #[doc = concat!("let mut file = AsyncMmapFileMut::open(\"", $filename_prefix, "_open_existing_test_with_options.txt\").await.unwrap();")]
481                /// let mut buf = vec![0; "some modified data...".len()];
482                /// // skip the sanity text
483                /// file.read_exact(buf.as_mut_slice(), "sanity text".as_bytes().len()).unwrap();
484                /// assert_eq!(buf.as_slice(), "some modified data...".as_bytes());
485                /// # })
486                #[doc = "```"]
487                ///
488                /// [`AsyncOptions`]: struct.AsyncOptions.html
489                pub async fn open_exist_mmap_file_mut<P: AsRef<Path>>(self, path: P) -> Result<AsyncMmapFileMut, Error> {
490                    Ok(AsyncMmapFileMut::from(AsyncDiskMmapFileMut::open_exist_with_options(path, self).await?))
491                }
492
493                /// Open and mmap an existing file in copy-on-write mode(copy-on-write memory map backed by a file) with [`AsyncOptions`].
494                /// Data written to the memory map will not be visible by other processes, and will not be carried through to the underlying file.
495                ///
496                /// # Examples
497                ///
498                #[doc = "```ignore"]
499                #[doc = concat!("use fmmap::", $path_str, "::{AsyncMmapFileMut, AsyncMmapFileExt, AsyncMmapFileMutExt, AsyncOptions};")]
500                /// # use scopeguard::defer;
501                ///
502                #[doc = concat!("# ", $doc_test_runtime, "::block_on(async {")]
503                /// // create a temp file
504                #[doc = concat!("let mut file = AsyncMmapFileMut::create(\"", $filename_prefix, "_open_cow_with_options_test.txt\").await.unwrap();")]
505                #[doc = concat!("#  defer!(std::fs::remove_file(\"", $filename_prefix, "_open_cow_with_options_test.txt\").unwrap());")]
506                /// file.truncate(23).await.unwrap();
507                /// file.write_all("sanity text".as_bytes(), 0).unwrap();
508                /// file.write_all("some data...".as_bytes(), "sanity text".as_bytes().len()).unwrap();
509                /// file.flush().unwrap();
510                /// drop(file);
511                ///
512                /// // mmap the file
513                /// let mut file = AsyncOptions::new()
514                ///     // mmap content after the sanity text
515                ///     .offset("sanity text".as_bytes().len() as u64)
516                #[doc = concat!(".open_cow_mmap_file_mut(\"", $filename_prefix, "_open_cow_with_options_test.txt\").await.unwrap();")]
517                /// assert!(file.is_cow());
518                ///
519                /// let mut buf = vec![0; "some data...".len()];
520                /// file.read_exact(buf.as_mut_slice(), 0).unwrap();
521                /// assert_eq!(buf.as_slice(), "some data...".as_bytes());
522                ///
523                /// // modify the file data
524                /// file.write_all("some data!!!".as_bytes(), 0).unwrap();
525                /// file.flush().unwrap();
526                ///
527                /// // cow, change will only be seen in current caller
528                /// assert_eq!(file.as_slice(), "some data!!!".as_bytes());
529                /// drop(file);
530                ///
531                /// // reopen to check content, cow will not change the content.
532                #[doc = concat!("let mut file = AsyncMmapFileMut::open(\"", $filename_prefix, "_open_cow_with_options_test.txt\").await.unwrap();")]
533                /// let mut buf = vec![0; "some data...".len()];
534                /// // skip the sanity text
535                /// file.read_exact(buf.as_mut_slice(), "sanity text".as_bytes().len()).unwrap();
536                /// assert_eq!(buf.as_slice(), "some data...".as_bytes());
537                /// # })
538                #[doc = "```"]
539                ///
540                ///
541                /// [`AsyncOptions`]: struct.AsyncOptions.html
542                pub async fn open_cow_mmap_file_mut<P: AsRef<Path>>(self, path: P) -> Result<AsyncMmapFileMut, Error> {
543                    Ok(AsyncMmapFileMut::from(AsyncDiskMmapFileMut::open_cow_with_options(path, self).await?))
544                }
545            }
546        };
547    }
548
549    macro_rules! impl_async_options_tests {
550        ($filename_prefix: literal, $runtime: meta, $path_str: ident) => {
551            #[cfg(test)]
552            mod tests {
553                use crate::$path_str::{AsyncOptions, AsyncMmapFileMut, AsyncMmapFileMutExt, AsyncMmapFileExt};
554                use scopeguard::defer;
555
556                #[$runtime]
557                async fn test_create_mmap_file_mut() {
558                    let path = concat!($filename_prefix, "_options_create_mmap_file_mut.txt");
559                    defer!(std::fs::remove_file(path).unwrap());
560                    let mut file = AsyncOptions::new()
561                        // truncate to 100
562                        .max_size(100)
563                        .create_mmap_file_mut(path).await.unwrap();
564
565                    assert!(!file.is_empty());
566                    file.write_all("some data...".as_bytes(), 0).unwrap();
567                    file.flush().unwrap();
568                }
569
570                #[$runtime]
571                async fn test_open_mmap_file() {
572                    let path = concat!($filename_prefix, "_options_open_mmap_file.txt");
573                    defer!(std::fs::remove_file(path).unwrap());
574                    let mut file = AsyncMmapFileMut::create(path).await.unwrap();
575                    file.truncate(23).await.unwrap();
576                    file.write_all("sanity text".as_bytes(), 0).unwrap();
577                    file.write_all("some data...".as_bytes(), "sanity text".as_bytes().len()).unwrap();
578                    file.flush().unwrap();
579                    drop(file);
580
581                    // mmap the file
582                    let file = AsyncOptions::new()
583                        // mmap content after the sanity text
584                        .offset("sanity text".as_bytes().len() as u64)
585                        .open_mmap_file(path).await.unwrap();
586                    let mut buf = vec![0; "some data...".len()];
587                    file.read_exact(buf.as_mut_slice(), 0).unwrap();
588                    assert_eq!(buf.as_slice(), "some data...".as_bytes());
589                }
590
591                #[$runtime]
592                async fn test_open_mmap_file_exec() {
593                    let path = concat!($filename_prefix, "_options_open_exec_mmap_file.txt");
594                    defer!(std::fs::remove_file(path).unwrap());
595                    let mut file = AsyncMmapFileMut::create(path).await.unwrap();
596                    file.truncate(23).await.unwrap();
597                    file.write_all("sanity text".as_bytes(), 0).unwrap();
598                    file.write_all("some data...".as_bytes(), "sanity text".as_bytes().len()).unwrap();
599                    file.flush().unwrap();
600                    drop(file);
601
602                    // mmap the file
603                    let file = AsyncOptions::new()
604                        // mmap content after the sanity text
605                        .offset("sanity text".as_bytes().len() as u64)
606                        .open_exec_mmap_file(path).await.unwrap();
607                    let mut buf = vec![0; "some data...".len()];
608                    file.read_exact(buf.as_mut_slice(), 0).unwrap();
609                    assert_eq!(buf.as_slice(), "some data...".as_bytes());
610                }
611
612                #[$runtime]
613                async fn test_open_mmap_file_mut() {
614                    let path = concat!($filename_prefix, "_options_open_mmap_file_mut.txt");
615                    defer!(std::fs::remove_file(path).unwrap());
616                    let mut file = AsyncMmapFileMut::create(path).await.unwrap();
617                    file.truncate(23).await.unwrap();
618                    file.write_all("sanity text".as_bytes(), 0).unwrap();
619                    file.write_all("some data...".as_bytes(), "sanity text".as_bytes().len()).unwrap();
620                    file.flush().unwrap();
621                    drop(file);
622
623                    let mut file = AsyncOptions::new()
624                        // allow read
625                        .read(true)
626                        // allow write
627                        .write(true)
628                        // allow append
629                        .append(true)
630                        // truncate to 100
631                        .max_size(100)
632                        // mmap content after the sanity text
633                        .offset("sanity text".as_bytes().len() as u64)
634                        .open_mmap_file_mut(path).await.unwrap();
635                    let mut buf = vec![0; "some data...".len()];
636                    file.read_exact(buf.as_mut_slice(), 0).unwrap();
637                    assert_eq!(buf.as_slice(), "some data...".as_bytes());
638
639                    // modify the file data
640                    file.truncate(("some modified data...".len() + "sanity text".len()) as u64).await.unwrap();
641                    file.write_all("some modified data...".as_bytes(), 0).unwrap();
642                    file.flush().unwrap();
643                    drop(file);
644
645                    // reopen to check content
646                    let mut buf = vec![0; "some modified data...".len()];
647                    let file = AsyncMmapFileMut::open(path).await.unwrap();
648                    // skip the sanity text
649                    file.read_exact(buf.as_mut_slice(), "sanity text".as_bytes().len()).unwrap();
650                    assert_eq!(buf.as_slice(), "some modified data...".as_bytes());
651                }
652
653                #[$runtime]
654                async fn open_exist_mmap_file_mut() {
655                    let path = concat!($filename_prefix, "_options_open_exist_mmap_file_mut.txt");
656                    defer!(std::fs::remove_file(path).unwrap());
657                    let mut file = AsyncMmapFileMut::create(path).await.unwrap();
658                    file.truncate(23).await.unwrap();
659                    file.write_all("sanity text".as_bytes(), 0).unwrap();
660                    file.write_all("some data...".as_bytes(), "sanity text".as_bytes().len()).unwrap();
661                    file.flush().unwrap();
662                    drop(file);
663
664                    // mmap the file
665                    let mut file = AsyncOptions::new()
666                        // truncate to 100
667                        .max_size(100)
668                        // mmap content after the sanity text
669                        .offset("sanity text".as_bytes().len() as u64)
670                        .open_exist_mmap_file_mut(path).await.unwrap();
671
672                    let mut buf = vec![0; "some data...".len()];
673                    file.read_exact(buf.as_mut_slice(), 0).unwrap();
674                    assert_eq!(buf.as_slice(), "some data...".as_bytes());
675
676                    // modify the file data
677                    file.truncate(("some modified data...".len() + "sanity text".len()) as u64).await.unwrap();
678                    file.write_all("some modified data...".as_bytes(), 0).unwrap();
679                    file.flush().unwrap();
680
681                    // reopen to check content, cow will not change the content.
682                    let file = AsyncMmapFileMut::open(path).await.unwrap();
683                    let mut buf = vec![0; "some modified data...".len()];
684                    // skip the sanity text
685                    file.read_exact(buf.as_mut_slice(), "sanity text".as_bytes().len()).unwrap();
686                    assert_eq!(buf.as_slice(), "some modified data...".as_bytes());
687                }
688
689                #[$runtime]
690                async fn open_cow_mmap_file_mut() {
691                    let path = concat!($filename_prefix, "_options_open_cow_mmap_file_mut.txt");
692                    defer!(std::fs::remove_file(path).unwrap());
693                    let mut file = AsyncMmapFileMut::create(path).await.unwrap();
694                    file.truncate(23).await.unwrap();
695                    file.write_all("sanity text".as_bytes(), 0).unwrap();
696                    file.write_all("some data...".as_bytes(), "sanity text".as_bytes().len()).unwrap();
697                    file.flush().unwrap();
698                    drop(file);
699
700                    // mmap the file
701                    let mut file = AsyncOptions::new()
702                        // mmap content after the sanity text
703                        .offset("sanity text".as_bytes().len() as u64)
704                        .open_cow_mmap_file_mut(path).await.unwrap();
705                    assert!(file.is_cow());
706
707                    let mut buf = vec![0; "some data...".len()];
708                    file.read_exact(buf.as_mut_slice(), 0).unwrap();
709                    assert_eq!(buf.as_slice(), "some data...".as_bytes());
710
711                    // modify the file data
712                    file.write_all("some data!!!".as_bytes(), 0).unwrap();
713                    file.flush().unwrap();
714
715                    // cow, change will only be seen in current caller
716                    assert_eq!(file.as_slice(), "some data!!!".as_bytes());
717                    drop(file);
718
719                    // reopen to check content, cow will not change the content.
720                    let file = AsyncMmapFileMut::open(path).await.unwrap();
721                    let mut buf = vec![0; "some data...".len()];
722                    // skip the sanity text
723                    file.read_exact(buf.as_mut_slice(), "sanity text".as_bytes().len()).unwrap();
724                    assert_eq!(buf.as_slice(), "some data...".as_bytes());
725                }
726            }
727        };
728    }
729}
730
731cfg_async_std!(
732    pub mod async_std_impl;
733);
734
735cfg_smol!(
736    pub mod smol_impl;
737);
738
739cfg_tokio!(
740    pub mod tokio_impl;
741);