1#![doc = include_str!("../README.md")]
2#![deny(
3 missing_docs,
4 rustdoc::broken_intra_doc_links,
5 missing_debug_implementations
6)]
7
8mod areas;
9pub mod error;
10mod mmap;
11mod os_impl;
12
13pub use areas::*;
14pub use error::Error;
15pub use mmap::*;
16
17#[cfg(test)]
18mod tests {
19 #[test]
20 fn reserve_none() {
21 use crate::{MemoryAreas, MmapNone, MmapOptions, Protection, ShareMode};
22
23 let mapping = MmapOptions::new(MmapOptions::page_size())
24 .unwrap()
25 .reserve_none()
26 .unwrap();
27
28 assert!(mapping.as_ptr() != std::ptr::null());
29
30 let mapping: MmapNone = mapping.try_into().unwrap();
31
32 assert!(mapping.as_ptr() != std::ptr::null());
33
34 let region = MemoryAreas::query(mapping.as_ptr() as usize)
35 .unwrap()
36 .unwrap();
37
38 assert_eq!(region.share_mode, ShareMode::Private);
39 assert!(!region.protection.contains(Protection::READ));
40 assert!(!region.protection.contains(Protection::WRITE));
41 assert!(!region.protection.contains(Protection::EXECUTE));
42 }
43
44 #[test]
45 fn reserve() {
46 use crate::{MemoryAreas, Mmap, MmapOptions, Protection, ShareMode};
47
48 let mapping = MmapOptions::new(MmapOptions::page_size())
49 .unwrap()
50 .map()
51 .unwrap();
52
53 assert!(mapping.as_ptr() != std::ptr::null());
54
55 let mapping: Mmap = mapping.try_into().unwrap();
56
57 assert!(mapping.as_ptr() != std::ptr::null());
58
59 let region = MemoryAreas::query(mapping.as_ptr() as usize)
60 .unwrap()
61 .unwrap();
62
63 assert_eq!(region.share_mode, ShareMode::Private);
64 assert!(region.protection.contains(Protection::READ));
65 assert!(!region.protection.contains(Protection::WRITE));
66 assert!(!region.protection.contains(Protection::EXECUTE));
67 }
68
69 #[test]
70 fn reserve_mut() {
71 use crate::{MemoryAreas, MmapMut, MmapOptions, Protection, ShareMode};
72
73 let mapping = MmapOptions::new(MmapOptions::page_size())
74 .unwrap()
75 .reserve_mut()
76 .unwrap();
77
78 assert!(mapping.as_ptr() != std::ptr::null());
79
80 let mut mapping: MmapMut = mapping.try_into().unwrap();
81
82 mapping[0] = 0x42;
83
84 assert!(mapping.as_ptr() != std::ptr::null());
85 assert_eq!(mapping[0], 0x42);
86
87 let region = MemoryAreas::query(mapping.as_ptr() as usize)
88 .unwrap()
89 .unwrap();
90
91 assert_eq!(region.share_mode, ShareMode::Private);
92 assert!(region.protection.contains(Protection::READ));
93 assert!(region.protection.contains(Protection::WRITE));
94 assert!(!region.protection.contains(Protection::EXECUTE));
95 }
96
97 #[test]
98 fn map_none() {
99 use crate::{MemoryAreas, MmapOptions, Protection, ShareMode};
100
101 let mapping = MmapOptions::new(MmapOptions::page_size())
102 .unwrap()
103 .map_none()
104 .unwrap();
105
106 assert!(mapping.as_ptr() != std::ptr::null());
107
108 let region = MemoryAreas::query(mapping.as_ptr() as usize)
109 .unwrap()
110 .unwrap();
111
112 assert_eq!(region.share_mode, ShareMode::Private);
113 assert!(!region.protection.contains(Protection::READ));
114 assert!(!region.protection.contains(Protection::WRITE));
115 assert!(!region.protection.contains(Protection::EXECUTE));
116 }
117
118 #[test]
119 fn map() {
120 use crate::{MemoryAreas, MmapOptions, Protection, ShareMode};
121
122 let mapping = MmapOptions::new(MmapOptions::page_size())
123 .unwrap()
124 .map()
125 .unwrap();
126
127 assert!(mapping.as_ptr() != std::ptr::null());
128
129 let region = MemoryAreas::query(mapping.as_ptr() as usize)
130 .unwrap()
131 .unwrap();
132
133 assert_eq!(region.share_mode, ShareMode::Private);
134 assert!(region.protection.contains(Protection::READ));
135 assert!(!region.protection.contains(Protection::WRITE));
136 assert!(!region.protection.contains(Protection::EXECUTE));
137 }
138
139 #[test]
140 fn map_mut() {
141 use crate::{MemoryAreas, MmapOptions, Protection, ShareMode};
142
143 let mut mapping = MmapOptions::new(MmapOptions::page_size())
144 .unwrap()
145 .map_mut()
146 .unwrap();
147
148 mapping[0] = 0x42;
149
150 assert!(mapping.as_ptr() != std::ptr::null());
151 assert_eq!(mapping[0], 0x42);
152
153 let region = MemoryAreas::query(mapping.as_ptr() as usize)
154 .unwrap()
155 .unwrap();
156
157 assert_eq!(region.share_mode, ShareMode::Private);
158 assert!(region.protection.contains(Protection::READ));
159 assert!(region.protection.contains(Protection::WRITE));
160 assert!(!region.protection.contains(Protection::EXECUTE));
161 }
162
163 #[test]
164 fn map_file() {
165 use crate::{MemoryAreas, MmapFlags, MmapOptions, Protection, ShareMode};
166 use std::io::Write;
167 use tempfile::NamedTempFile;
168
169 let mut file = NamedTempFile::new().unwrap();
170
171 let mut bytes = vec![0u8; MmapOptions::page_size()];
172 bytes[0] = 0x42;
173 file.as_file_mut().write(&bytes).unwrap();
174
175 let mapping = unsafe {
176 MmapOptions::new(MmapOptions::page_size())
177 .unwrap()
178 .with_flags(MmapFlags::SHARED)
179 .with_file(file.as_file(), 0)
180 .map()
181 .unwrap()
182 };
183
184 let other_mapping = unsafe {
185 MmapOptions::new(MmapOptions::page_size())
186 .unwrap()
187 .with_flags(MmapFlags::SHARED)
188 .with_file(file.as_file(), 0)
189 .map()
190 .unwrap()
191 };
192
193 assert_ne!(mapping.as_ptr(), std::ptr::null());
194 assert_ne!(other_mapping.as_ptr(), std::ptr::null());
195 assert_eq!(mapping[0], 0x42);
196 assert_eq!(other_mapping[0], 0x42);
197
198 let region = MemoryAreas::query(mapping.as_ptr() as usize)
199 .unwrap()
200 .unwrap();
201
202 assert_eq!(region.share_mode, ShareMode::Shared);
203 assert!(region.protection.contains(Protection::READ));
204 assert!(!region.protection.contains(Protection::WRITE));
205 assert!(!region.protection.contains(Protection::EXECUTE));
206 #[cfg(not(target_os = "freebsd"))]
207 assert!(region.path().is_some());
208 }
209
210 #[test]
211 fn map_file_mut() {
212 use crate::{MemoryAreas, MmapFlags, MmapOptions, Protection, ShareMode};
213 use std::io::{Read, Seek, SeekFrom, Write};
214 use tempfile::NamedTempFile;
215
216 let mut file = NamedTempFile::new().unwrap();
217
218 let mut bytes = vec![0u8; MmapOptions::page_size()];
219 file.as_file_mut().write(&bytes).unwrap();
220
221 let mut mapping = unsafe {
222 MmapOptions::new(MmapOptions::page_size())
223 .unwrap()
224 .with_flags(MmapFlags::SHARED)
225 .with_file(file.as_file(), 0)
226 .map_mut()
227 .unwrap()
228 };
229
230 let other_mapping = unsafe {
231 MmapOptions::new(MmapOptions::page_size())
232 .unwrap()
233 .with_flags(MmapFlags::SHARED)
234 .with_file(file.as_file(), 0)
235 .map()
236 .unwrap()
237 };
238
239 assert_ne!(mapping.as_ptr(), std::ptr::null());
240 assert_ne!(other_mapping.as_ptr(), std::ptr::null());
241 mapping[0] = 0x42;
242 assert_eq!(other_mapping[0], 0x42);
243 mapping.flush(0..MmapOptions::page_size()).unwrap();
244 file.as_file_mut().sync_all().unwrap();
245
246 let region = MemoryAreas::query(mapping.as_ptr() as usize)
247 .unwrap()
248 .unwrap();
249
250 assert_eq!(region.share_mode, ShareMode::Shared);
251 assert!(region.protection.contains(Protection::READ));
252 assert!(region.protection.contains(Protection::WRITE));
253 assert!(!region.protection.contains(Protection::EXECUTE));
254 #[cfg(not(target_os = "freebsd"))]
255 assert!(region.path().is_some());
256
257 file.as_file_mut().seek(SeekFrom::Start(0)).unwrap();
258 file.as_file().read(&mut bytes).unwrap();
259 assert_eq!(bytes[0], 0x42);
260 }
261
262 #[test]
263 fn map_file_private() {
264 use crate::{MemoryAreas, MmapOptions, Protection, ShareMode};
265 use std::io::{Read, Seek, SeekFrom, Write};
266 use tempfile::NamedTempFile;
267
268 let mut file = NamedTempFile::new().unwrap();
269
270 let mut bytes = vec![0u8; MmapOptions::page_size()];
271 file.as_file_mut().write(&bytes).unwrap();
272
273 let mut mapping = unsafe {
274 MmapOptions::new(MmapOptions::page_size())
275 .unwrap()
276 .with_file(file.as_file(), 0)
277 .map_mut()
278 .unwrap()
279 };
280
281 let other_mapping = unsafe {
282 MmapOptions::new(MmapOptions::page_size())
283 .unwrap()
284 .with_file(file.as_file(), 0)
285 .map()
286 .unwrap()
287 };
288
289 assert_ne!(mapping.as_ptr(), std::ptr::null());
290 assert_ne!(other_mapping.as_ptr(), std::ptr::null());
291 mapping[0] = 0x42;
292 assert_ne!(other_mapping[0], 0x42);
293 mapping.flush(0..MmapOptions::page_size()).unwrap();
294 file.as_file_mut().sync_all().unwrap();
295
296 let region = MemoryAreas::query(mapping.as_ptr() as usize)
297 .unwrap()
298 .unwrap();
299
300 assert_eq!(region.share_mode, ShareMode::Private);
301 assert!(region.protection.contains(Protection::READ));
302 assert!(region.protection.contains(Protection::WRITE));
303 assert!(!region.protection.contains(Protection::EXECUTE));
304 #[cfg(not(target_os = "freebsd"))]
305 assert!(region.path().is_some());
306
307 file.as_file_mut().seek(SeekFrom::Start(0)).unwrap();
308 file.as_file().read(&mut bytes).unwrap();
309 assert_ne!(bytes[0], 0x42);
310 }
311
312 #[test]
313 fn reserve_and_split() {
314 use crate::{MmapMut, MmapOptions};
315
316 let mut mapping = MmapOptions::new(2 * MmapOptions::page_size())
317 .unwrap()
318 .reserve_mut()
319 .unwrap();
320
321 let rest = mapping.split_off(MmapOptions::page_size()).unwrap();
322
323 assert!(mapping.as_ptr() < rest.as_ptr());
324
325 let mut rest: MmapMut = rest.try_into().unwrap();
326
327 rest[0] = 0x42;
328 assert_eq!(rest[0], 0x42);
329
330 assert_eq!(mapping.len(), MmapOptions::page_size());
331 assert_eq!(rest.len(), MmapOptions::page_size());
332 assert!(mapping.as_ptr() < rest.as_ptr());
333 }
334
335 #[test]
336 fn split_off() {
337 use crate::MmapOptions;
338
339 let mut mapping = MmapOptions::new(2 * MmapOptions::page_size())
340 .unwrap()
341 .map_mut()
342 .unwrap();
343
344 assert!(mapping.split_off(1).is_err());
345
346 mapping[0] = 0x1;
347 mapping[MmapOptions::page_size()] = 0x2;
348
349 let rest = mapping.split_off(MmapOptions::page_size()).unwrap();
350
351 assert_eq!(mapping[0], 0x1);
352 assert_eq!(rest[0], 0x2);
353 assert_eq!(mapping.len(), MmapOptions::page_size());
354 assert_eq!(rest.len(), MmapOptions::page_size());
355 assert!(mapping.as_ptr() < rest.as_ptr());
356 }
357
358 #[test]
359 fn split_to() {
360 use crate::MmapOptions;
361
362 let mut mapping = MmapOptions::new(2 * MmapOptions::page_size())
363 .unwrap()
364 .map_mut()
365 .unwrap();
366
367 assert!(mapping.split_to(1).is_err());
368
369 mapping[0] = 0x1;
370 mapping[MmapOptions::page_size()] = 0x2;
371
372 let rest = mapping.split_to(MmapOptions::page_size()).unwrap();
373
374 assert_eq!(mapping[0], 0x2);
375 assert_eq!(rest[0], 0x1);
376 assert_eq!(mapping.len(), MmapOptions::page_size());
377 assert_eq!(rest.len(), MmapOptions::page_size());
378 assert!(mapping.as_ptr() > rest.as_ptr());
379 }
380
381 #[test]
382 fn split_file() {
383 use crate::MmapOptions;
384 use std::io::Write;
385 use tempfile::NamedTempFile;
386
387 let mut file = NamedTempFile::new().unwrap();
388
389 let mut bytes = vec![0u8; 2 * MmapOptions::page_size()];
390 bytes[0] = 0x1;
391 bytes[MmapOptions::page_size()] = 0x2;
392 file.as_file_mut().write(&bytes).unwrap();
393
394 let mut mapping = unsafe {
395 MmapOptions::new(2 * MmapOptions::page_size())
396 .unwrap()
397 .with_file(file.as_file(), 0)
398 .map()
399 .unwrap()
400 };
401
402 assert!(mapping.split_off(1).is_err());
403
404 let rest = mapping.split_off(MmapOptions::page_size()).unwrap();
405
406 assert_eq!(mapping[0], 0x1);
407 assert_eq!(rest[0], 0x2);
408 assert_eq!(mapping.len(), MmapOptions::page_size());
409 assert_eq!(rest.len(), MmapOptions::page_size());
410 assert!(mapping.as_ptr() < rest.as_ptr());
411 }
412
413 #[test]
414 fn split_and_merge() {
415 use crate::{MemoryAreas, MmapOptions, Protection, ShareMode};
416
417 let mut left = MmapOptions::new(3 * MmapOptions::page_size())
419 .unwrap()
420 .map_mut()
421 .unwrap();
422
423 let mut middle = left.split_off(MmapOptions::page_size()).unwrap();
425 let right = middle.split_off(MmapOptions::page_size()).unwrap();
426
427 assert!(left.as_ptr() < middle.as_ptr());
428 assert!(middle.as_ptr() < right.as_ptr());
429
430 let Err((_, mut right)) = left.merge(right) else {
432 panic!("expected merge to fail")
433 };
434 let Err((_, left)) = right.merge(left) else {
435 panic!("expected merge to fail")
436 };
437
438 let Err((_, mut left)) = middle.merge(left) else {
440 panic!("expected merge to fail")
441 };
442 left.merge(middle).unwrap();
443
444 let Err((_, mut left)) = right.merge(left) else {
446 panic!("expected merge to fail")
447 };
448 left.merge(right).unwrap();
449
450 assert_eq!(left.size(), 3 * MmapOptions::page_size());
452
453 let region = MemoryAreas::query(left.as_ptr() as usize).unwrap().unwrap();
454
455 assert_eq!(region.share_mode, ShareMode::Private);
456 assert!(region.protection.contains(Protection::READ));
457 assert!(region.protection.contains(Protection::WRITE));
458 assert!(!region.protection.contains(Protection::EXECUTE));
459
460 assert!(region.range.start <= left.start());
462
463 let padding = left.start().saturating_sub(region.range.start);
465 let size = region.range.len().saturating_sub(padding);
466
467 assert!(size >= 3 * MmapOptions::page_size());
469 }
470
471 #[test]
472 fn query_range() {
473 use crate::{MemoryAreas, MmapOptions};
474
475 let mut left = MmapOptions::new(3 * MmapOptions::page_size())
477 .unwrap()
478 .map_mut()
479 .unwrap();
480
481 let mut middle = left.split_off(MmapOptions::page_size()).unwrap();
483 let right = middle.split_off(MmapOptions::page_size()).unwrap();
484
485 assert!(left.as_ptr() < middle.as_ptr());
486 assert!(middle.as_ptr() < right.as_ptr());
487
488 drop(middle);
490
491 let start = left.as_ptr() as usize;
493 let end = right.as_ptr() as usize + right.len();
494
495 let mut areas = MemoryAreas::query_range(start..end).unwrap();
496
497 let region = areas.next().unwrap().unwrap();
498 assert_eq!(
499 region.end(),
500 left.as_ptr() as usize + MmapOptions::page_size()
501 );
502 let mut region = areas.next().unwrap().unwrap();
503
504 if region.start() != right.as_ptr() as usize {
505 region = areas.next().unwrap().unwrap();
506 }
507
508 assert_eq!(region.start(), right.as_ptr() as usize);
509 assert!(areas.next().is_none());
510 }
511}