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);