platform_mem/
file_mapped.rs1use {
2 crate::{Error::CapacityOverflow, RawMem, Result, raw_place::RawPlace, utils},
3 memmap2::{MmapMut, MmapOptions},
4 std::{
5 alloc::Layout,
6 fmt::{self, Formatter},
7 fs::File,
8 io,
9 mem::{self, MaybeUninit},
10 path::Path,
11 ptr::{self, NonNull},
12 },
13};
14
15pub struct FileMapped<T> {
24 buf: RawPlace<T>,
25 mmap: Option<MmapMut>,
26 pub(crate) file: File,
27}
28
29impl<T> FileMapped<T> {
30 pub fn new(file: File) -> io::Result<Self> {
34 const MIN_PAGE_SIZE: u64 = 4096;
35
36 if file.metadata()?.len() < MIN_PAGE_SIZE {
37 file.set_len(MIN_PAGE_SIZE)?;
38 }
39
40 Ok(Self { file, buf: RawPlace::dangling(), mmap: None })
41 }
42
43 pub fn from_path<P: AsRef<Path>>(path: P) -> io::Result<Self> {
45 File::options()
46 .create(true)
47 .truncate(false)
48 .read(true)
49 .write(true)
50 .open(path)
51 .and_then(Self::new)
52 }
53
54 fn map_yet(&mut self, cap: u64) -> io::Result<MmapMut> {
55 unsafe { MmapOptions::new().len(cap as usize).map_mut(&self.file) }
56 }
57
58 unsafe fn assume_mapped(&mut self) -> &mut [u8] {
59 unsafe { self.mmap.as_mut().unwrap_unchecked() }
60 }
61}
62
63impl<T> RawMem for FileMapped<T> {
64 type Item = T;
65
66 fn allocated(&self) -> &[Self::Item] {
67 unsafe { self.buf.as_slice() }
68 }
69
70 fn allocated_mut(&mut self) -> &mut [Self::Item] {
71 unsafe { self.buf.as_slice_mut() }
72 }
73
74 unsafe fn grow(
75 &mut self,
76 addition: usize,
77 fill: impl FnOnce(usize, (&mut [T], &mut [MaybeUninit<T>])),
78 ) -> Result<&mut [T]> {
79 unsafe {
80 let cap = self.buf.cap().checked_add(addition).ok_or(CapacityOverflow)?;
81 let layout = Layout::array::<T>(cap).map_err(|_| CapacityOverflow)?;
83 let new_size = layout.size() as u64;
84
85 let _ = self.mmap.take();
87
88 let old_size = self.file.metadata()?.len();
89
90 #[rustfmt::skip]
91 let inited = if old_size < new_size {
92 self.file.set_len(new_size)?;
93 (old_size as usize / mem::size_of::<T>()) .unchecked_sub(self.buf.cap())
95 } else {
96 addition };
98
99 let ptr = {
100 let mmap = self.map_yet(new_size)?;
101 self.mmap.replace(mmap);
102 NonNull::from(self.assume_mapped()) };
105
106 Ok(self.buf.handle_fill((ptr.cast(), cap), inited, fill))
107 }
108 }
109
110 fn shrink(&mut self, cap: usize) -> Result<()> {
111 let cap = self.buf.cap().checked_sub(cap).expect("Tried to shrink to a larger capacity");
112 self.buf.shrink_to(cap);
113
114 let _ = self.mmap.take();
115
116 let ptr = unsafe {
117 let new_size = mem::size_of::<T>().unchecked_mul(cap) as u64;
120 self.file.set_len(new_size)?;
121
122 let mmap = self.map_yet(new_size)?;
123 self.mmap.replace(mmap);
124
125 self.assume_mapped().into()
126 };
127
128 self.buf.set_ptr(ptr);
129
130 Ok(())
131 }
132}
133
134impl<T> Drop for FileMapped<T> {
135 fn drop(&mut self) {
136 unsafe {
137 ptr::drop_in_place(self.buf.as_slice_mut());
138 }
139
140 let _ = self.file.sync_all();
141 }
142}
143
144impl<T> fmt::Debug for FileMapped<T> {
145 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
146 utils::debug_mem(f, &self.buf, "FileMapped")?
147 .field("mmap", &self.mmap)
148 .field("file", &self.file)
149 .finish()
150 }
151}