rarena_allocator/options/
open_options.rs

1use memmap2::MmapOptions;
2use std::{
3  fs::{File, OpenOptions},
4  io,
5  path::Path,
6};
7
8use super::{Allocator, Options};
9
10impl Options {
11  /// Set if lock the meta of the [`Allocator`](crate::Allocator) in the memory to prevent OS from swapping out the header of [`Allocator`](crate::Allocator).
12  /// When using memory map backed [`Allocator`](crate::Allocator), the meta of the [`Allocator`](crate::Allocator)
13  /// is in the header, meta is frequently accessed,
14  /// lock (`mlock` on the header) the meta can reduce the page fault,
15  /// but yes, this means that one [`Allocator`](crate::Allocator) will have one page are locked in memory,
16  /// and will not be swapped out. So, this is a trade-off between performance and memory usage.
17  ///
18  /// Default is `true`.
19  ///
20  /// This configuration has no effect on windows and vec backed [`Allocator`](crate::Allocator).
21  ///
22  /// ## Example
23  ///
24  /// ```rust
25  /// use rarena_allocator::Options;
26  ///
27  /// let opts = Options::new().with_lock_meta(false);
28  /// ```
29  #[inline]
30  pub const fn with_lock_meta(mut self, lock_meta: bool) -> Self {
31    self.lock_meta = lock_meta;
32    self
33  }
34
35  /// Sets the option for read access.
36  ///
37  /// This option, when true, will indicate that the file should be
38  /// `read`-able if opened.
39  ///
40  /// ## Examples
41  ///
42  /// ```rust
43  /// use rarena_allocator::Options;
44  ///
45  /// let opts = Options::new().with_read(true);
46  /// ```
47  #[inline]
48  #[cfg(all(feature = "memmap", not(target_family = "wasm")))]
49  #[cfg_attr(docsrs, doc(cfg(all(feature = "memmap", not(target_family = "wasm")))))]
50  pub const fn with_read(mut self, read: bool) -> Self {
51    self.read = read;
52    self
53  }
54
55  /// Sets the option for write access.
56  ///
57  /// This option, when true, will indicate that the file should be
58  /// `write`-able if opened.
59  ///
60  /// If the file already exists, any write calls on it will overwrite its
61  /// contents, without truncating it.
62  ///
63  /// ## Examples
64  ///
65  /// ```rust
66  /// use rarena_allocator::Options;
67  ///
68  /// let opts = Options::new().with_write(true);
69  /// ```
70  #[inline]
71  #[cfg(all(feature = "memmap", not(target_family = "wasm")))]
72  #[cfg_attr(docsrs, doc(cfg(all(feature = "memmap", not(target_family = "wasm")))))]
73  pub const fn with_write(mut self, write: bool) -> Self {
74    self.write = write;
75    self
76  }
77
78  /// Sets the option for the append mode.
79  ///
80  /// This option, when true, means that writes will append to a file instead
81  /// of overwriting previous contents.
82  /// Note that setting `.write(true).append(true)` has the same effect as
83  /// setting only `.append(true)`.
84  ///
85  /// For most filesystems, the operating system guarantees that all writes are
86  /// atomic: no writes get mangled because another process writes at the same
87  /// time.
88  ///
89  /// One maybe obvious note when using append-mode: make sure that all data
90  /// that belongs together is written to the file in one operation. This
91  /// can be done by concatenating strings before passing them to [`write()`],
92  /// or using a buffered writer (with a buffer of adequate size),
93  /// and calling [`flush()`] when the message is complete.
94  ///
95  /// If a file is opened with both read and append access, beware that after
96  /// opening, and after every write, the position for reading may be set at the
97  /// end of the file. So, before writing, save the current position (using
98  /// <code>[seek]\([SeekFrom](std::io::SeekFrom)::[Current]\(opts))</code>), and restore it before the next read.
99  ///
100  /// ## Note
101  ///
102  /// This function doesn't create the file if it doesn't exist. Use the
103  /// [`Options::with_create`] method to do so.
104  ///
105  /// [`write()`]: std::io::Write::write "io::Write::write"
106  /// [`flush()`]: std::io::Write::flush "io::Write::flush"
107  /// [seek]: std::io::Seek::seek "io::Seek::seek"
108  /// [Current]: std::io::SeekFrom::Current "io::SeekFrom::Current"
109  ///
110  /// ## Examples
111  ///
112  /// ```rust
113  /// use rarena_allocator::Options;
114  ///
115  /// let opts = Options::new().with_append(true);
116  /// ```
117  #[inline]
118  #[cfg(all(feature = "memmap", not(target_family = "wasm")))]
119  #[cfg_attr(docsrs, doc(cfg(all(feature = "memmap", not(target_family = "wasm")))))]
120  pub const fn with_append(mut self, append: bool) -> Self {
121    self.write = true;
122    self.append = append;
123    self
124  }
125
126  /// Sets the option for truncating a previous file.
127  ///
128  /// If a file is successfully opened with this option set it will truncate
129  /// the file to opts length if it already exists.
130  ///
131  /// The file must be opened with write access for truncate to work.
132  ///
133  /// ## Examples
134  ///
135  /// ```rust
136  /// use rarena_allocator::Options;
137  ///
138  /// let opts = Options::new().with_write(true).with_truncate(true);
139  /// ```
140  #[inline]
141  #[cfg(all(feature = "memmap", not(target_family = "wasm")))]
142  #[cfg_attr(docsrs, doc(cfg(all(feature = "memmap", not(target_family = "wasm")))))]
143  pub const fn with_truncate(mut self, truncate: bool) -> Self {
144    self.truncate = truncate;
145    self.write = true;
146    self
147  }
148
149  /// Sets the option to create a new file, or open it if it already exists.
150  /// If the file does not exist, it is created and set the lenght of the file to the given size.
151  ///
152  /// In order for the file to be created, [`Options::with_write`] or
153  /// [`Options::with_append`] access must be used.
154  ///
155  /// See also [`std::fs::write()`][std::fs::write] for a simple function to
156  /// create a file with some given data.
157  ///
158  /// ## Examples
159  ///
160  /// ```rust
161  /// use rarena_allocator::Options;
162  ///
163  /// let opts = Options::new().with_write(true).with_create(true);
164  /// ```
165  #[inline]
166  #[cfg(all(feature = "memmap", not(target_family = "wasm")))]
167  #[cfg_attr(docsrs, doc(cfg(all(feature = "memmap", not(target_family = "wasm")))))]
168  pub const fn with_create(mut self, val: bool) -> Self {
169    self.create = val;
170    self
171  }
172
173  /// Sets the option to create a new file and set the file length to the given value, failing if it already exists.
174  ///
175  /// No file is allowed to exist at the target location, also no (dangling) symlink. In this
176  /// way, if the call succeeds, the file returned is guaranteed to be new.
177  ///
178  /// This option is useful because it is atomic. Otherwise between checking
179  /// whether a file exists and creating a new one, the file may have been
180  /// created by another process (a TOCTOU race condition / attack).
181  ///
182  /// If `.with_create_new(true)` is set, [`.with_create()`](Options::with_create) and [`.with_truncate()`](Options::with_truncate) are
183  /// ignored.
184  ///
185  /// The file must be opened with write or append access in order to create
186  /// a new file.
187  ///
188  /// ## Examples
189  ///
190  /// ```rust
191  /// use rarena_allocator::Options;
192  ///
193  /// let file = Options::new()
194  ///   .with_write(true)
195  ///   .with_create_new(true);
196  /// ```
197  #[inline]
198  #[cfg(all(feature = "memmap", not(target_family = "wasm")))]
199  #[cfg_attr(docsrs, doc(cfg(all(feature = "memmap", not(target_family = "wasm")))))]
200  pub const fn with_create_new(mut self, val: bool) -> Self {
201    self.create_new = val;
202    self
203  }
204
205  /// Configures the memory map to start at byte `offset` from the beginning of the file.
206  ///
207  /// This option has no effect on anonymous memory maps or vec backed [`Allocator`](crate::Allocator).
208  ///
209  /// By default, the offset is 0.
210  ///
211  /// ## Example
212  ///
213  /// ```
214  /// use rarena_allocator::Options;
215  ///
216  /// let opts = Options::new().with_offset(30);
217  /// ```
218  #[inline]
219  #[cfg(all(feature = "memmap", not(target_family = "wasm")))]
220  #[cfg_attr(docsrs, doc(cfg(all(feature = "memmap", not(target_family = "wasm")))))]
221  pub const fn with_offset(mut self, offset: u64) -> Self {
222    self.offset = offset;
223    self
224  }
225
226  /// Configures the anonymous memory map to be suitable for a process or thread stack.
227  ///
228  /// This option corresponds to the `MAP_STACK` flag on Linux. It has no effect on Windows.
229  ///
230  /// This option has no effect on file-backed memory maps and vec backed [`Allocator`](crate::Allocator).
231  ///
232  /// ## Example
233  ///
234  /// ```
235  /// use rarena_allocator::Options;
236  ///
237  /// let stack = Options::new().with_stack(true);
238  /// ```
239  #[inline]
240  #[cfg(all(feature = "memmap", not(target_family = "wasm")))]
241  #[cfg_attr(docsrs, doc(cfg(all(feature = "memmap", not(target_family = "wasm")))))]
242  pub const fn with_stack(mut self, stack: bool) -> Self {
243    self.stack = stack;
244    self
245  }
246
247  /// Configures the anonymous memory map to be allocated using huge pages.
248  ///
249  /// This option corresponds to the `MAP_HUGETLB` flag on Linux. It has no effect on Windows.
250  ///
251  /// The size of the requested page can be specified in page bits. If not provided, the system
252  /// default is requested. The requested length should be a multiple of this, or the mapping
253  /// will fail.
254  ///
255  /// This option has no effect on file-backed memory maps and vec backed [`Allocator`](crate::Allocator).
256  ///
257  /// ## Example
258  ///
259  /// ```
260  /// use rarena_allocator::Options;
261  ///
262  /// let stack = Options::new().with_huge(Some(8));
263  /// ```
264  #[inline]
265  #[cfg(all(feature = "memmap", not(target_family = "wasm")))]
266  #[cfg_attr(docsrs, doc(cfg(all(feature = "memmap", not(target_family = "wasm")))))]
267  pub const fn with_huge(mut self, page_bits: Option<u8>) -> Self {
268    self.huge = page_bits;
269    self
270  }
271
272  /// Populate (prefault) page tables for a mapping.
273  ///
274  /// For a file mapping, this causes read-ahead on the file. This will help to reduce blocking on page faults later.
275  ///
276  /// This option corresponds to the `MAP_POPULATE` flag on Linux. It has no effect on Windows.
277  ///
278  /// This option has no effect on vec backed [`Allocator`](crate::Allocator).
279  ///
280  /// ## Example
281  ///
282  /// ```
283  /// use rarena_allocator::Options;
284  ///
285  /// let opts = Options::new().with_populate(true);
286  /// ```
287  #[inline]
288  #[cfg(all(feature = "memmap", not(target_family = "wasm")))]
289  #[cfg_attr(docsrs, doc(cfg(all(feature = "memmap", not(target_family = "wasm")))))]
290  pub const fn with_populate(mut self, populate: bool) -> Self {
291    self.populate = populate;
292    self
293  }
294}
295
296impl Options {
297  /// Get if lock the meta of the [`Allocator`](crate::Allocator) in the memory to prevent OS from swapping out the header of [`Allocator`](crate::Allocator).
298  /// When using memory map backed [`Allocator`](crate::Allocator), the meta of the [`Allocator`](crate::Allocator)
299  /// is in the header, meta is frequently accessed,
300  /// lock (`mlock` on the header) the meta can reduce the page fault,
301  /// but yes, this means that one [`Allocator`](crate::Allocator) will have one page are locked in memory,
302  /// and will not be swapped out. So, this is a trade-off between performance and memory usage.
303  ///
304  /// ## Example
305  ///
306  /// ```rust
307  /// use rarena_allocator::Options;
308  ///
309  /// let opts = Options::new().with_lock_meta(false);
310  /// assert_eq!(opts.lock_meta(), false);
311  /// ```
312  #[inline]
313  #[cfg(all(feature = "memmap", not(target_family = "wasm")))]
314  #[cfg_attr(docsrs, doc(cfg(all(feature = "memmap", not(target_family = "wasm")))))]
315  pub const fn lock_meta(&self) -> bool {
316    self.lock_meta
317  }
318
319  /// Returns `true` if the file should be opened with read access.
320  ///
321  /// ## Examples
322  ///
323  /// ```rust
324  /// use rarena_allocator::Options;
325  ///
326  /// let opts = Options::new().with_read(true);
327  /// assert_eq!(opts.read(), true);
328  /// ```
329  #[inline]
330  #[cfg(all(feature = "memmap", not(target_family = "wasm")))]
331  #[cfg_attr(docsrs, doc(cfg(all(feature = "memmap", not(target_family = "wasm")))))]
332  pub const fn read(&self) -> bool {
333    self.read
334  }
335
336  /// Returns `true` if the file should be opened with write access.
337  ///
338  /// ## Examples
339  ///
340  /// ```rust
341  /// use rarena_allocator::Options;
342  ///
343  /// let opts = Options::new().with_write(true);
344  /// assert_eq!(opts.write(), true);
345  /// ```
346  #[inline]
347  #[cfg(all(feature = "memmap", not(target_family = "wasm")))]
348  #[cfg_attr(docsrs, doc(cfg(all(feature = "memmap", not(target_family = "wasm")))))]
349  pub const fn write(&self) -> bool {
350    self.write
351  }
352
353  /// Returns `true` if the file should be opened with append access.
354  ///
355  /// ## Examples
356  ///
357  /// ```rust
358  /// use rarena_allocator::Options;
359  ///
360  /// let opts = Options::new().with_append(true);
361  /// assert_eq!(opts.append(), true);
362  /// ```
363  #[inline]
364  #[cfg(all(feature = "memmap", not(target_family = "wasm")))]
365  #[cfg_attr(docsrs, doc(cfg(all(feature = "memmap", not(target_family = "wasm")))))]
366  pub const fn append(&self) -> bool {
367    self.append
368  }
369
370  /// Returns `true` if the file should be opened with truncate access.
371  ///
372  /// ## Examples
373  ///
374  /// ```rust
375  /// use rarena_allocator::Options;
376  ///
377  /// let opts = Options::new().with_truncate(true);
378  /// assert_eq!(opts.truncate(), true);
379  /// ```
380  #[inline]
381  #[cfg(all(feature = "memmap", not(target_family = "wasm")))]
382  #[cfg_attr(docsrs, doc(cfg(all(feature = "memmap", not(target_family = "wasm")))))]
383  pub const fn truncate(&self) -> bool {
384    self.truncate
385  }
386
387  /// Returns `true` if the file should be created if it does not exist.
388  ///
389  /// ## Examples
390  ///
391  /// ```rust
392  /// use rarena_allocator::Options;
393  ///
394  /// let opts = Options::new().with_create(true);
395  /// assert_eq!(opts.create(), true);
396  /// ```
397  #[inline]
398  #[cfg(all(feature = "memmap", not(target_family = "wasm")))]
399  #[cfg_attr(docsrs, doc(cfg(all(feature = "memmap", not(target_family = "wasm")))))]
400  pub const fn create(&self) -> bool {
401    self.create
402  }
403
404  /// Returns `true` if the file should be created if it does not exist and fail if it does.
405  ///
406  /// ## Examples
407  ///
408  /// ```rust
409  /// use rarena_allocator::Options;
410  ///
411  /// let opts = Options::new().with_create_new(true);
412  /// assert_eq!(opts.create_new(), true);
413  /// ```
414  #[inline]
415  #[cfg(all(feature = "memmap", not(target_family = "wasm")))]
416  #[cfg_attr(docsrs, doc(cfg(all(feature = "memmap", not(target_family = "wasm")))))]
417  pub const fn create_new(&self) -> bool {
418    self.create_new
419  }
420
421  /// Returns the offset of the memory map.
422  ///
423  /// ## Examples
424  ///
425  /// ```rust
426  /// use rarena_allocator::Options;
427  ///
428  /// let opts = Options::new().with_offset(30);
429  /// assert_eq!(opts.offset(), 30);
430  /// ```
431  #[inline]
432  #[cfg(all(feature = "memmap", not(target_family = "wasm")))]
433  #[cfg_attr(docsrs, doc(cfg(all(feature = "memmap", not(target_family = "wasm")))))]
434  pub const fn offset(&self) -> u64 {
435    self.offset
436  }
437
438  /// Returns `true` if the memory map should be suitable for a process or thread stack.
439  ///
440  /// ## Examples
441  ///
442  /// ```rust
443  /// use rarena_allocator::Options;
444  ///
445  /// let opts = Options::new().with_stack(true);
446  /// assert_eq!(opts.stack(), true);
447  /// ```
448  #[inline]
449  #[cfg(all(feature = "memmap", not(target_family = "wasm")))]
450  #[cfg_attr(docsrs, doc(cfg(all(feature = "memmap", not(target_family = "wasm")))))]
451  pub const fn stack(&self) -> bool {
452    self.stack
453  }
454
455  /// Returns the page bits of the memory map.
456  ///
457  /// ## Examples
458  ///
459  /// ```rust
460  /// use rarena_allocator::Options;
461  ///
462  /// let opts = Options::new().with_huge(Some(8));
463  /// assert_eq!(opts.huge(), Some(8));
464  /// ```
465  #[inline]
466  #[cfg(all(feature = "memmap", not(target_family = "wasm")))]
467  #[cfg_attr(docsrs, doc(cfg(all(feature = "memmap", not(target_family = "wasm")))))]
468  pub const fn huge(&self) -> Option<u8> {
469    self.huge
470  }
471
472  /// Returns `true` if the memory map should populate (prefault) page tables for a mapping.
473  ///
474  /// ## Examples
475  ///
476  /// ```rust
477  /// use rarena_allocator::Options;
478  ///
479  /// let opts = Options::new().with_populate(true);
480  /// assert_eq!(opts.populate(), true);
481  /// ```
482  #[inline]
483  #[cfg(all(feature = "memmap", not(target_family = "wasm")))]
484  #[cfg_attr(docsrs, doc(cfg(all(feature = "memmap", not(target_family = "wasm")))))]
485  pub const fn populate(&self) -> bool {
486    self.populate
487  }
488}
489
490impl Options {
491  /// Creates a new allocator backed by an anonymous mmap.
492  ///
493  /// ## Example
494  ///
495  /// ```rust
496  /// use rarena_allocator::{sync::Arena, Options, Allocator};
497  ///
498  /// let arena = Options::new().with_capacity(100).map_anon::<Arena>().unwrap();
499  /// ```
500  #[cfg(all(feature = "memmap", not(target_family = "wasm")))]
501  #[cfg_attr(docsrs, doc(cfg(all(feature = "memmap", not(target_family = "wasm")))))]
502  pub fn map_anon<A: Allocator>(self) -> std::io::Result<A> {
503    constructor!(self.map_anon())
504  }
505
506  /// Opens a read only allocator backed by a mmap file.
507  ///
508  /// ## Safety
509  ///
510  /// All file-backed memory map constructors are marked `unsafe` because of the potential for
511  /// *Undefined Behavior* (UB) using the map if the underlying file is subsequently modified, in or
512  /// out of process. Applications must consider the risk and take appropriate precautions when
513  /// using file-backed maps. Solutions such as file permissions, locks or process-private (e.g.
514  /// unlinked) files exist but are platform specific and limited.
515  ///
516  /// ## Example
517  ///
518  /// ```rust
519  /// use rarena_allocator::{sync::Arena, Options, Allocator};
520  ///
521  /// # let path = tempfile::NamedTempFile::new().unwrap().into_temp_path();
522  /// # std::fs::remove_file(&path);
523  ///
524  /// # {
525  /// #   let arena = unsafe {  Options::new().with_capacity(100).with_create_new(true).with_read(true).with_write(true).map_mut::<Arena, _>(&path).unwrap() };
526  /// # }
527  ///
528  ///
529  ///
530  /// let arena = unsafe { Options::new().with_read(true).map::<Arena, _>(&path,).unwrap() };
531  ///
532  /// # std::fs::remove_file(path);
533  /// ```
534  #[inline]
535  #[cfg(all(feature = "memmap", not(target_family = "wasm")))]
536  #[cfg_attr(docsrs, doc(cfg(all(feature = "memmap", not(target_family = "wasm")))))]
537  pub unsafe fn map<A: Allocator, P: AsRef<std::path::Path>>(self, p: P) -> std::io::Result<A> {
538    constructor!(self.map(p))
539  }
540
541  /// Opens a read only allocator backed by a mmap file with the given path builder.
542  ///
543  /// ## Safety
544  ///
545  /// All file-backed memory map constructors are marked `unsafe` because of the potential for
546  /// *Undefined Behavior* (UB) using the map if the underlying file is subsequently modified, in or
547  /// out of process. Applications must consider the risk and take appropriate precautions when
548  /// using file-backed maps. Solutions such as file permissions, locks or process-private (e.g.
549  /// unlinked) files exist but are platform specific and limited.
550  ///
551  /// ## Example
552  ///
553  /// ```rust
554  /// use rarena_allocator::{sync::Arena, Allocator, Options};
555  ///
556  /// # let path = tempfile::NamedTempFile::new().unwrap().into_temp_path();
557  /// # std::fs::remove_file(&path);
558  ///
559  /// # {
560  /// #   let arena = unsafe { Options::new().with_capacity(100).with_read(true).with_write(true).with_create_new(true).map_mut::<Arena, _>(&path).unwrap() };
561  /// # }
562  ///
563  ///
564  ///
565  /// let arena = unsafe { Options::new().with_read(true).map_with_path_builder::<Arena, _, std::io::Error>(|| Ok(path.to_path_buf())).unwrap() };
566  ///
567  /// # std::fs::remove_file(path);
568  /// ```
569  #[cfg(all(feature = "memmap", not(target_family = "wasm")))]
570  #[cfg_attr(docsrs, doc(cfg(all(feature = "memmap", not(target_family = "wasm")))))]
571  pub unsafe fn map_with_path_builder<A: Allocator, PB, E>(
572    self,
573    path_builder: PB,
574  ) -> Result<A, either::Either<E, std::io::Error>>
575  where
576    PB: FnOnce() -> Result<std::path::PathBuf, E>,
577  {
578    constructor!(self.map_with_path_builder(path_builder))
579  }
580
581  /// Creates a new allocator backed by a copy-on-write memory map backed by a file.
582  ///
583  /// Data written to the allocator will not be visible by other processes, and will not be carried through to the underlying file.
584  ///
585  /// ## Safety
586  ///
587  /// All file-backed memory map constructors are marked `unsafe` because of the potential for
588  /// *Undefined Behavior* (UB) using the map if the underlying file is subsequently modified, in or
589  /// out of process. Applications must consider the risk and take appropriate precautions when
590  /// using file-backed maps. Solutions such as file permissions, locks or process-private (e.g.
591  /// unlinked) files exist but are platform specific and limited.
592  ///
593  /// ## Example
594  ///
595  /// ```rust
596  /// use rarena_allocator::{sync::Arena, Options, Allocator};
597  ///
598  /// # let path = tempfile::NamedTempFile::new().unwrap().into_temp_path();
599  /// # std::fs::remove_file(&path);
600  ///
601  /// let arena = unsafe { Options::new().with_capacity(100).with_read(true).with_write(true).with_create_new(true).map_copy::<Arena, _>(&path,).unwrap() };
602  ///
603  /// # std::fs::remove_file(path);
604  /// ```
605  #[cfg(all(feature = "memmap", not(target_family = "wasm")))]
606  #[cfg_attr(docsrs, doc(cfg(all(feature = "memmap", not(target_family = "wasm")))))]
607  #[inline]
608  pub unsafe fn map_copy<A: Allocator, P: AsRef<std::path::Path>>(
609    self,
610    path: P,
611  ) -> std::io::Result<A> {
612    constructor!(self.map_copy(path))
613  }
614
615  /// Creates a new allocator backed by a copy-on-write memory map backed by a file with the given path builder.
616  ///
617  /// Data written to the allocator will not be visible by other processes, and will not be carried through to the underlying file.
618  ///
619  /// ## Safety
620  ///
621  /// All file-backed memory map constructors are marked `unsafe` because of the potential for
622  /// *Undefined Behavior* (UB) using the map if the underlying file is subsequently modified, in or
623  /// out of process. Applications must consider the risk and take appropriate precautions when
624  /// using file-backed maps. Solutions such as file permissions, locks or process-private (e.g.
625  /// unlinked) files exist but are platform specific and limited.
626  ///
627  /// ## Example
628  ///
629  /// ```rust
630  /// use rarena_allocator::{sync::Arena, Options, Allocator};
631  ///
632  /// # let path = tempfile::NamedTempFile::new().unwrap().into_temp_path();
633  /// # std::fs::remove_file(&path);
634  ///
635  /// let arena = unsafe { Options::new().with_capacity(100).with_create_new(true).with_read(true).with_write(true).map_copy_with_path_builder::<Arena, _, std::io::Error>(|| Ok(path.to_path_buf()),).unwrap() };
636  ///
637  /// # std::fs::remove_file(path);
638  /// ```
639  #[cfg(all(feature = "memmap", not(target_family = "wasm")))]
640  #[cfg_attr(docsrs, doc(cfg(all(feature = "memmap", not(target_family = "wasm")))))]
641  #[inline]
642  pub unsafe fn map_copy_with_path_builder<A: Allocator, PB, E>(
643    self,
644    path_builder: PB,
645  ) -> Result<A, either::Either<E, std::io::Error>>
646  where
647    PB: FnOnce() -> Result<std::path::PathBuf, E>,
648  {
649    constructor!(self.map_copy_with_path_builder(path_builder))
650  }
651
652  /// Opens a read only allocator backed by a copy-on-write read-only memory map backed by a file.
653  ///
654  /// ## Safety
655  ///
656  /// All file-backed memory map constructors are marked `unsafe` because of the potential for
657  /// *Undefined Behavior* (UB) using the map if the underlying file is subsequently modified, in or
658  /// out of process. Applications must consider the risk and take appropriate precautions when
659  /// using file-backed maps. Solutions such as file permissions, locks or process-private (e.g.
660  /// unlinked) files exist but are platform specific and limited.
661  ///
662  /// ## Example
663  ///
664  /// ```rust
665  /// use rarena_allocator::{sync::Arena, Options, Allocator};
666  ///
667  /// # let path = tempfile::NamedTempFile::new().unwrap().into_temp_path();
668  /// # std::fs::remove_file(&path);
669  ///
670  /// # {
671  /// #   let arena = unsafe {  Options::new().with_capacity(100).with_create_new(true).with_read(true).with_write(true).map_mut::<Arena, _>(&path).unwrap() };
672  /// # }
673  ///
674  ///
675  ///
676  /// let arena = unsafe { Options::new().with_read(true).map_copy_read_only::<Arena, _>(&path,).unwrap() };
677  ///
678  /// # std::fs::remove_file(path);
679  /// ```
680  #[cfg(all(feature = "memmap", not(target_family = "wasm")))]
681  #[cfg_attr(docsrs, doc(cfg(all(feature = "memmap", not(target_family = "wasm")))))]
682  #[inline]
683  pub unsafe fn map_copy_read_only<A: Allocator, P: AsRef<std::path::Path>>(
684    self,
685    path: P,
686  ) -> std::io::Result<A> {
687    constructor!(self.map_copy_read_only(path))
688  }
689
690  /// Opens a read only allocator backed by a copy-on-write read-only memory map backed by a file with the given path builder.
691  ///
692  /// ## Safety
693  ///
694  /// All file-backed memory map constructors are marked `unsafe` because of the potential for
695  /// *Undefined Behavior* (UB) using the map if the underlying file is subsequently modified, in or
696  /// out of process. Applications must consider the risk and take appropriate precautions when
697  /// using file-backed maps. Solutions such as file permissions, locks or process-private (e.g.
698  /// unlinked) files exist but are platform specific and limited.
699  ///
700  /// ## Example
701  ///
702  /// ```rust
703  /// use rarena_allocator::{sync::Arena, Options, Allocator};
704  ///
705  /// # let path = tempfile::NamedTempFile::new().unwrap().into_temp_path();
706  /// # std::fs::remove_file(&path);
707  ///
708  /// # {
709  ///   #
710  ///   #
711  ///   # let arena = unsafe { Options::new().with_create_new(true).with_read(true).with_write(true).with_capacity(100).map_mut::<Arena, _>(&path).unwrap() };
712  /// # }
713  ///
714  ///
715  ///
716  /// let arena = unsafe {
717  ///   Options::new().with_read(true).map_copy_read_only_with_path_builder::<Arena, _, std::io::Error>(|| Ok(path.to_path_buf())).unwrap()
718  /// };
719  ///
720  /// # std::fs::remove_file(path);
721  /// ```
722  #[cfg(all(feature = "memmap", not(target_family = "wasm")))]
723  #[cfg_attr(docsrs, doc(cfg(all(feature = "memmap", not(target_family = "wasm")))))]
724  pub unsafe fn map_copy_read_only_with_path_builder<A: Allocator, PB, E>(
725    self,
726    path_builder: PB,
727  ) -> Result<A, either::Either<E, std::io::Error>>
728  where
729    PB: FnOnce() -> Result<std::path::PathBuf, E>,
730  {
731    constructor!(self.map_copy_read_only_with_path_builder(path_builder))
732  }
733
734  /// Creates a new allocator backed by a mmap with the given path.
735  ///
736  /// ## Safety
737  ///
738  /// All file-backed memory map constructors are marked `unsafe` because of the potential for
739  /// *Undefined Behavior* (UB) using the map if the underlying file is subsequently modified, in or
740  /// out of process. Applications must consider the risk and take appropriate precautions when
741  /// using file-backed maps. Solutions such as file permissions, locks or process-private (e.g.
742  /// unlinked) files exist but are platform specific and limited.
743  ///
744  /// ## Example
745  ///
746  /// ```rust
747  /// use rarena_allocator::{sync::Arena, Options, Allocator};
748  ///
749  /// # let path = tempfile::NamedTempFile::new().unwrap().into_temp_path();
750  /// # std::fs::remove_file(&path);
751  ///
752  /// let arena = unsafe {
753  ///   Options::new()
754  ///     .with_capacity(100)
755  ///     .with_create_new(true)
756  ///     .with_read(true)
757  ///     .with_write(true)
758  ///     .map_mut::<Arena, _>(&path).unwrap()
759  /// };
760  ///
761  /// # std::fs::remove_file(path);
762  /// ```
763  #[cfg(all(feature = "memmap", not(target_family = "wasm")))]
764  #[cfg_attr(docsrs, doc(cfg(all(feature = "memmap", not(target_family = "wasm")))))]
765  #[inline]
766  pub unsafe fn map_mut<A: Allocator, P: AsRef<std::path::Path>>(
767    self,
768    path: P,
769  ) -> std::io::Result<A> {
770    constructor!(self.map_mut(path))
771  }
772
773  /// Creates a new allocator backed by a mmap with the given path builder.
774  ///
775  /// ## Safety
776  ///
777  /// All file-backed memory map constructors are marked `unsafe` because of the potential for
778  /// *Undefined Behavior* (UB) using the map if the underlying file is subsequently modified, in or
779  /// out of process. Applications must consider the risk and take appropriate precautions when
780  /// using file-backed maps. Solutions such as file permissions, locks or process-private (e.g.
781  /// unlinked) files exist but are platform specific and limited.
782  ///
783  /// ## Example
784  ///
785  /// ```rust
786  /// use rarena_allocator::{sync::Arena, Options, Allocator};
787  ///
788  /// # let path = tempfile::NamedTempFile::new().unwrap().into_temp_path();
789  /// # std::fs::remove_file(&path);
790  ///
791  /// let arena = unsafe {
792  ///   Options::new()
793  ///     .with_create_new(true)
794  ///     .with_read(true)
795  ///     .with_write(true)
796  ///     .with_capacity(100)
797  ///     .map_mut_with_path_builder::<Arena, _, std::io::Error>(|| Ok(path.to_path_buf())).unwrap()
798  /// };
799  ///
800  /// # std::fs::remove_file(path);
801  /// ```
802  #[inline]
803  #[cfg(all(feature = "memmap", not(target_family = "wasm")))]
804  #[cfg_attr(docsrs, doc(cfg(all(feature = "memmap", not(target_family = "wasm")))))]
805  pub unsafe fn map_mut_with_path_builder<A: Allocator, PB, E>(
806    self,
807    path_builder: PB,
808  ) -> Result<A, either::Either<E, std::io::Error>>
809  where
810    PB: FnOnce() -> Result<std::path::PathBuf, E>,
811  {
812    constructor!(self.map_mut_with_path_builder(path_builder))
813  }
814}
815
816impl Options {
817  /// Returns if the file is newly created and the file
818  pub(crate) fn open<P: AsRef<Path>>(&self, path: P) -> io::Result<(bool, File)> {
819    if self.create_new {
820      return self.to_open_options().open(path).and_then(|f| {
821        if let Some(cap) = self.capacity {
822          f.set_len(cap as u64).map(|_| (true, f))
823        } else {
824          Ok((true, f))
825        }
826      });
827    }
828
829    if self.create {
830      return if path.as_ref().exists() {
831        self.to_open_options().open(path).map(|f| (false, f))
832      } else {
833        self.to_open_options().open(path).and_then(|f| {
834          if let Some(cap) = self.capacity {
835            f.set_len(cap as u64).map(|_| (true, f))
836          } else {
837            Ok((true, f))
838          }
839        })
840      };
841    }
842
843    self.to_open_options().open(path).map(|f| (false, f))
844  }
845
846  #[allow(clippy::wrong_self_convention)]
847  #[inline]
848  pub(crate) fn to_open_options(&self) -> OpenOptions {
849    let mut open_opts = OpenOptions::new();
850
851    if self.read {
852      open_opts.read(true);
853    }
854
855    if self.write {
856      open_opts.write(true);
857    }
858
859    if self.append {
860      open_opts.append(true);
861    }
862
863    if self.truncate {
864      open_opts.truncate(true);
865    }
866
867    if self.create {
868      open_opts.create(true);
869    }
870
871    if self.create_new {
872      open_opts.create_new(true);
873    }
874
875    open_opts
876  }
877
878  #[allow(clippy::wrong_self_convention)]
879  #[inline]
880  pub(crate) fn to_mmap_options(&self) -> MmapOptions {
881    let mut mmap_opts = MmapOptions::new();
882
883    if self.stack {
884      mmap_opts.stack();
885    }
886
887    if let Some(page_bits) = self.huge {
888      mmap_opts.huge(Some(page_bits));
889    }
890
891    if self.populate {
892      mmap_opts.populate();
893    }
894
895    if self.offset > 0 {
896      mmap_opts.offset(self.offset);
897    }
898
899    if let Some(cap) = self.capacity {
900      mmap_opts.len(cap as usize);
901    }
902
903    mmap_opts
904  }
905}