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> {
29 buf: RawPlace<T>,
30 mmap: Option<MmapMut>,
31 pub(crate) file: File,
32 initialized_size: u64,
35}
36
37impl<T> FileMapped<T> {
38 pub fn new(file: File) -> io::Result<Self> {
42 const MIN_PAGE_SIZE: u64 = 4096;
43
44 let initialized_size = file.metadata()?.len();
45 if initialized_size < MIN_PAGE_SIZE {
46 file.set_len(MIN_PAGE_SIZE)?;
47 }
48
49 Ok(Self { file, buf: RawPlace::dangling(), mmap: None, initialized_size })
50 }
51
52 pub fn from_path<P: AsRef<Path>>(path: P) -> io::Result<Self> {
54 File::options()
55 .create(true)
56 .truncate(false)
57 .read(true)
58 .write(true)
59 .open(path)
60 .and_then(Self::new)
61 }
62
63 fn map_yet(&mut self, cap: u64) -> io::Result<MmapMut> {
64 unsafe { MmapOptions::new().len(cap as usize).map_mut(&self.file) }
65 }
66
67 unsafe fn assume_mapped(&mut self) -> &mut [u8] {
68 unsafe { self.mmap.as_mut().unwrap_unchecked() }
69 }
70}
71
72impl<T> RawMem for FileMapped<T> {
73 type Item = T;
74
75 fn allocated(&self) -> &[Self::Item] {
76 unsafe { self.buf.as_slice() }
77 }
78
79 fn allocated_mut(&mut self) -> &mut [Self::Item] {
80 unsafe { self.buf.as_slice_mut() }
81 }
82
83 unsafe fn grow(
84 &mut self,
85 addition: usize,
86 fill: impl FnOnce(usize, (&mut [T], &mut [MaybeUninit<T>])),
87 ) -> Result<&mut [T]> {
88 unsafe {
89 let cap = self.buf.cap().checked_add(addition).ok_or(CapacityOverflow)?;
90 let layout = Layout::array::<T>(cap).map_err(|_| CapacityOverflow)?;
92 let new_size = layout.size() as u64;
93
94 let _ = self.mmap.take();
96
97 let old_size = self.file.metadata()?.len();
98
99 if old_size < new_size {
100 self.file.set_len(new_size)?;
101 }
102 let inited = (self.initialized_size / mem::size_of::<T>() as u64)
103 .saturating_sub(self.buf.cap() as u64)
104 .min(addition as u64) as usize;
105
106 let ptr = {
107 let mmap = self.map_yet(new_size)?;
108 self.mmap.replace(mmap);
109 NonNull::from(self.assume_mapped()) };
112
113 let grown = self.buf.handle_fill((ptr.cast(), cap), inited, fill);
114 self.initialized_size = self.initialized_size.max(new_size);
115 Ok(grown)
116 }
117 }
118
119 fn shrink(&mut self, cap: usize) -> Result<()> {
120 let cap = self.buf.cap().checked_sub(cap).expect("Tried to shrink to a larger capacity");
121 self.buf.shrink_to(cap);
122
123 let _ = self.mmap.take();
124
125 let ptr = unsafe {
126 let new_size = mem::size_of::<T>().unchecked_mul(cap) as u64;
129 self.file.set_len(new_size)?;
130 self.initialized_size = new_size;
131
132 let mmap = self.map_yet(new_size)?;
133 self.mmap.replace(mmap);
134
135 self.assume_mapped().into()
136 };
137
138 self.buf.set_ptr(ptr);
139
140 Ok(())
141 }
142}
143
144impl<T> Drop for FileMapped<T> {
145 fn drop(&mut self) {
146 unsafe {
147 ptr::drop_in_place(self.buf.as_slice_mut());
148 }
149
150 let _ = self.file.sync_all();
151 }
152}
153
154impl<T> fmt::Debug for FileMapped<T> {
155 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
156 utils::debug_mem(f, &self.buf, "FileMapped")?
157 .field("mmap", &self.mmap)
158 .field("file", &self.file)
159 .finish()
160 }
161}