1use std::fs::File;
33use std::fs::OpenOptions;
34use std::io;
35use std::io::Seek;
36use std::io::SeekFrom;
37use std::marker::PhantomData;
38use std::ops::Deref;
39use std::ops::DerefMut;
40use std::path::Path;
41
42use fs2::FileExt;
43
44use memmap::Mmap;
45use memmap::MmapMut;
46
47pub struct Mapping<'a> {
49 mmap: Option<Mmap>,
50 _lt: PhantomData<&'a ()>,
51}
52
53
54pub struct MutMapping<'a> {
56 mmap: Option<MmapMut>,
57 _lt: PhantomData<&'a mut ()>,
58}
59
60impl<'a> MutMapping<'a> {
61 pub fn flush(&self) -> io::Result<()> {
62 self.mmap
63 .as_ref()
64 .map(|mm| mm.flush())
65 .or(Some(Ok(())))
66 .unwrap()
67 }
68
69 pub fn flush_range(&self, offset: usize, len: usize) -> io::Result<()> {
70 self.mmap
71 .as_ref()
72 .map(|mm| mm.flush_range(offset, len))
73 .or(Some(Ok(())))
74 .unwrap()
75 }
76}
77
78impl<'a> Drop for Mapping<'a> {
81 fn drop(&mut self) {}
82}
83
84impl<'a> Drop for MutMapping<'a> {
85 fn drop(&mut self) {}
86}
87
88impl<'a> Deref for Mapping<'a> {
89 type Target = [u8];
90
91 #[inline]
92 fn deref(&self) -> &Self::Target {
93 match self.mmap.as_ref() {
94 Some(mm) => mm,
95 None => &[],
96 }
97 }
98}
99
100impl<'a> AsRef<[u8]> for Mapping<'a> {
101 #[inline]
102 fn as_ref(&self) -> &[u8] {
103 self.deref()
104 }
105}
106
107impl<'a> Deref for MutMapping<'a> {
108 type Target = [u8];
109
110 #[inline]
111 fn deref(&self) -> &Self::Target {
112 match self.mmap.as_ref() {
113 Some(mm) => mm,
114 None => &[],
115 }
116 }
117}
118
119impl<'a> DerefMut for MutMapping<'a> {
120 #[inline]
121 fn deref_mut(&mut self) -> &mut [u8] {
122 match self.mmap.as_mut() {
123 Some(mm) => mm,
124 None => &mut [],
125 }
126 }
127}
128
129impl<'a> AsRef<[u8]> for MutMapping<'a> {
130 #[inline]
131 fn as_ref(&self) -> &[u8] {
132 self.deref()
133 }
134}
135
136impl<'a> AsMut<[u8]> for MutMapping<'a> {
137 #[inline]
138 fn as_mut(&mut self) -> &mut [u8] {
139 self.deref_mut()
140 }
141}
142
143pub struct MappedFile {
148 file: File,
149 size: u64,
150}
151
152impl Drop for MappedFile {
153 fn drop(&mut self) {
154 self.file.unlock().unwrap();
155 }
156}
157
158impl MappedFile {
159 #[inline]
160 pub fn open<P: AsRef<Path>>(path: P) -> io::Result<Self> {
161 let file = OpenOptions::new().read(true).write(true).open(path)?;
162 Self::new(file)
163 }
164
165 #[inline]
166 pub fn create<P: AsRef<Path>>(path: P) -> io::Result<Self> {
167 let file = OpenOptions::new()
168 .create(true)
169 .read(true)
170 .write(true)
171 .open(path)?;
172 Self::new(file)
173 }
174
175 #[inline]
176 pub fn new(mut file: File) -> io::Result<Self> {
177 file.try_lock_exclusive()?;
179 let size = file.seek(SeekFrom::End(0))?;
180
181 Ok(Self {
182 file: file,
183 size: size,
184 })
185 }
186
187 #[inline]
189 pub fn map(&self, offset: u64, size: usize) -> io::Result<Mapping> {
190 let mmap = if size == 0 {
191 None
192 } else {
193 Some(unsafe {
194 memmap::MmapOptions::new()
195 .offset(offset)
196 .len(size)
197 .map(&self.file)?
198 })
199 };
200
201 Ok(Mapping {
202 mmap: mmap,
203 _lt: PhantomData,
204 })
205 }
206
207 #[inline]
209 pub fn map_mut<'a>(&'a mut self, offset: u64, size: usize) -> io::Result<MutMapping<'a>> {
210 let mmap = if size == 0 {
211 None
212 } else {
213 Some(unsafe {
214 memmap::MmapOptions::new()
215 .offset(offset)
216 .len(size)
217 .map_mut(&self.file)?
218 })
219 };
220
221 Ok(MutMapping {
222 mmap: mmap,
223 _lt: PhantomData,
224 })
225 }
226
227 #[inline]
231 pub fn resize(&mut self, size: u64) -> io::Result<()> {
232 self.file.set_len(size)?;
233 self.size = size;
234 Ok(())
235 }
236
237 #[inline]
239 pub fn size(&self) -> u64 {
240 self.size
241 }
242
243 #[inline]
245 pub fn sync_data(&mut self) -> io::Result<()> {
246 self.file.sync_data()
247 }
248
249 #[inline]
251 pub fn sync_all(&mut self) -> io::Result<()> {
252 self.file.sync_all()
253 }
254
255 #[inline]
258 pub fn into_mut_mapping(
259 self,
260 offset: u64,
261 size: usize,
262 ) -> Result<IntoMutMapping, (io::Error, Self)> {
263 let mmap = if size == 0 {
264 None
265 } else {
266 let mmap = unsafe {
267 memmap::MmapOptions::new()
268 .offset(offset)
269 .len(size)
270 .map_mut(&self.file)
271 };
272
273 Some(match mmap {
274 Ok(mm) => mm,
275 Err(e) => return Err((e, self)),
276 })
277 };
278
279 Ok(IntoMutMapping {
280 mmap: mmap,
281 file: Some(self),
282 })
283 }
284}
285
286
287pub struct IntoMutMapping {
289 mmap: Option<MmapMut>,
290 file: Option<MappedFile>,
291}
292
293
294impl IntoMutMapping {
295 #[inline]
298 pub fn unmap(mut self) -> MappedFile {
299 self.file.take().unwrap()
300 }
301
302 #[inline]
304 pub fn flush(&self) -> io::Result<()> {
305 self.mmap
306 .as_ref()
307 .map(|mm| mm.flush())
308 .or(Some(Ok(())))
309 .unwrap()
310 }
311
312 #[inline]
314 pub fn flush_range(&self, offset: usize, len: usize) -> io::Result<()> {
315 self.mmap
316 .as_ref()
317 .map(|mm| mm.flush_range(offset, len))
318 .or(Some(Ok(())))
319 .unwrap()
320 }
321
322 pub fn size(&self) -> u64 {
324 self.file.as_ref().unwrap().size()
325 }
326}
327
328impl<'a> Deref for IntoMutMapping {
329 type Target = [u8];
330
331 #[inline]
332 fn deref(&self) -> &Self::Target {
333 match self.mmap.as_ref() {
334 Some(mm) => mm,
335 None => &[],
336 }
337 }
338}
339
340impl<'a> DerefMut for IntoMutMapping {
341 #[inline]
342 fn deref_mut(&mut self) -> &mut [u8] {
343 match self.mmap.as_mut() {
344 Some(mm) => mm,
345 None => &mut [],
346 }
347 }
348}
349
350impl<'a> AsRef<[u8]> for IntoMutMapping {
351 #[inline]
352 fn as_ref(&self) -> &[u8] {
353 self.deref()
354 }
355}
356
357impl<'a> AsMut<[u8]> for IntoMutMapping {
358 #[inline]
359 fn as_mut(&mut self) -> &mut [u8] {
360 self.deref_mut()
361 }
362}
363
364
365#[cfg(test)]
366mod tests {
367 use super::MappedFile;
369 use std::fs::remove_file;
370 use std::path::PathBuf;
371
372 fn temp_file_name() -> PathBuf {
373 use rand::Rng;
374
375 let mut p = std::env::temp_dir();
376 p.push(
377 String::from("cargo-test.mmap-safe.") + &rand::thread_rng()
378 .sample_iter(&rand::distributions::Alphanumeric)
379 .take(12)
380 .collect::<String>(),
381 );
382 p
383 }
384
385 #[test]
386 fn only_one_instance() {
387 let file = temp_file_name();
388 let mut mf = MappedFile::create(&file).unwrap();
389 mf.resize(10).unwrap();
390
391 assert!(MappedFile::open(&file).is_err());
392 assert!(MappedFile::create(&file).is_err());
393
394 remove_file(file).unwrap();
395 }
396
397 #[test]
398 fn write_works() {
399 let file = temp_file_name();
400 let mut mf = MappedFile::create(&file).unwrap();
401 mf.resize(10).unwrap();
402
403 {
404 let mut mapping = mf.map_mut(0, 10).unwrap();
405 mapping[0] = 0x42;
406 }
407
408 let mapping = mf.map(0, 10).unwrap();
409 assert_eq!(mapping[0], 0x42);
410
411 remove_file(file).unwrap();
412 }
413
414 #[test]
415 fn multiple_immutable_mappings() {
416 let file = temp_file_name();
417 let mut mf = MappedFile::create(&file).unwrap();
418 mf.resize(10).unwrap();
419
420 {
421 let mut mm = mf.map_mut(0, 10).unwrap();
422 mm[0] = 0x42;
423 }
424
425 let mm1 = mf.map(0, 10).unwrap();
426 let mm2 = mf.map(0, 10).unwrap();
427 assert_eq!(mm1[0], 0x42);
428 assert_eq!(mm2[0], 0x42);
429
430 remove_file(file).unwrap();
431 }
432
433 #[test]
434 fn empty_files() {
435 let file = temp_file_name();
436 let mut mf = MappedFile::create(&file).unwrap();
437
438 {
439 let mm = mf.map_mut(0, 0).unwrap();
440 assert_eq!(mm.len(), 0);
441 }
442
443 {
444 let mm = mf.map(0, 0).unwrap();
445 assert_eq!(mm.len(), 0);
446 }
447
448 mf.into_mut_mapping(0, 0).map_err(|(e, _)| e).unwrap();
449
450 remove_file(file).unwrap();
451 }
452}