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}