memmap/
lib.rs

1//! A cross-platform Rust API for memory mapped buffers.
2
3#![doc(html_root_url = "https://docs.rs/memmap/0.7.0")]
4
5#[cfg(windows)]
6extern crate winapi;
7#[cfg(windows)]
8mod windows;
9#[cfg(windows)]
10use windows::MmapInner;
11
12#[cfg(unix)]
13mod unix;
14#[cfg(unix)]
15use unix::MmapInner;
16
17use std::fmt;
18use std::fs::File;
19use std::io::{Error, ErrorKind, Result};
20use std::ops::{Deref, DerefMut};
21use std::slice;
22use std::usize;
23
24/// A memory map builder, providing advanced options and flags for specifying memory map behavior.
25///
26/// `MmapOptions` can be used to create an anonymous memory map using `MmapOptions::map_anon`, or a
27/// file-backed memory map using one of `MmapOptions::map`, `MmapOptions::map_mut`,
28/// `MmapOptions::map_exec`, or `MmapOptions::map_copy`.
29#[derive(Clone, Debug, Default)]
30pub struct MmapOptions {
31    offset: u64,
32    len: Option<usize>,
33    stack: bool,
34}
35
36impl MmapOptions {
37    /// Creates a new set of options for configuring and creating a memory map.
38    ///
39    /// # Example
40    ///
41    /// ```
42    /// use memmap::{MmapMut, MmapOptions};
43    /// # use std::io::Result;
44    ///
45    /// # fn main() -> Result<()> {
46    /// // Create a new memory map builder.
47    /// let mut mmap_options = MmapOptions::new();
48    ///
49    /// // Configure the memory map builder using option setters, then create
50    /// // a memory map using one of `mmap_options.map_anon`, `mmap_options.map`,
51    /// // `mmap_options.map_mut`, `mmap_options.map_exec`, or `mmap_options.map_copy`:
52    /// let mut mmap: MmapMut = mmap_options.len(36).map_anon()?;
53    ///
54    /// // Use the memory map:
55    /// mmap.copy_from_slice(b"...data to copy to the memory map...");
56    /// # let _ = mmap_options;
57    /// # Ok(())
58    /// # }
59    /// ```
60    pub fn new() -> MmapOptions {
61        MmapOptions::default()
62    }
63
64    /// Configures the memory map to start at byte `offset` from the beginning of the file.
65    ///
66    /// This option has no effect on anonymous memory maps.
67    ///
68    /// By default, the offset is 0.
69    ///
70    /// # Example
71    ///
72    /// ```
73    /// use memmap::MmapOptions;
74    /// use std::fs::File;
75    ///
76    /// # fn main() -> std::io::Result<()> {
77    /// let mmap = unsafe {
78    ///     MmapOptions::new()
79    ///                 .offset(10)
80    ///                 .map(&File::open("README.md")?)?
81    /// };
82    /// assert_eq!(&b"A Rust library for cross-platform memory mapped IO."[..],
83    ///            &mmap[..51]);
84    /// # Ok(())
85    /// # }
86    /// ```
87    pub fn offset(&mut self, offset: u64) -> &mut Self {
88        self.offset = offset;
89        self
90    }
91
92    /// Configures the created memory mapped buffer to be `len` bytes long.
93    ///
94    /// This option is mandatory for anonymous memory maps.
95    ///
96    /// For file-backed memory maps, the length will default to the file length.
97    ///
98    /// # Example
99    ///
100    /// ```
101    /// use memmap::MmapOptions;
102    /// use std::fs::File;
103    ///
104    /// # fn main() -> std::io::Result<()> {
105    /// let mmap = unsafe {
106    ///     MmapOptions::new()
107    ///                 .len(8)
108    ///                 .map(&File::open("README.md")?)?
109    /// };
110    /// assert_eq!(&b"# memmap"[..], &mmap[..]);
111    /// # Ok(())
112    /// # }
113    /// ```
114    pub fn len(&mut self, len: usize) -> &mut Self {
115        self.len = Some(len);
116        self
117    }
118
119    /// Returns the configured length, or the length of the provided file.
120    fn get_len(&self, file: &File) -> Result<usize> {
121        self.len.map(Ok).unwrap_or_else(|| {
122            let len = file.metadata()?.len() - self.offset;
123            if len > (usize::MAX as u64) {
124                return Err(Error::new(
125                    ErrorKind::InvalidData,
126                    "memory map length overflows usize",
127                ));
128            }
129            Ok(len as usize)
130        })
131    }
132
133    /// Configures the anonymous memory map to be suitable for a process or thread stack.
134    ///
135    /// This option corresponds to the `MAP_STACK` flag on Linux.
136    ///
137    /// This option has no effect on file-backed memory maps.
138    ///
139    /// # Example
140    ///
141    /// ```
142    /// use memmap::MmapOptions;
143    ///
144    /// # fn main() -> std::io::Result<()> {
145    /// let stack = MmapOptions::new().stack().len(4096).map_anon();
146    /// # Ok(())
147    /// # }
148    /// ```
149    pub fn stack(&mut self) -> &mut Self {
150        self.stack = true;
151        self
152    }
153
154    /// Creates a read-only memory map backed by a file.
155    ///
156    /// # Errors
157    ///
158    /// This method returns an error when the underlying system call fails, which can happen for a
159    /// variety of reasons, such as when the file is not open with read permissions.
160    ///
161    /// # Example
162    ///
163    /// ```
164    /// use memmap::MmapOptions;
165    /// use std::fs::File;
166    /// use std::io::Read;
167    ///
168    /// # fn main() -> std::io::Result<()> {
169    /// let mut file = File::open("README.md")?;
170    ///
171    /// let mut contents = Vec::new();
172    /// file.read_to_end(&mut contents)?;
173    ///
174    /// let mmap = unsafe {
175    ///     MmapOptions::new().map(&file)?
176    /// };
177    ///
178    /// assert_eq!(&contents[..], &mmap[..]);
179    /// # Ok(())
180    /// # }
181    /// ```
182    pub unsafe fn map(&self, file: &File) -> Result<Mmap> {
183        MmapInner::map(self.get_len(file)?, file, self.offset).map(|inner| Mmap { inner: inner })
184    }
185
186    /// Creates a readable and executable memory map backed by a file.
187    ///
188    /// # Errors
189    ///
190    /// This method returns an error when the underlying system call fails, which can happen for a
191    /// variety of reasons, such as when the file is not open with read permissions.
192    pub unsafe fn map_exec(&self, file: &File) -> Result<Mmap> {
193        MmapInner::map_exec(self.get_len(file)?, file, self.offset)
194            .map(|inner| Mmap { inner: inner })
195    }
196
197    /// Creates a writeable memory map backed by a file.
198    ///
199    /// # Errors
200    ///
201    /// This method returns an error when the underlying system call fails, which can happen for a
202    /// variety of reasons, such as when the file is not open with read and write permissions.
203    ///
204    /// # Example
205    ///
206    /// ```
207    /// # extern crate memmap;
208    /// # extern crate tempdir;
209    /// #
210    /// use std::fs::OpenOptions;
211    /// use std::path::PathBuf;
212    ///
213    /// use memmap::MmapOptions;
214    /// #
215    /// # fn main() -> std::io::Result<()> {
216    /// # let tempdir = tempdir::TempDir::new("mmap")?;
217    /// let path: PathBuf = /* path to file */
218    /// #   tempdir.path().join("map_mut");
219    /// let file = OpenOptions::new().read(true).write(true).create(true).open(&path)?;
220    /// file.set_len(13)?;
221    ///
222    /// let mut mmap = unsafe {
223    ///     MmapOptions::new().map_mut(&file)?
224    /// };
225    ///
226    /// mmap.copy_from_slice(b"Hello, world!");
227    /// # Ok(())
228    /// # }
229    /// ```
230    pub unsafe fn map_mut(&self, file: &File) -> Result<MmapMut> {
231        MmapInner::map_mut(self.get_len(file)?, file, self.offset)
232            .map(|inner| MmapMut { inner: inner })
233    }
234
235    /// Creates a copy-on-write memory map backed by a file.
236    ///
237    /// Data written to the memory map will not be visible by other processes,
238    /// and will not be carried through to the underlying file.
239    ///
240    /// # Errors
241    ///
242    /// This method returns an error when the underlying system call fails, which can happen for a
243    /// variety of reasons, such as when the file is not open with writable permissions.
244    ///
245    /// # Example
246    ///
247    /// ```
248    /// use memmap::MmapOptions;
249    /// use std::fs::File;
250    /// use std::io::Write;
251    ///
252    /// # fn main() -> std::io::Result<()> {
253    /// let file = File::open("README.md")?;
254    /// let mut mmap = unsafe { MmapOptions::new().map_copy(&file)? };
255    /// (&mut mmap[..]).write_all(b"Hello, world!")?;
256    /// # Ok(())
257    /// # }
258    /// ```
259    pub unsafe fn map_copy(&self, file: &File) -> Result<MmapMut> {
260        MmapInner::map_copy(self.get_len(file)?, file, self.offset)
261            .map(|inner| MmapMut { inner: inner })
262    }
263
264    /// Creates an anonymous memory map.
265    ///
266    /// Note: the memory map length must be configured to be greater than 0 before creating an
267    /// anonymous memory map using `MmapOptions::len()`.
268    ///
269    /// # Errors
270    ///
271    /// This method returns an error when the underlying system call fails.
272    pub fn map_anon(&self) -> Result<MmapMut> {
273        MmapInner::map_anon(self.len.unwrap_or(0), self.stack).map(|inner| MmapMut { inner: inner })
274    }
275}
276
277/// An immutable memory mapped buffer.
278///
279/// A `Mmap` may be backed by a file, or it can be anonymous map, backed by volatile memory.
280///
281/// Use `MmapOptions` to configure and create a file-backed memory map. To create an immutable
282/// anonymous memory map, first create a mutable anonymous memory map using `MmapOptions`, and then
283/// make it immutable with `MmapMut::make_read_only`.
284///
285/// # Example
286///
287/// ```
288/// use memmap::MmapOptions;
289/// use std::io::Write;
290/// use std::fs::File;
291///
292/// # fn main() -> std::io::Result<()> {
293/// let file = File::open("README.md")?;
294/// let mmap = unsafe { MmapOptions::new().map(&file)? };
295/// assert_eq!(b"# memmap", &mmap[0..8]);
296/// # Ok(())
297/// # }
298/// ```
299///
300/// See `MmapMut` for the mutable version.
301pub struct Mmap {
302    inner: MmapInner,
303}
304
305impl Mmap {
306    /// Creates a read-only memory map backed by a file.
307    ///
308    /// This is equivalent to calling `MmapOptions::new().map(file)`.
309    ///
310    /// # Errors
311    ///
312    /// This method returns an error when the underlying system call fails, which can happen for a
313    /// variety of reasons, such as when the file is not open with read permissions.
314    ///
315    /// # Example
316    ///
317    /// ```
318    /// use std::fs::File;
319    /// use std::io::Read;
320    ///
321    /// use memmap::Mmap;
322    ///
323    /// # fn main() -> std::io::Result<()> {
324    /// let mut file = File::open("README.md")?;
325    ///
326    /// let mut contents = Vec::new();
327    /// file.read_to_end(&mut contents)?;
328    ///
329    /// let mmap = unsafe { Mmap::map(&file)?  };
330    ///
331    /// assert_eq!(&contents[..], &mmap[..]);
332    /// # Ok(())
333    /// # }
334    /// ```
335    pub unsafe fn map(file: &File) -> Result<Mmap> {
336        MmapOptions::new().map(file)
337    }
338
339    /// Transition the memory map to be writable.
340    ///
341    /// If the memory map is file-backed, the file must have been opened with write permissions.
342    ///
343    /// # Errors
344    ///
345    /// This method returns an error when the underlying system call fails, which can happen for a
346    /// variety of reasons, such as when the file is not open with writable permissions.
347    ///
348    /// # Example
349    ///
350    /// ```
351    /// # extern crate memmap;
352    /// # extern crate tempdir;
353    /// #
354    /// use memmap::Mmap;
355    /// use std::ops::DerefMut;
356    /// use std::io::Write;
357    /// # use std::fs::OpenOptions;
358    ///
359    /// # fn main() -> std::io::Result<()> {
360    /// # let tempdir = tempdir::TempDir::new("mmap")?;
361    /// let file = /* file opened with write permissions */
362    /// #          OpenOptions::new()
363    /// #                      .read(true)
364    /// #                      .write(true)
365    /// #                      .create(true)
366    /// #                      .open(tempdir.path()
367    /// #                      .join("make_mut"))?;
368    /// # file.set_len(128)?;
369    /// let mmap = unsafe { Mmap::map(&file)? };
370    /// // ... use the read-only memory map ...
371    /// let mut mut_mmap = mmap.make_mut()?;
372    /// mut_mmap.deref_mut().write_all(b"hello, world!")?;
373    /// # Ok(())
374    /// # }
375    /// ```
376    pub fn make_mut(mut self) -> Result<MmapMut> {
377        self.inner.make_mut()?;
378        Ok(MmapMut { inner: self.inner })
379    }
380}
381
382impl Deref for Mmap {
383    type Target = [u8];
384
385    #[inline]
386    fn deref(&self) -> &[u8] {
387        unsafe { slice::from_raw_parts(self.inner.ptr(), self.inner.len()) }
388    }
389}
390
391impl AsRef<[u8]> for Mmap {
392    #[inline]
393    fn as_ref(&self) -> &[u8] {
394        self.deref()
395    }
396}
397
398impl fmt::Debug for Mmap {
399    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
400        fmt.debug_struct("Mmap")
401            .field("ptr", &self.as_ptr())
402            .field("len", &self.len())
403            .finish()
404    }
405}
406
407/// A mutable memory mapped buffer.
408///
409/// A file-backed `MmapMut` buffer may be used to read from or write to a file. An anonymous
410/// `MmapMut` buffer may be used any place that an in-memory byte buffer is needed. Use
411/// `MmapOptions` for creating memory maps.
412///
413/// See `Mmap` for the immutable version.
414pub struct MmapMut {
415    inner: MmapInner,
416}
417
418impl MmapMut {
419    /// Creates a writeable memory map backed by a file.
420    ///
421    /// This is equivalent to calling `MmapOptions::new().map_mut(file)`.
422    ///
423    /// # Errors
424    ///
425    /// This method returns an error when the underlying system call fails, which can happen for a
426    /// variety of reasons, such as when the file is not open with read and write permissions.
427    ///
428    /// # Example
429    ///
430    /// ```
431    /// # extern crate memmap;
432    /// # extern crate tempdir;
433    /// #
434    /// use std::fs::OpenOptions;
435    /// use std::path::PathBuf;
436    ///
437    /// use memmap::MmapMut;
438    /// #
439    /// # fn main() -> std::io::Result<()> {
440    /// # let tempdir = tempdir::TempDir::new("mmap")?;
441    /// let path: PathBuf = /* path to file */
442    /// #   tempdir.path().join("map_mut");
443    /// let file = OpenOptions::new()
444    ///                        .read(true)
445    ///                        .write(true)
446    ///                        .create(true)
447    ///                        .open(&path)?;
448    /// file.set_len(13)?;
449    ///
450    /// let mut mmap = unsafe { MmapMut::map_mut(&file)? };
451    ///
452    /// mmap.copy_from_slice(b"Hello, world!");
453    /// # Ok(())
454    /// # }
455    /// ```
456    pub unsafe fn map_mut(file: &File) -> Result<MmapMut> {
457        MmapOptions::new().map_mut(file)
458    }
459
460    /// Creates an anonymous memory map.
461    ///
462    /// This is equivalent to calling `MmapOptions::new().len(length).map_anon()`.
463    ///
464    /// # Errors
465    ///
466    /// This method returns an error when the underlying system call fails.
467    pub fn map_anon(length: usize) -> Result<MmapMut> {
468        MmapOptions::new().len(length).map_anon()
469    }
470
471    /// Flushes outstanding memory map modifications to disk.
472    ///
473    /// When this method returns with a non-error result, all outstanding changes to a file-backed
474    /// memory map are guaranteed to be durably stored. The file's metadata (including last
475    /// modification timestamp) may not be updated.
476    ///
477    /// # Example
478    ///
479    /// ```
480    /// # extern crate memmap;
481    /// # extern crate tempdir;
482    /// #
483    /// use std::fs::OpenOptions;
484    /// use std::io::Write;
485    /// use std::path::PathBuf;
486    ///
487    /// use memmap::MmapMut;
488    ///
489    /// # fn main() -> std::io::Result<()> {
490    /// # let tempdir = tempdir::TempDir::new("mmap")?;
491    /// let path: PathBuf = /* path to file */
492    /// #   tempdir.path().join("flush");
493    /// let file = OpenOptions::new().read(true).write(true).create(true).open(&path)?;
494    /// file.set_len(128)?;
495    ///
496    /// let mut mmap = unsafe { MmapMut::map_mut(&file)? };
497    ///
498    /// (&mut mmap[..]).write_all(b"Hello, world!")?;
499    /// mmap.flush()?;
500    /// # Ok(())
501    /// # }
502    /// ```
503    pub fn flush(&self) -> Result<()> {
504        let len = self.len();
505        self.inner.flush(0, len)
506    }
507
508    /// Asynchronously flushes outstanding memory map modifications to disk.
509    ///
510    /// This method initiates flushing modified pages to durable storage, but it will not wait for
511    /// the operation to complete before returning. The file's metadata (including last
512    /// modification timestamp) may not be updated.
513    pub fn flush_async(&self) -> Result<()> {
514        let len = self.len();
515        self.inner.flush_async(0, len)
516    }
517
518    /// Flushes outstanding memory map modifications in the range to disk.
519    ///
520    /// The offset and length must be in the bounds of the memory map.
521    ///
522    /// When this method returns with a non-error result, all outstanding changes to a file-backed
523    /// memory in the range are guaranteed to be durable stored. The file's metadata (including
524    /// last modification timestamp) may not be updated. It is not guaranteed the only the changes
525    /// in the specified range are flushed; other outstanding changes to the memory map may be
526    /// flushed as well.
527    pub fn flush_range(&self, offset: usize, len: usize) -> Result<()> {
528        self.inner.flush(offset, len)
529    }
530
531    /// Asynchronously flushes outstanding memory map modifications in the range to disk.
532    ///
533    /// The offset and length must be in the bounds of the memory map.
534    ///
535    /// This method initiates flushing modified pages to durable storage, but it will not wait for
536    /// the operation to complete before returning. The file's metadata (including last
537    /// modification timestamp) may not be updated. It is not guaranteed that the only changes
538    /// flushed are those in the specified range; other outstanding changes to the memory map may
539    /// be flushed as well.
540    pub fn flush_async_range(&self, offset: usize, len: usize) -> Result<()> {
541        self.inner.flush_async(offset, len)
542    }
543
544    /// Returns an immutable version of this memory mapped buffer.
545    ///
546    /// If the memory map is file-backed, the file must have been opened with read permissions.
547    ///
548    /// # Errors
549    ///
550    /// This method returns an error when the underlying system call fails, which can happen for a
551    /// variety of reasons, such as when the file has not been opened with read permissions.
552    ///
553    /// # Example
554    ///
555    /// ```
556    /// # extern crate memmap;
557    /// #
558    /// use std::io::Write;
559    /// use std::path::PathBuf;
560    ///
561    /// use memmap::{Mmap, MmapMut};
562    ///
563    /// # fn main() -> std::io::Result<()> {
564    /// let mut mmap = MmapMut::map_anon(128)?;
565    ///
566    /// (&mut mmap[..]).write(b"Hello, world!")?;
567    ///
568    /// let mmap: Mmap = mmap.make_read_only()?;
569    /// # Ok(())
570    /// # }
571    /// ```
572    pub fn make_read_only(mut self) -> Result<Mmap> {
573        self.inner.make_read_only()?;
574        Ok(Mmap { inner: self.inner })
575    }
576
577    /// Transition the memory map to be readable and executable.
578    ///
579    /// If the memory map is file-backed, the file must have been opened with execute permissions.
580    ///
581    /// # Errors
582    ///
583    /// This method returns an error when the underlying system call fails, which can happen for a
584    /// variety of reasons, such as when the file has not been opened with execute permissions.
585    pub fn make_exec(mut self) -> Result<Mmap> {
586        self.inner.make_exec()?;
587        Ok(Mmap { inner: self.inner })
588    }
589}
590
591impl Deref for MmapMut {
592    type Target = [u8];
593
594    #[inline]
595    fn deref(&self) -> &[u8] {
596        unsafe { slice::from_raw_parts(self.inner.ptr(), self.inner.len()) }
597    }
598}
599
600impl DerefMut for MmapMut {
601    #[inline]
602    fn deref_mut(&mut self) -> &mut [u8] {
603        unsafe { slice::from_raw_parts_mut(self.inner.mut_ptr(), self.inner.len()) }
604    }
605}
606
607impl AsRef<[u8]> for MmapMut {
608    #[inline]
609    fn as_ref(&self) -> &[u8] {
610        self.deref()
611    }
612}
613
614impl AsMut<[u8]> for MmapMut {
615    #[inline]
616    fn as_mut(&mut self) -> &mut [u8] {
617        self.deref_mut()
618    }
619}
620
621impl fmt::Debug for MmapMut {
622    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
623        fmt.debug_struct("MmapMut")
624            .field("ptr", &self.as_ptr())
625            .field("len", &self.len())
626            .finish()
627    }
628}
629
630#[cfg(test)]
631mod test {
632
633    extern crate tempdir;
634    #[cfg(windows)]
635    extern crate winapi;
636
637    use std::fs::OpenOptions;
638    use std::io::{Read, Write};
639    #[cfg(windows)]
640    use std::os::windows::fs::OpenOptionsExt;
641    use std::sync::Arc;
642    use std::thread;
643
644    #[cfg(windows)]
645    use winapi::um::winnt::GENERIC_ALL;
646
647    use super::{Mmap, MmapMut, MmapOptions};
648
649    #[test]
650    fn map_file() {
651        let expected_len = 128;
652        let tempdir = tempdir::TempDir::new("mmap").unwrap();
653        let path = tempdir.path().join("mmap");
654
655        let file = OpenOptions::new()
656            .read(true)
657            .write(true)
658            .create(true)
659            .open(&path)
660            .unwrap();
661
662        file.set_len(expected_len as u64).unwrap();
663
664        let mut mmap = unsafe { MmapMut::map_mut(&file).unwrap() };
665        let len = mmap.len();
666        assert_eq!(expected_len, len);
667
668        let zeros = vec![0; len];
669        let incr: Vec<u8> = (0..len as u8).collect();
670
671        // check that the mmap is empty
672        assert_eq!(&zeros[..], &mmap[..]);
673
674        // write values into the mmap
675        (&mut mmap[..]).write_all(&incr[..]).unwrap();
676
677        // read values back
678        assert_eq!(&incr[..], &mmap[..]);
679    }
680
681    /// Checks that a 0-length file will not be mapped.
682    #[test]
683    fn map_empty_file() {
684        let tempdir = tempdir::TempDir::new("mmap").unwrap();
685        let path = tempdir.path().join("mmap");
686
687        let file = OpenOptions::new()
688            .read(true)
689            .write(true)
690            .create(true)
691            .open(&path)
692            .unwrap();
693        let mmap = unsafe { Mmap::map(&file) };
694        assert!(mmap.is_err());
695    }
696
697    #[test]
698    fn map_anon() {
699        let expected_len = 128;
700        let mut mmap = MmapMut::map_anon(expected_len).unwrap();
701        let len = mmap.len();
702        assert_eq!(expected_len, len);
703
704        let zeros = vec![0; len];
705        let incr: Vec<u8> = (0..len as u8).collect();
706
707        // check that the mmap is empty
708        assert_eq!(&zeros[..], &mmap[..]);
709
710        // write values into the mmap
711        (&mut mmap[..]).write_all(&incr[..]).unwrap();
712
713        // read values back
714        assert_eq!(&incr[..], &mmap[..]);
715    }
716
717    #[test]
718    fn map_anon_zero_len() {
719        assert!(MmapOptions::new().map_anon().is_err())
720    }
721
722    #[test]
723    fn file_write() {
724        let tempdir = tempdir::TempDir::new("mmap").unwrap();
725        let path = tempdir.path().join("mmap");
726
727        let mut file = OpenOptions::new()
728            .read(true)
729            .write(true)
730            .create(true)
731            .open(&path)
732            .unwrap();
733        file.set_len(128).unwrap();
734
735        let write = b"abc123";
736        let mut read = [0u8; 6];
737
738        let mut mmap = unsafe { MmapMut::map_mut(&file).unwrap() };
739        (&mut mmap[..]).write_all(write).unwrap();
740        mmap.flush().unwrap();
741
742        file.read(&mut read).unwrap();
743        assert_eq!(write, &read);
744    }
745
746    #[test]
747    fn flush_range() {
748        let tempdir = tempdir::TempDir::new("mmap").unwrap();
749        let path = tempdir.path().join("mmap");
750
751        let file = OpenOptions::new()
752            .read(true)
753            .write(true)
754            .create(true)
755            .open(&path)
756            .unwrap();
757        file.set_len(128).unwrap();
758        let write = b"abc123";
759
760        let mut mmap = unsafe {
761            MmapOptions::new()
762                .offset(2)
763                .len(write.len())
764                .map_mut(&file)
765                .unwrap()
766        };
767        (&mut mmap[..]).write_all(write).unwrap();
768        mmap.flush_range(0, write.len()).unwrap();
769    }
770
771    #[test]
772    fn map_copy() {
773        let tempdir = tempdir::TempDir::new("mmap").unwrap();
774        let path = tempdir.path().join("mmap");
775
776        let mut file = OpenOptions::new()
777            .read(true)
778            .write(true)
779            .create(true)
780            .open(&path)
781            .unwrap();
782        file.set_len(128).unwrap();
783
784        let nulls = b"\0\0\0\0\0\0";
785        let write = b"abc123";
786        let mut read = [0u8; 6];
787
788        let mut mmap = unsafe { MmapOptions::new().map_copy(&file).unwrap() };
789
790        (&mut mmap[..]).write(write).unwrap();
791        mmap.flush().unwrap();
792
793        // The mmap contains the write
794        (&mmap[..]).read(&mut read).unwrap();
795        assert_eq!(write, &read);
796
797        // The file does not contain the write
798        file.read(&mut read).unwrap();
799        assert_eq!(nulls, &read);
800
801        // another mmap does not contain the write
802        let mmap2 = unsafe { MmapOptions::new().map(&file).unwrap() };
803        (&mmap2[..]).read(&mut read).unwrap();
804        assert_eq!(nulls, &read);
805    }
806
807    #[test]
808    fn map_offset() {
809        let tempdir = tempdir::TempDir::new("mmap").unwrap();
810        let path = tempdir.path().join("mmap");
811
812        let file = OpenOptions::new()
813            .read(true)
814            .write(true)
815            .create(true)
816            .open(&path)
817            .unwrap();
818
819        let offset = u32::max_value() as u64 + 2;
820        let len = 5432;
821        file.set_len(offset + len as u64).unwrap();
822
823        // Check inferred length mmap.
824        let mmap = unsafe { MmapOptions::new().offset(offset).map_mut(&file).unwrap() };
825        assert_eq!(len, mmap.len());
826
827        // Check explicit length mmap.
828        let mut mmap = unsafe {
829            MmapOptions::new()
830                .offset(offset)
831                .len(len)
832                .map_mut(&file)
833                .unwrap()
834        };
835        assert_eq!(len, mmap.len());
836
837        let zeros = vec![0; len];
838        let incr: Vec<_> = (0..len).map(|i| i as u8).collect();
839
840        // check that the mmap is empty
841        assert_eq!(&zeros[..], &mmap[..]);
842
843        // write values into the mmap
844        (&mut mmap[..]).write_all(&incr[..]).unwrap();
845
846        // read values back
847        assert_eq!(&incr[..], &mmap[..]);
848    }
849
850    #[test]
851    fn index() {
852        let mut mmap = MmapMut::map_anon(128).unwrap();
853        mmap[0] = 42;
854        assert_eq!(42, mmap[0]);
855    }
856
857    #[test]
858    fn sync_send() {
859        let mmap = Arc::new(MmapMut::map_anon(129).unwrap());
860        thread::spawn(move || {
861            &mmap[..];
862        });
863    }
864
865    #[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
866    fn jit_x86(mut mmap: MmapMut) {
867        use std::mem;
868        mmap[0] = 0xB8; // mov eax, 0xAB
869        mmap[1] = 0xAB;
870        mmap[2] = 0x00;
871        mmap[3] = 0x00;
872        mmap[4] = 0x00;
873        mmap[5] = 0xC3; // ret
874
875        let mmap = mmap.make_exec().expect("make_exec");
876
877        let jitfn: extern "C" fn() -> u8 = unsafe { mem::transmute(mmap.as_ptr()) };
878        assert_eq!(jitfn(), 0xab);
879    }
880
881    #[test]
882    #[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
883    fn jit_x86_anon() {
884        jit_x86(MmapMut::map_anon(4096).unwrap());
885    }
886
887    #[test]
888    #[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
889    fn jit_x86_file() {
890        let tempdir = tempdir::TempDir::new("mmap").unwrap();
891        let mut options = OpenOptions::new();
892        #[cfg(windows)]
893        options.access_mode(GENERIC_ALL);
894
895        let file = options
896            .read(true)
897            .write(true)
898            .create(true)
899            .open(&tempdir.path().join("jit_x86"))
900            .expect("open");
901
902        file.set_len(4096).expect("set_len");
903        jit_x86(unsafe { MmapMut::map_mut(&file).expect("map_mut") });
904    }
905
906    #[test]
907    fn mprotect_file() {
908        let tempdir = tempdir::TempDir::new("mmap").unwrap();
909        let path = tempdir.path().join("mmap");
910
911        let mut options = OpenOptions::new();
912        #[cfg(windows)]
913        options.access_mode(GENERIC_ALL);
914
915        let mut file = options
916            .read(true)
917            .write(true)
918            .create(true)
919            .open(&path)
920            .expect("open");
921        file.set_len(256 as u64).expect("set_len");
922
923        let mmap = unsafe { MmapMut::map_mut(&file).expect("map_mut") };
924
925        let mmap = mmap.make_read_only().expect("make_read_only");
926        let mut mmap = mmap.make_mut().expect("make_mut");
927
928        let write = b"abc123";
929        let mut read = [0u8; 6];
930
931        (&mut mmap[..]).write(write).unwrap();
932        mmap.flush().unwrap();
933
934        // The mmap contains the write
935        (&mmap[..]).read(&mut read).unwrap();
936        assert_eq!(write, &read);
937
938        // The file should contain the write
939        file.read(&mut read).unwrap();
940        assert_eq!(write, &read);
941
942        // another mmap should contain the write
943        let mmap2 = unsafe { MmapOptions::new().map(&file).unwrap() };
944        (&mmap2[..]).read(&mut read).unwrap();
945        assert_eq!(write, &read);
946
947        let mmap = mmap.make_exec().expect("make_exec");
948
949        drop(mmap);
950    }
951
952    #[test]
953    fn mprotect_copy() {
954        let tempdir = tempdir::TempDir::new("mmap").unwrap();
955        let path = tempdir.path().join("mmap");
956
957        let mut options = OpenOptions::new();
958        #[cfg(windows)]
959        options.access_mode(GENERIC_ALL);
960
961        let mut file = options
962            .read(true)
963            .write(true)
964            .create(true)
965            .open(&path)
966            .expect("open");
967        file.set_len(256 as u64).expect("set_len");
968
969        let mmap = unsafe { MmapOptions::new().map_copy(&file).expect("map_mut") };
970
971        let mmap = mmap.make_read_only().expect("make_read_only");
972        let mut mmap = mmap.make_mut().expect("make_mut");
973
974        let nulls = b"\0\0\0\0\0\0";
975        let write = b"abc123";
976        let mut read = [0u8; 6];
977
978        (&mut mmap[..]).write(write).unwrap();
979        mmap.flush().unwrap();
980
981        // The mmap contains the write
982        (&mmap[..]).read(&mut read).unwrap();
983        assert_eq!(write, &read);
984
985        // The file does not contain the write
986        file.read(&mut read).unwrap();
987        assert_eq!(nulls, &read);
988
989        // another mmap does not contain the write
990        let mmap2 = unsafe { MmapOptions::new().map(&file).unwrap() };
991        (&mmap2[..]).read(&mut read).unwrap();
992        assert_eq!(nulls, &read);
993
994        let mmap = mmap.make_exec().expect("make_exec");
995
996        drop(mmap);
997    }
998
999    #[test]
1000    fn mprotect_anon() {
1001        let mmap = MmapMut::map_anon(256).expect("map_mut");
1002
1003        let mmap = mmap.make_read_only().expect("make_read_only");
1004        let mmap = mmap.make_mut().expect("make_mut");
1005        let mmap = mmap.make_exec().expect("make_exec");
1006        drop(mmap);
1007    }
1008}