macro_rules! declare_and_impl_options {
($name: ident, $file_open_options: ident) => {
/// A memory map builder, providing advanced options and flags for specifying memory map file behavior.
///
// TODO: support file lock options
#[derive(Clone)]
pub struct $name {
pub(crate) mmap_opts: MmapOptions,
pub(crate) file_opts: $file_open_options,
pub(crate) max_size: u64,
}
impl Default for $name {
fn default() -> Self {
Self::new()
}
}
impl $name {
/// Creates a new set of options for configuring and creating a memory map.
pub fn new() -> Self {
Self {
mmap_opts: MmapOptions::new(),
file_opts: <$file_open_options>::new(),
max_size: 0,
}
}
/// Configures the memory map to start at byte offset from the beginning of the file.
/// This option has no effect on anonymous memory maps.
/// By default, the offset is 0.
pub fn offset(mut self, offset: u64) -> Self {
self.mmap_opts.offset(offset);
self
}
/// Configures the created memory mapped buffer to be len bytes long.
/// This option is mandatory for anonymous memory maps.
/// For file-backed memory maps, the length will default to the file length.
pub fn len(mut self, len: usize) -> Self {
self.mmap_opts.len(len);
self
}
/// Populate (prefault) page tables for a mapping.
/// For a file mapping, this causes read-ahead on the file. This will help to reduce blocking on page faults later.
/// This option corresponds to the MAP_POPULATE flag on Linux. It has no effect on Windows
pub fn populate(mut self) -> Self {
self.mmap_opts.populate();
self
}
/// Configures the anonymous memory map to be suitable for a process or thread stack.
/// This option corresponds to the MAP_STACK flag on Linux. It has no effect on Windows.
/// This option has no effect on file-backed memory maps
pub fn stack(mut self) -> Self {
self.mmap_opts.stack();
self
}
/// Configures the max size of the file.
///
/// This option only has effect when mmaping a real file in write mode.
///
/// This field is ignored when opening [`DiskMmapFile`], [`AsyncDiskMmapFile`], [`MmapFile`] and [`AsyncMmapFile`].
///
/// [`DiskMmapFile`]: fmmap::raw::DiskMmapFile
/// [`AsyncDiskMmapFile`]: fmmap::raw::AsyncDiskMmapFile
/// [`MmapFile`]: struct.MmapFile.html
/// [`AsyncMmapFile`]: struct.AsyncMmapFile.html
pub fn max_size(mut self, max_sz: u64) -> Self {
self.max_size = max_sz;
self
}
/// Sets the option for read access. For details, please see [`std::fs::OpenOptions::read`]
///
/// [`std::fs::OpenOptions::read`]: https://doc.rust-lang.org/std/fs/struct.OpenOptions.html#method.read
pub fn read(mut self, val: bool) -> Self {
self.file_opts.read(val);
self
}
/// Sets the option for write access. For details, please see [`std::fs::OpenOptions::write`].
///
/// This field is ignored when opening [`DiskMmapFile`], [`AsyncDiskMmapFile`], [`MmapFile`] and [`AsyncMmapFile`].
///
/// [`DiskMmapFile`]: fmmap::raw::DiskMmapFile
/// [`AsyncDiskMmapFile`]: fmmap::raw::AsyncDiskMmapFile
/// [`MmapFile`]: struct.MmapFile.html
/// [`AsyncMmapFile`]: struct.AsyncMmapFile.html
/// [`std::fs::OpenOptions::write`]: https://doc.rust-lang.org/std/fs/struct.OpenOptions.html#method.write
pub fn write(mut self, val: bool) -> Self {
self.file_opts.write(val);
self
}
/// Sets the option to create a new file, or open it if it already exists. For details, please see [`std::fs::OpenOptions::create`].
///
/// This field is ignored when opening [`DiskMmapFile`], [`AsyncDiskMmapFile`], [`MmapFile`] and [`AsyncMmapFile`].
///
/// [`DiskMmapFile`]: fmmap::raw::DiskMmapFile
/// [`AsyncDiskMmapFile`]: fmmap::raw::AsyncDiskMmapFile
/// [`MmapFile`]: struct.MmapFile.html
/// [`AsyncMmapFile`]: struct.AsyncMmapFile.html
/// [`std::fs::OpenOptions::create`]: https://doc.rust-lang.org/std/fs/struct.OpenOptions.html#method.create
pub fn create(mut self, val: bool) -> Self {
self.file_opts.create(val);
self
}
/// Sets the option to create a new file, failing if it already exists. For details, please see [`std::fs::OpenOptions::create_new`]
///
/// This field is ignored when opening [`DiskMmapFile`], [`AsyncDiskMmapFile`], [`MmapFile`] and [`AsyncMmapFile`].
///
/// [`DiskMmapFile`]: fmmap::raw::DiskMmapFile
/// [`AsyncDiskMmapFile`]: fmmap::raw::AsyncDiskMmapFile
/// [`MmapFile`]: struct.MmapFile.html
/// [`AsyncMmapFile`]: struct.AsyncMmapFile.html
/// [`std::fs::OpenOptions::create_new`]: https://doc.rust-lang.org/std/fs/struct.OpenOptions.html#method.create_new
pub fn create_new(mut self, val: bool) -> Self {
self.file_opts.create_new(val);
self
}
/// Sets the option for the append mode. For details, please see [`std::fs::OpenOptions::append`]
///
/// This field is ignored when opening [`DiskMmapFile`], [`AsyncDiskMmapFile`], [`MmapFile`] and [`AsyncMmapFile`].
///
/// [`DiskMmapFile`]: fmmap::raw::DiskMmapFile
/// [`AsyncDiskMmapFile`]: fmmap::raw::AsyncDiskMmapFile
/// [`MmapFile`]: struct.MmapFile.html
/// [`AsyncMmapFile`]: struct.AsyncMmapFile.html
/// [`std::fs::OpenOptions::append`]: https://doc.rust-lang.org/std/fs/struct.OpenOptions.html#method.append
pub fn append(mut self, val: bool) -> Self {
self.file_opts.append(val);
self
}
/// Sets the option for truncating a previous file. For details, please see [`std::fs::OpenOptions::truncate`]
///
/// This field is ignored when opening [`DiskMmapFile`], [`AsyncDiskMmapFile`], [`MmapFile`] and [`AsyncMmapFile`].
///
/// [`DiskMmapFile`]: fmmap::raw::DiskMmapFile
/// [`AsyncDiskMmapFile`]: fmmap::raw::AsyncDiskMmapFile
/// [`MmapFile`]: struct.MmapFile.html
/// [`AsyncMmapFile`]: struct.AsyncMmapFile.html
/// [`std::fs::OpenOptions::truncate`]: https://doc.rust-lang.org/std/fs/struct.OpenOptions.html#method.truncate
pub fn truncate(mut self, val: bool) -> Self {
self.file_opts.truncate(val);
self
}
}
};
}
#[cfg(unix)]
macro_rules! impl_options_unix_ext {
($name: ident) => {
#[cfg(unix)]
impl $name {
/// Sets the mode bits that a new file will be created with. [Read more]
///
/// [Read more]: https://doc.rust-lang.org/std/os/unix/fs/trait.OpenOptionsExt.html#tymethod.mode
#[cfg(unix)]
pub fn mode(mut self, mode: u32) -> Self {
self.file_opts.mode(mode);
self
}
/// Pass custom flags to the `flags` argument of `open`. [Read more]
///
/// [Read more]: https://doc.rust-lang.org/std/os/unix/fs/trait.OpenOptionsExt.html#tymethod.mode
#[cfg(unix)]
pub fn custom_flags(mut self, flags: i32) -> Self {
self.file_opts.custom_flags(flags);
self
}
}
};
}
#[cfg(windows)]
macro_rules! impl_options_windows_ext {
($name: ident) => {
#[cfg(windows)]
impl $name {
/// Overrides the `dwDesiredAccess` argument to the call to [`CreateFile`] with the specified value. [Read more]
///
/// [`CreateFile`]: https://docs.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-createfilea
/// [Read more]: https://doc.rust-lang.org/std/os/windows/fs/trait.OpenOptionsExt.html#tymethod.security_qos_flags
#[cfg(windows)]
pub fn access_mode(mut self, access: u32) -> Self {
self.file_opts.access_mode(access);
self
}
/// Overrides the `dwShareMode` argument to the call to [`CreateFile`] with the specified value. [Read more]
///
/// [`CreateFile`]: https://docs.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-createfilea
/// [Read more]: https://doc.rust-lang.org/std/os/windows/fs/trait.OpenOptionsExt.html#tymethod.security_qos_flags
#[cfg(windows)]
pub fn share_mode(mut self, val: u32) -> Self {
self.file_opts.share_mode(val);
self
}
/// Sets extra flags for the dwFileFlags argument to the
/// call to [`CreateFile2`] to the specified value (or combines
/// it with `attributes` and `security_qos_flags` to set the `dwFlagsAndAttributes` for [`CreateFile`]). [Read more]
///
/// [`CreateFile2`]: https://docs.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-createfile2
/// [`CreateFile`]: https://docs.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-createfilea
/// [Read more]: https://doc.rust-lang.org/std/os/windows/fs/trait.OpenOptionsExt.html#tymethod.security_qos_flags
#[cfg(windows)]
pub fn custom_flags(mut self, flag: u32) -> Self {
self.file_opts.custom_flags(flag);
self
}
/// Overrides the `dwDesiredAccess` argument to the call to [`CreateFile`] with the specified value. [Read more]
///
/// [`CreateFile`]: https://docs.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-createfilea
/// [Read more]: https://doc.rust-lang.org/std/os/windows/fs/trait.OpenOptionsExt.html#tymethod.security_qos_flags
#[cfg(windows)]
pub fn attributes(mut self, val: u32) -> Self {
self.file_opts.attributes(val);
self
}
/// Sets the `dwSecurityQosFlags` argument to the call to
/// [`CreateFile2`] to the specified value (or combines it with `custom_flags`
/// and `attributes` to set the `dwFlagsAndAttributes` for [`CreateFile`]). [Read more]
///
/// [`CreateFile2`]: https://docs.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-createfile2
/// [`CreateFile`]: https://docs.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-createfilea
/// [Read more]: https://doc.rust-lang.org/std/os/windows/fs/trait.OpenOptionsExt.html#tymethod.security_qos_flags
#[cfg(windows)]
pub fn security_qos_flags(mut self, flags: u32) -> Self {
self.file_opts.security_qos_flags(flags);
self
}
}
};
}
cfg_sync!(
mod sync_impl;
pub use sync_impl::Options;
);
cfg_async! {
macro_rules! declare_and_impl_async_options {
($filename_prefix: literal, $doc_test_runtime: literal, $path_str: literal) => {
declare_and_impl_options!(AsyncOptions, OpenOptions);
impl AsyncOptions {
/// Create a new file and mmap this file with [`AsyncOptions`]
///
/// # Example
#[doc = "```ignore"]
#[doc = concat!("use fmmap::", $path_str, "::{AsyncOptions, AsyncMmapFileMut, AsyncMmapFileExt, AsyncMmapFileMutExt};")]
/// # use scopeguard::defer;
///
#[doc = concat!("# ", $doc_test_runtime, "::block_on(async {")]
/// let mut file = AsyncOptions::new()
/// // truncate to 100
/// .max_size(100)
#[doc = concat!(".create_mmap_file_mut(\"", $filename_prefix, "_create_with_options_test.txt\").await.unwrap();")]
#[doc = concat!("# defer!(std::fs::remove_file(\"", $filename_prefix, "_create_with_options_test.txt\").unwrap());")]
/// assert!(!file.is_empty());
/// file.write_all("some data...".as_bytes(), 0).unwrap();
/// file.flush().unwrap();
/// # })
#[doc = "```"]
///
/// [`AsyncOptions`]: struct.AsyncOptions.html
pub async fn create_mmap_file_mut<P: AsRef<Path>>(self, path: P) -> Result<AsyncMmapFileMut, Error> {
Ok(AsyncMmapFileMut::from(AsyncDiskMmapFileMut::create_with_options(path, self).await?))
}
/// Open a readable memory map backed by a file with [`Options`]
///
/// # Example
///
#[doc = "```ignore"]
#[doc = concat!("use fmmap::", $path_str, "::{AsyncOptions, AsyncMmapFile, AsyncMmapFileExt};")]
#[doc = concat!("# use fmmap::", $path_str, "::{AsyncMmapFileMut, AsyncMmapFileMutExt};")]
/// # use scopeguard::defer;
///
#[doc = concat!("# ", $doc_test_runtime, "::block_on(async {")]
#[doc = concat!("# let mut file = AsyncMmapFileMut::create(\"", $filename_prefix, "_open_with_options_test.txt\").await.unwrap();")]
#[doc = concat!("# defer!(std::fs::remove_file(\"", $filename_prefix, "_open_with_options_test.txt\").unwrap());")]
/// # file.truncate(23).await.unwrap();
/// # file.write_all("sanity text".as_bytes(), 0).unwrap();
/// # file.write_all("some data...".as_bytes(), "sanity text".as_bytes().len()).unwrap();
/// # file.flush().unwrap();
/// # drop(file);
///
/// // mmap the file
/// let file = AsyncOptions::new()
/// // mmap content after the sanity text
/// .offset("sanity text".as_bytes().len() as u64)
#[doc = concat!(".open_mmap_file(\"", $filename_prefix, "_open_with_options_test.txt\").await.unwrap();")]
/// let mut buf = vec![0; "some data...".len()];
/// file.read_exact(buf.as_mut_slice(), 0).unwrap();
/// assert_eq!(buf.as_slice(), "some data...".as_bytes());
/// # })
#[doc = "```"]
///
/// [`AsyncOptions`]: struct.AsyncOptions.html
pub async fn open_mmap_file<P: AsRef<Path>>(self, path: P) -> Result<AsyncMmapFile, Error> {
Ok(AsyncMmapFile::from(AsyncDiskMmapFile::open_with_options(path, self).await?))
}
/// Open a readable and executable memory map backed by a file with [`AsyncOptions`].
///
/// # Examples
///
#[doc = "```ignore"]
#[doc = concat!("use fmmap::", $path_str, "::{AsyncOptions, AsyncMmapFile, AsyncMmapFileExt};")]
#[doc = concat!("# use fmmap::", $path_str, "::{AsyncMmapFileMut, AsyncMmapFileMutExt};")]
/// # use scopeguard::defer;
///
#[doc = concat!("# ", $doc_test_runtime, "::block_on(async {")]
#[doc = concat!("# let mut file = AsyncMmapFileMut::create(\"", $filename_prefix, "_open_exec_with_options_test.txt\").await.unwrap();")]
#[doc = concat!(" # defer!(std::fs::remove_file(\"", $filename_prefix, "_open_exec_with_options_test.txt\").unwrap());")]
/// # file.truncate(23).await.unwrap();
/// # file.write_all("sanity text".as_bytes(), 0).unwrap();
/// # file.write_all("some data...".as_bytes(), "sanity text".as_bytes().len()).unwrap();
/// # file.flush().unwrap();
/// # drop(file);
///
/// // mmap the file
/// let file = AsyncOptions::new()
/// // mmap content after the sanity text
/// .offset("sanity text".as_bytes().len() as u64)
#[doc = concat!(".open_exec_mmap_file(\"", $filename_prefix, "_open_exec_with_options_test.txt\").await.unwrap();")]
/// let mut buf = vec![0; "some data...".len()];
/// file.read_exact(buf.as_mut_slice(), 0).unwrap();
/// assert_eq!(buf.as_slice(), "some data...".as_bytes());
/// # })
#[doc = "```"]
///
/// [`AsyncOptions`]: struct.AsyncOptions.html
pub async fn open_exec_mmap_file<P: AsRef<Path>>(self, path: P) -> Result<AsyncMmapFile, Error> {
Ok(AsyncMmapFile::from(AsyncDiskMmapFile::open_exec_with_options(path, self).await?))
}
/// Open or Create(if not exists) a file and mmap this file with [`AsyncOptions`].
///
/// # Examples
///
/// File already exists
///
/// ```ignore
#[doc = concat!("use fmmap::", $path_str, "::{AsyncMmapFileMut, AsyncMmapFileExt, AsyncMmapFileMutExt, AsyncOptions};")]
/// # use scopeguard::defer;
///
#[doc = concat!("# ", $doc_test_runtime, "::block_on(async {")]
#[doc = concat!("# let mut file = AsyncMmapFileMut::create(\"", $filename_prefix, "_open_with_options_test.txt\").await.unwrap();")]
#[doc = concat!("# defer!(std::fs::remove_file(\"", $filename_prefix, "_open_with_options_test.txt\").unwrap());")]
/// # file.truncate(23).await.unwrap();
/// # file.write_all("sanity text".as_bytes(), 0).unwrap();
/// # file.write_all("some data...".as_bytes(), "sanity text".as_bytes().len()).unwrap();
/// # file.flush().unwrap();
/// # drop(file);
///
/// let mut file = AsyncOptions::new()
/// // allow read
/// .read(true)
/// // allow write
/// .write(true)
/// // allow append
/// .append(true)
/// // truncate to 100
/// .max_size(100)
/// // mmap content after the sanity text
/// .offset("sanity text".as_bytes().len() as u64)
#[doc = concat!(".open_mmap_file_mut(\"", $filename_prefix, "_open_with_options_test.txt\").await.unwrap();")]
/// let mut buf = vec![0; "some data...".len()];
/// file.read_exact(buf.as_mut_slice(), 0).unwrap();
/// assert_eq!(buf.as_slice(), "some data...".as_bytes());
///
/// // modify the file data
/// file.truncate(("some modified data...".len() + "sanity text".len()) as u64).await.unwrap();
/// file.write_all("some modified data...".as_bytes(), 0).unwrap();
/// file.flush().unwrap();
/// drop(file);
///
/// // reopen to check content
/// let mut buf = vec![0; "some modified data...".len()];
#[doc = concat!("let mut file = AsyncMmapFileMut::open(\"", $filename_prefix, "_open_with_options_test.txt\").await.unwrap();")]
/// // skip the sanity text
/// file.read_exact(buf.as_mut_slice(), "sanity text".as_bytes().len()).unwrap();
/// assert_eq!(buf.as_slice(), "some modified data...".as_bytes());
/// # })
#[doc = "```"]
///
/// File does not exists
///
/// ```ignore
#[doc = concat!("use fmmap::", $path_str, "::{AsyncMmapFileMut, AsyncMmapFileExt, AsyncMmapFileMutExt, AsyncOptions};")]
/// # use scopeguard::defer;
///
#[doc = concat!("# ", $doc_test_runtime, "::block_on(async {")]
/// // mmap the file with options
/// let mut file = AsyncOptions::new()
/// // allow read
/// .read(true)
/// // allow write
/// .write(true)
/// // allow append
/// .append(true)
/// // truncate to 100
/// .max_size(100)
#[doc = concat!(".open_mmap_file_mut(\"", $filename_prefix, "_open_with_options_test.txt\").await.unwrap();")]
#[doc = concat!("# defer!(std::fs::remove_file(\"", $filename_prefix, "_open_with_options_test.txt\").unwrap());")]
/// file.write_all("some data...".as_bytes(), 0).unwrap();
///
/// let mut buf = vec![0; "some data...".len()];
/// file.read_exact(buf.as_mut_slice(), 0).unwrap();
/// assert_eq!(buf.as_slice(), "some data...".as_bytes());
///
/// // modify the file data
/// file.truncate("some modified data...".len() as u64).await.unwrap();
/// file.write_all("some modified data...".as_bytes(), 0).unwrap();
/// file.flush().unwrap();
/// drop(file);
///
/// // reopen to check content
/// let mut buf = vec![0; "some modified data...".len()];
#[doc = concat!("let mut file = AsyncMmapFileMut::open(\"", $filename_prefix, "_open_with_options_test.txt\").await.unwrap();")]
/// file.read_exact(buf.as_mut_slice(), 0).unwrap();
/// assert_eq!(buf.as_slice(), "some modified data...".as_bytes());
/// # })
#[doc = "```"]
///
/// [`AsyncOptions`]: struct.AsyncOptions.html
pub async fn open_mmap_file_mut<P: AsRef<Path>>(self, path: P) -> Result<AsyncMmapFileMut, Error> {
Ok(AsyncMmapFileMut::from(AsyncDiskMmapFileMut::open_with_options(path, self).await?))
}
/// Open an existing file and mmap this file with [`AsyncOptions`]
///
/// # Example
///
/// ```ignore
#[doc = concat!("use fmmap::", $path_str, "::{AsyncMmapFileMut, AsyncMmapFileExt, AsyncMmapFileMutExt, AsyncOptions};")]
/// # use scopeguard::defer;
///
#[doc = concat!("# ", $doc_test_runtime, "::block_on(async {")]
/// // create a temp file
#[doc = concat!("let mut file = AsyncMmapFileMut::create(\"", $filename_prefix, "_open_existing_test_with_options.txt\").await.unwrap();")]
#[doc = concat!("# defer!(std::fs::remove_file(\"", $filename_prefix, "_open_existing_test_with_options.txt\").unwrap());")]
/// file.truncate(23).await.unwrap();
/// file.write_all("sanity text".as_bytes(), 0).unwrap();
/// file.write_all("some data...".as_bytes(), "sanity text".as_bytes().len()).unwrap();
/// file.flush().unwrap();
/// drop(file);
///
/// // mmap the file
/// let mut file = AsyncOptions::new()
/// // truncate to 100
/// .max_size(100)
/// // mmap content after the sanity text
/// .offset("sanity text".as_bytes().len() as u64)
#[doc = concat!(".open_exist_mmap_file_mut(\"", $filename_prefix, "_open_existing_test_with_options.txt\").await.unwrap();")]
///
/// let mut buf = vec![0; "some data...".len()];
/// file.read_exact(buf.as_mut_slice(), 0).unwrap();
/// assert_eq!(buf.as_slice(), "some data...".as_bytes());
///
/// // modify the file data
/// file.truncate(("some modified data...".len() + "sanity text".len()) as u64).await.unwrap();
/// file.write_all("some modified data...".as_bytes(), 0).unwrap();
/// file.flush().unwrap();
///
/// // reopen to check content, cow will not change the content.
#[doc = concat!("let mut file = AsyncMmapFileMut::open(\"", $filename_prefix, "_open_existing_test_with_options.txt\").await.unwrap();")]
/// let mut buf = vec![0; "some modified data...".len()];
/// // skip the sanity text
/// file.read_exact(buf.as_mut_slice(), "sanity text".as_bytes().len()).unwrap();
/// assert_eq!(buf.as_slice(), "some modified data...".as_bytes());
/// # })
#[doc = "```"]
///
/// [`AsyncOptions`]: struct.AsyncOptions.html
pub async fn open_exist_mmap_file_mut<P: AsRef<Path>>(self, path: P) -> Result<AsyncMmapFileMut, Error> {
Ok(AsyncMmapFileMut::from(AsyncDiskMmapFileMut::open_exist_with_options(path, self).await?))
}
/// Open and mmap an existing file in copy-on-write mode(copy-on-write memory map backed by a file) with [`AsyncOptions`].
/// Data written to the memory map will not be visible by other processes, and will not be carried through to the underlying file.
///
/// # Examples
///
#[doc = "```ignore"]
#[doc = concat!("use fmmap::", $path_str, "::{AsyncMmapFileMut, AsyncMmapFileExt, AsyncMmapFileMutExt, AsyncOptions};")]
/// # use scopeguard::defer;
///
#[doc = concat!("# ", $doc_test_runtime, "::block_on(async {")]
/// // create a temp file
#[doc = concat!("let mut file = AsyncMmapFileMut::create(\"", $filename_prefix, "_open_cow_with_options_test.txt\").await.unwrap();")]
#[doc = concat!("# defer!(std::fs::remove_file(\"", $filename_prefix, "_open_cow_with_options_test.txt\").unwrap());")]
/// file.truncate(23).await.unwrap();
/// file.write_all("sanity text".as_bytes(), 0).unwrap();
/// file.write_all("some data...".as_bytes(), "sanity text".as_bytes().len()).unwrap();
/// file.flush().unwrap();
/// drop(file);
///
/// // mmap the file
/// let mut file = AsyncOptions::new()
/// // mmap content after the sanity text
/// .offset("sanity text".as_bytes().len() as u64)
#[doc = concat!(".open_cow_mmap_file_mut(\"", $filename_prefix, "_open_cow_with_options_test.txt\").await.unwrap();")]
/// assert!(file.is_cow());
///
/// let mut buf = vec![0; "some data...".len()];
/// file.read_exact(buf.as_mut_slice(), 0).unwrap();
/// assert_eq!(buf.as_slice(), "some data...".as_bytes());
///
/// // modify the file data
/// file.write_all("some data!!!".as_bytes(), 0).unwrap();
/// file.flush().unwrap();
///
/// // cow, change will only be seen in current caller
/// assert_eq!(file.as_slice(), "some data!!!".as_bytes());
/// drop(file);
///
/// // reopen to check content, cow will not change the content.
#[doc = concat!("let mut file = AsyncMmapFileMut::open(\"", $filename_prefix, "_open_cow_with_options_test.txt\").await.unwrap();")]
/// let mut buf = vec![0; "some data...".len()];
/// // skip the sanity text
/// file.read_exact(buf.as_mut_slice(), "sanity text".as_bytes().len()).unwrap();
/// assert_eq!(buf.as_slice(), "some data...".as_bytes());
/// # })
#[doc = "```"]
///
///
/// [`AsyncOptions`]: struct.AsyncOptions.html
pub async fn open_cow_mmap_file_mut<P: AsRef<Path>>(self, path: P) -> Result<AsyncMmapFileMut, Error> {
Ok(AsyncMmapFileMut::from(AsyncDiskMmapFileMut::open_cow_with_options(path, self).await?))
}
}
};
}
macro_rules! impl_async_options_tests {
($filename_prefix: literal, $runtime: meta, $path_str: ident) => {
#[cfg(test)]
mod tests {
use crate::$path_str::{AsyncOptions, AsyncMmapFileMut, AsyncMmapFileMutExt, AsyncMmapFileExt};
use scopeguard::defer;
#[$runtime]
async fn test_create_mmap_file_mut() {
let path = concat!($filename_prefix, "_options_create_mmap_file_mut.txt");
defer!(std::fs::remove_file(path).unwrap());
let mut file = AsyncOptions::new()
// truncate to 100
.max_size(100)
.create_mmap_file_mut(path).await.unwrap();
assert!(!file.is_empty());
file.write_all("some data...".as_bytes(), 0).unwrap();
file.flush().unwrap();
}
#[$runtime]
async fn test_open_mmap_file() {
let path = concat!($filename_prefix, "_options_open_mmap_file.txt");
defer!(std::fs::remove_file(path).unwrap());
let mut file = AsyncMmapFileMut::create(path).await.unwrap();
file.truncate(23).await.unwrap();
file.write_all("sanity text".as_bytes(), 0).unwrap();
file.write_all("some data...".as_bytes(), "sanity text".as_bytes().len()).unwrap();
file.flush().unwrap();
drop(file);
// mmap the file
let file = AsyncOptions::new()
// mmap content after the sanity text
.offset("sanity text".as_bytes().len() as u64)
.open_mmap_file(path).await.unwrap();
let mut buf = vec![0; "some data...".len()];
file.read_exact(buf.as_mut_slice(), 0).unwrap();
assert_eq!(buf.as_slice(), "some data...".as_bytes());
}
#[$runtime]
async fn test_open_mmap_file_exec() {
let path = concat!($filename_prefix, "_options_open_exec_mmap_file.txt");
defer!(std::fs::remove_file(path).unwrap());
let mut file = AsyncMmapFileMut::create(path).await.unwrap();
file.truncate(23).await.unwrap();
file.write_all("sanity text".as_bytes(), 0).unwrap();
file.write_all("some data...".as_bytes(), "sanity text".as_bytes().len()).unwrap();
file.flush().unwrap();
drop(file);
// mmap the file
let file = AsyncOptions::new()
// mmap content after the sanity text
.offset("sanity text".as_bytes().len() as u64)
.open_exec_mmap_file(path).await.unwrap();
let mut buf = vec![0; "some data...".len()];
file.read_exact(buf.as_mut_slice(), 0).unwrap();
assert_eq!(buf.as_slice(), "some data...".as_bytes());
}
#[$runtime]
async fn test_open_mmap_file_mut() {
let path = concat!($filename_prefix, "_options_open_mmap_file_mut.txt");
defer!(std::fs::remove_file(path).unwrap());
let mut file = AsyncMmapFileMut::create(path).await.unwrap();
file.truncate(23).await.unwrap();
file.write_all("sanity text".as_bytes(), 0).unwrap();
file.write_all("some data...".as_bytes(), "sanity text".as_bytes().len()).unwrap();
file.flush().unwrap();
drop(file);
let mut file = AsyncOptions::new()
// allow read
.read(true)
// allow write
.write(true)
// allow append
.append(true)
// truncate to 100
.max_size(100)
// mmap content after the sanity text
.offset("sanity text".as_bytes().len() as u64)
.open_mmap_file_mut(path).await.unwrap();
let mut buf = vec![0; "some data...".len()];
file.read_exact(buf.as_mut_slice(), 0).unwrap();
assert_eq!(buf.as_slice(), "some data...".as_bytes());
// modify the file data
file.truncate(("some modified data...".len() + "sanity text".len()) as u64).await.unwrap();
file.write_all("some modified data...".as_bytes(), 0).unwrap();
file.flush().unwrap();
drop(file);
// reopen to check content
let mut buf = vec![0; "some modified data...".len()];
let file = AsyncMmapFileMut::open(path).await.unwrap();
// skip the sanity text
file.read_exact(buf.as_mut_slice(), "sanity text".as_bytes().len()).unwrap();
assert_eq!(buf.as_slice(), "some modified data...".as_bytes());
}
#[$runtime]
async fn open_exist_mmap_file_mut() {
let path = concat!($filename_prefix, "_options_open_exist_mmap_file_mut.txt");
defer!(std::fs::remove_file(path).unwrap());
let mut file = AsyncMmapFileMut::create(path).await.unwrap();
file.truncate(23).await.unwrap();
file.write_all("sanity text".as_bytes(), 0).unwrap();
file.write_all("some data...".as_bytes(), "sanity text".as_bytes().len()).unwrap();
file.flush().unwrap();
drop(file);
// mmap the file
let mut file = AsyncOptions::new()
// truncate to 100
.max_size(100)
// mmap content after the sanity text
.offset("sanity text".as_bytes().len() as u64)
.open_exist_mmap_file_mut(path).await.unwrap();
let mut buf = vec![0; "some data...".len()];
file.read_exact(buf.as_mut_slice(), 0).unwrap();
assert_eq!(buf.as_slice(), "some data...".as_bytes());
// modify the file data
file.truncate(("some modified data...".len() + "sanity text".len()) as u64).await.unwrap();
file.write_all("some modified data...".as_bytes(), 0).unwrap();
file.flush().unwrap();
// reopen to check content, cow will not change the content.
let file = AsyncMmapFileMut::open(path).await.unwrap();
let mut buf = vec![0; "some modified data...".len()];
// skip the sanity text
file.read_exact(buf.as_mut_slice(), "sanity text".as_bytes().len()).unwrap();
assert_eq!(buf.as_slice(), "some modified data...".as_bytes());
}
#[$runtime]
async fn open_cow_mmap_file_mut() {
let path = concat!($filename_prefix, "_options_open_cow_mmap_file_mut.txt");
defer!(std::fs::remove_file(path).unwrap());
let mut file = AsyncMmapFileMut::create(path).await.unwrap();
file.truncate(23).await.unwrap();
file.write_all("sanity text".as_bytes(), 0).unwrap();
file.write_all("some data...".as_bytes(), "sanity text".as_bytes().len()).unwrap();
file.flush().unwrap();
drop(file);
// mmap the file
let mut file = AsyncOptions::new()
// mmap content after the sanity text
.offset("sanity text".as_bytes().len() as u64)
.open_cow_mmap_file_mut(path).await.unwrap();
assert!(file.is_cow());
let mut buf = vec![0; "some data...".len()];
file.read_exact(buf.as_mut_slice(), 0).unwrap();
assert_eq!(buf.as_slice(), "some data...".as_bytes());
// modify the file data
file.write_all("some data!!!".as_bytes(), 0).unwrap();
file.flush().unwrap();
// cow, change will only be seen in current caller
assert_eq!(file.as_slice(), "some data!!!".as_bytes());
drop(file);
// reopen to check content, cow will not change the content.
let file = AsyncMmapFileMut::open(path).await.unwrap();
let mut buf = vec![0; "some data...".len()];
// skip the sanity text
file.read_exact(buf.as_mut_slice(), "sanity text".as_bytes().len()).unwrap();
assert_eq!(buf.as_slice(), "some data...".as_bytes());
}
}
};
}
}
cfg_async_std!(
pub mod async_std_impl;
);
cfg_smol!(
pub mod smol_impl;
);
cfg_tokio!(
pub mod tokio_impl;
);