1use crate::error::{PdfError, Result};
7use std::fs::File;
8use std::io::{Read, Seek, SeekFrom};
9use std::ops::Deref;
10use std::path::Path;
11use std::sync::Arc;
12
13#[cfg(unix)]
15mod unix_mmap {
16 use super::*;
17 use std::os::unix::io::AsRawFd;
18 use std::ptr;
19
20 pub struct MmapInner {
21 ptr: *mut u8,
22 len: usize,
23 }
24
25 unsafe impl Send for MmapInner {}
27 unsafe impl Sync for MmapInner {}
28
29 impl MmapInner {
30 pub fn new(file: &File, len: usize) -> Result<Self> {
31 if len == 0 {
32 return Err(PdfError::InvalidFormat(
33 "Cannot mmap empty file".to_string(),
34 ));
35 }
36
37 unsafe {
38 let ptr = libc::mmap(
39 ptr::null_mut(),
40 len,
41 libc::PROT_READ,
42 libc::MAP_PRIVATE,
43 file.as_raw_fd(),
44 0,
45 );
46
47 if ptr == libc::MAP_FAILED {
48 return Err(PdfError::Io(std::io::Error::last_os_error()));
49 }
50
51 Ok(Self {
52 ptr: ptr as *mut u8,
53 len,
54 })
55 }
56 }
57
58 pub fn as_slice(&self) -> &[u8] {
59 unsafe { std::slice::from_raw_parts(self.ptr, self.len) }
60 }
61 }
62
63 impl Drop for MmapInner {
64 fn drop(&mut self) {
65 unsafe {
66 libc::munmap(self.ptr as *mut libc::c_void, self.len);
67 }
68 }
69 }
70}
71
72#[cfg(windows)]
73mod windows_mmap {
74 use super::*;
75 use std::os::windows::io::AsRawHandle;
76 use std::ptr;
77 use winapi::um::handleapi::CloseHandle;
78 use winapi::um::memoryapi::{
79 CreateFileMappingW, MapViewOfFile, UnmapViewOfFile, FILE_MAP_READ,
80 };
81 use winapi::um::winnt::PAGE_READONLY;
82
83 pub struct MmapInner {
84 ptr: *mut u8,
85 len: usize,
86 mapping_handle: *mut winapi::ctypes::c_void,
87 }
88
89 unsafe impl Send for MmapInner {}
90 unsafe impl Sync for MmapInner {}
91
92 impl MmapInner {
93 pub fn new(file: &File, len: usize) -> Result<Self> {
94 if len == 0 {
95 return Err(PdfError::InvalidFormat(
96 "Cannot mmap empty file".to_string(),
97 ));
98 }
99
100 unsafe {
101 let mapping_handle = CreateFileMappingW(
102 file.as_raw_handle() as *mut _,
103 ptr::null_mut(),
104 PAGE_READONLY,
105 0,
106 0,
107 ptr::null(),
108 );
109
110 if mapping_handle.is_null() {
111 return Err(PdfError::Io(std::io::Error::last_os_error()));
112 }
113
114 let ptr = MapViewOfFile(mapping_handle, FILE_MAP_READ, 0, 0, len);
115
116 if ptr.is_null() {
117 CloseHandle(mapping_handle);
118 return Err(PdfError::Io(std::io::Error::last_os_error()));
119 }
120
121 Ok(Self {
122 ptr: ptr as *mut u8,
123 len,
124 mapping_handle,
125 })
126 }
127 }
128
129 pub fn as_slice(&self) -> &[u8] {
130 unsafe { std::slice::from_raw_parts(self.ptr, self.len) }
131 }
132 }
133
134 impl Drop for MmapInner {
135 fn drop(&mut self) {
136 unsafe {
137 UnmapViewOfFile(self.ptr as *mut _);
138 CloseHandle(self.mapping_handle);
139 }
140 }
141 }
142}
143
144#[cfg(not(any(unix, windows)))]
146mod fallback_mmap {
147 use super::*;
148
149 pub struct MmapInner {
150 data: Vec<u8>,
151 }
152
153 impl MmapInner {
154 pub fn new(file: &File, len: usize) -> Result<Self> {
155 let mut data = vec![0u8; len];
156 let mut file_clone = file.try_clone()?;
157 file_clone.seek(SeekFrom::Start(0))?;
158 file_clone.read_exact(&mut data)?;
159 Ok(Self { data })
160 }
161
162 pub fn as_slice(&self) -> &[u8] {
163 &self.data
164 }
165 }
166}
167
168#[cfg(not(any(unix, windows)))]
169use fallback_mmap::MmapInner;
170#[cfg(unix)]
171use unix_mmap::MmapInner;
172#[cfg(windows)]
173use windows_mmap::MmapInner;
174
175pub struct MemoryMappedFile {
177 inner: Arc<MmapInner>,
178}
179
180impl MemoryMappedFile {
181 pub fn new<P: AsRef<Path>>(path: P) -> Result<Self> {
183 let file = File::open(path)?;
184 let metadata = file.metadata()?;
185 let len = metadata.len() as usize;
186
187 let inner = MmapInner::new(&file, len)?;
188
189 Ok(Self {
190 inner: Arc::new(inner),
191 })
192 }
193
194 pub fn len(&self) -> usize {
196 self.inner.as_slice().len()
197 }
198
199 pub fn is_empty(&self) -> bool {
201 self.inner.as_slice().is_empty()
202 }
203}
204
205impl Deref for MemoryMappedFile {
206 type Target = [u8];
207
208 fn deref(&self) -> &Self::Target {
209 self.inner.as_slice()
210 }
211}
212
213impl AsRef<[u8]> for MemoryMappedFile {
214 fn as_ref(&self) -> &[u8] {
215 self.inner.as_slice()
216 }
217}
218
219pub struct MappedReader {
221 mmap: MemoryMappedFile,
222 position: usize,
223}
224
225impl MappedReader {
226 pub fn new<P: AsRef<Path>>(path: P) -> Result<Self> {
228 let mmap = MemoryMappedFile::new(path)?;
229 Ok(Self { mmap, position: 0 })
230 }
231
232 pub fn get_slice(&self, start: usize, end: usize) -> Option<&[u8]> {
234 let data = self.mmap.as_ref();
235 if start <= end && end <= data.len() {
236 Some(&data[start..end])
237 } else {
238 None
239 }
240 }
241}
242
243impl Read for MappedReader {
244 fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize> {
245 let data = self.mmap.as_ref();
246 let remaining = data.len().saturating_sub(self.position);
247 let to_read = buf.len().min(remaining);
248
249 if to_read > 0 {
250 buf[..to_read].copy_from_slice(&data[self.position..self.position + to_read]);
251 self.position += to_read;
252 }
253
254 Ok(to_read)
255 }
256}
257
258impl Seek for MappedReader {
259 fn seek(&mut self, pos: SeekFrom) -> std::io::Result<u64> {
260 let new_pos = match pos {
261 SeekFrom::Start(n) => n as i64,
262 SeekFrom::End(n) => self.mmap.len() as i64 + n,
263 SeekFrom::Current(n) => self.position as i64 + n,
264 };
265
266 if new_pos < 0 || new_pos > self.mmap.len() as i64 {
267 return Err(std::io::Error::new(
268 std::io::ErrorKind::InvalidInput,
269 "Seek position out of bounds",
270 ));
271 }
272
273 self.position = new_pos as usize;
274 Ok(self.position as u64)
275 }
276}
277
278#[cfg(test)]
279mod tests {
280 use super::*;
281 use std::io::Write;
282 use tempfile::NamedTempFile;
283
284 #[test]
285 fn test_memory_mapped_file() {
286 let mut temp_file = NamedTempFile::new().unwrap();
288 let test_data = b"Hello, memory mapped world!";
289 temp_file.write_all(test_data).unwrap();
290 temp_file.flush().unwrap();
291
292 let mmap = MemoryMappedFile::new(temp_file.path()).unwrap();
294
295 assert_eq!(mmap.len(), test_data.len());
296 assert!(!mmap.is_empty());
297 assert_eq!(&mmap[..], test_data);
298 }
299
300 #[test]
301 fn test_mapped_reader_read() {
302 let mut temp_file = NamedTempFile::new().unwrap();
303 let test_data = b"Test data for mapped reader";
304 temp_file.write_all(test_data).unwrap();
305 temp_file.flush().unwrap();
306
307 let mut reader = MappedReader::new(temp_file.path()).unwrap();
308
309 let mut buf = [0u8; 4];
311 assert_eq!(reader.read(&mut buf).unwrap(), 4);
312 assert_eq!(&buf, b"Test");
313
314 let mut buf = [0u8; 5];
316 assert_eq!(reader.read(&mut buf).unwrap(), 5);
317 assert_eq!(&buf, b" data");
318 }
319
320 #[test]
321 fn test_mapped_reader_seek() {
322 let mut temp_file = NamedTempFile::new().unwrap();
323 let test_data = b"0123456789";
324 temp_file.write_all(test_data).unwrap();
325 temp_file.flush().unwrap();
326
327 let mut reader = MappedReader::new(temp_file.path()).unwrap();
328
329 assert_eq!(reader.seek(SeekFrom::Start(5)).unwrap(), 5);
331 let mut buf = [0u8; 2];
332 let _bytes_read = reader.read(&mut buf).unwrap();
333 assert_eq!(&buf, b"56");
334
335 assert_eq!(reader.seek(SeekFrom::Current(-3)).unwrap(), 4);
337 let _bytes_read = reader.read(&mut buf).unwrap();
338 assert_eq!(&buf, b"45");
339
340 assert_eq!(reader.seek(SeekFrom::End(-2)).unwrap(), 8);
342 let _bytes_read = reader.read(&mut buf).unwrap();
343 assert_eq!(&buf, b"89");
344 }
345
346 #[test]
347 fn test_get_slice() {
348 let mut temp_file = NamedTempFile::new().unwrap();
349 let test_data = b"Hello, World!";
350 temp_file.write_all(test_data).unwrap();
351 temp_file.flush().unwrap();
352
353 let reader = MappedReader::new(temp_file.path()).unwrap();
354
355 assert_eq!(reader.get_slice(0, 5), Some(&b"Hello"[..]));
356 assert_eq!(reader.get_slice(7, 12), Some(&b"World"[..]));
357 assert_eq!(
358 reader.get_slice(0, test_data.len()),
359 Some(test_data.as_ref())
360 );
361
362 assert_eq!(reader.get_slice(10, 20), None);
364 assert_eq!(reader.get_slice(5, 3), None); }
366
367 #[test]
368 fn test_memory_mapped_file_empty() {
369 let temp_file = NamedTempFile::new().unwrap();
370 let result = MemoryMappedFile::new(temp_file.path());
373
374 assert!(result.is_err());
376 match result {
377 Err(PdfError::InvalidFormat(msg)) => {
378 assert!(msg.contains("empty file"));
379 }
380 _ => panic!("Expected InvalidFormat error for empty file"),
381 }
382 }
383
384 #[test]
385 fn test_memory_mapped_file_nonexistent() {
386 let nonexistent_path = "/path/that/does/not/exist.pdf";
387 let result = MemoryMappedFile::new(nonexistent_path);
388
389 assert!(result.is_err());
390 match result {
391 Err(PdfError::Io(_)) => {}
392 _ => panic!("Expected IO error for nonexistent file"),
393 }
394 }
395
396 #[test]
397 fn test_memory_mapped_file_large() {
398 let mut temp_file = NamedTempFile::new().unwrap();
399 let large_data = vec![0xAB; 10000];
400 temp_file.write_all(&large_data).unwrap();
401 temp_file.flush().unwrap();
402
403 let mmap = MemoryMappedFile::new(temp_file.path()).unwrap();
404
405 assert_eq!(mmap.len(), 10000);
406 assert!(!mmap.is_empty());
407 assert_eq!(mmap[0], 0xAB);
408 assert_eq!(mmap[9999], 0xAB);
409 assert_eq!(&mmap[..100], &large_data[..100]);
410 }
411
412 #[test]
413 fn test_memory_mapped_file_deref() {
414 let mut temp_file = NamedTempFile::new().unwrap();
415 let test_data = b"Deref test data";
416 temp_file.write_all(test_data).unwrap();
417 temp_file.flush().unwrap();
418
419 let mmap = MemoryMappedFile::new(temp_file.path()).unwrap();
420
421 let slice: &[u8] = &mmap;
423 assert_eq!(slice, test_data);
424
425 assert_eq!(mmap[0], b'D');
427 assert_eq!(mmap[5], b' ');
428 assert_eq!(mmap[test_data.len() - 1], b'a');
429
430 let as_ref: &[u8] = mmap.as_ref();
432 assert_eq!(as_ref, test_data);
433 }
434
435 #[test]
436 fn test_memory_mapped_file_binary_data() {
437 let mut temp_file = NamedTempFile::new().unwrap();
438 let binary_data = vec![0x00, 0xFF, 0x7F, 0x80, 0x01, 0xFE];
439 temp_file.write_all(&binary_data).unwrap();
440 temp_file.flush().unwrap();
441
442 let mmap = MemoryMappedFile::new(temp_file.path()).unwrap();
443
444 assert_eq!(mmap.len(), 6);
445 assert_eq!(mmap[0], 0x00);
446 assert_eq!(mmap[1], 0xFF);
447 assert_eq!(mmap[2], 0x7F);
448 assert_eq!(mmap[3], 0x80);
449 assert_eq!(mmap[4], 0x01);
450 assert_eq!(mmap[5], 0xFE);
451 }
452
453 #[test]
454 fn test_memory_mapped_file_single_byte() {
455 let mut temp_file = NamedTempFile::new().unwrap();
456 temp_file.write_all(&[42]).unwrap();
457 temp_file.flush().unwrap();
458
459 let mmap = MemoryMappedFile::new(temp_file.path()).unwrap();
460
461 assert_eq!(mmap.len(), 1);
462 assert!(!mmap.is_empty());
463 assert_eq!(mmap[0], 42);
464 }
465
466 #[test]
467 fn test_mapped_reader_creation() {
468 let mut temp_file = NamedTempFile::new().unwrap();
469 let test_data = b"Reader creation test";
470 temp_file.write_all(test_data).unwrap();
471 temp_file.flush().unwrap();
472
473 let reader = MappedReader::new(temp_file.path()).unwrap();
474
475 assert_eq!(reader.mmap.len(), test_data.len());
476 assert_eq!(reader.position, 0);
477 }
478
479 #[test]
480 fn test_mapped_reader_read_entire_file() {
481 let mut temp_file = NamedTempFile::new().unwrap();
482 let test_data = b"Complete file read test";
483 temp_file.write_all(test_data).unwrap();
484 temp_file.flush().unwrap();
485
486 let mut reader = MappedReader::new(temp_file.path()).unwrap();
487
488 let mut buf = vec![0u8; test_data.len()];
489 let bytes_read = reader.read(&mut buf).unwrap();
490
491 assert_eq!(bytes_read, test_data.len());
492 assert_eq!(&buf, test_data);
493 assert_eq!(reader.position, test_data.len());
494 }
495
496 #[test]
497 fn test_mapped_reader_read_beyond_eof() {
498 let mut temp_file = NamedTempFile::new().unwrap();
499 let test_data = b"Short";
500 temp_file.write_all(test_data).unwrap();
501 temp_file.flush().unwrap();
502
503 let mut reader = MappedReader::new(temp_file.path()).unwrap();
504
505 let mut buf = vec![0u8; test_data.len()];
507 assert_eq!(reader.read(&mut buf).unwrap(), test_data.len());
508
509 let mut buf = vec![0u8; 10];
511 assert_eq!(reader.read(&mut buf).unwrap(), 0);
512 assert_eq!(reader.position, test_data.len());
513 }
514
515 #[test]
516 fn test_mapped_reader_partial_reads() {
517 let mut temp_file = NamedTempFile::new().unwrap();
518 let test_data = b"0123456789ABCDEF";
519 temp_file.write_all(test_data).unwrap();
520 temp_file.flush().unwrap();
521
522 let mut reader = MappedReader::new(temp_file.path()).unwrap();
523
524 let mut buf = [0u8; 4];
526
527 assert_eq!(reader.read(&mut buf).unwrap(), 4);
528 assert_eq!(&buf, b"0123");
529 assert_eq!(reader.position, 4);
530
531 assert_eq!(reader.read(&mut buf).unwrap(), 4);
532 assert_eq!(&buf, b"4567");
533 assert_eq!(reader.position, 8);
534
535 assert_eq!(reader.read(&mut buf).unwrap(), 4);
536 assert_eq!(&buf, b"89AB");
537 assert_eq!(reader.position, 12);
538
539 assert_eq!(reader.read(&mut buf).unwrap(), 4);
540 assert_eq!(&buf, b"CDEF");
541 assert_eq!(reader.position, 16);
542
543 assert_eq!(reader.read(&mut buf).unwrap(), 0);
545 }
546
547 #[test]
548 fn test_mapped_reader_seek_start() {
549 let mut temp_file = NamedTempFile::new().unwrap();
550 let test_data = b"Seek test data";
551 temp_file.write_all(test_data).unwrap();
552 temp_file.flush().unwrap();
553
554 let mut reader = MappedReader::new(temp_file.path()).unwrap();
555
556 assert_eq!(reader.seek(SeekFrom::Start(0)).unwrap(), 0);
558 assert_eq!(reader.position, 0);
559
560 assert_eq!(reader.seek(SeekFrom::Start(5)).unwrap(), 5);
561 assert_eq!(reader.position, 5);
562
563 assert_eq!(
564 reader
565 .seek(SeekFrom::Start(test_data.len() as u64))
566 .unwrap(),
567 test_data.len() as u64
568 );
569 assert_eq!(reader.position, test_data.len());
570 }
571
572 #[test]
573 fn test_mapped_reader_seek_current() {
574 let mut temp_file = NamedTempFile::new().unwrap();
575 let test_data = b"Current seek test";
576 temp_file.write_all(test_data).unwrap();
577 temp_file.flush().unwrap();
578
579 let mut reader = MappedReader::new(temp_file.path()).unwrap();
580
581 assert_eq!(reader.seek(SeekFrom::Current(5)).unwrap(), 5);
583 assert_eq!(reader.position, 5);
584
585 assert_eq!(reader.seek(SeekFrom::Current(3)).unwrap(), 8);
587 assert_eq!(reader.position, 8);
588
589 assert_eq!(reader.seek(SeekFrom::Current(-2)).unwrap(), 6);
591 assert_eq!(reader.position, 6);
592
593 assert_eq!(
595 reader
596 .seek(SeekFrom::Current(-(reader.position as i64)))
597 .unwrap(),
598 0
599 );
600 assert_eq!(reader.position, 0);
601 }
602
603 #[test]
604 fn test_mapped_reader_seek_end() {
605 let mut temp_file = NamedTempFile::new().unwrap();
606 let test_data = b"End seek test data";
607 temp_file.write_all(test_data).unwrap();
608 temp_file.flush().unwrap();
609
610 let mut reader = MappedReader::new(temp_file.path()).unwrap();
611
612 assert_eq!(
614 reader.seek(SeekFrom::End(0)).unwrap(),
615 test_data.len() as u64
616 );
617 assert_eq!(reader.position, test_data.len());
618
619 assert_eq!(
621 reader.seek(SeekFrom::End(-5)).unwrap(),
622 (test_data.len() - 5) as u64
623 );
624 assert_eq!(reader.position, test_data.len() - 5);
625
626 assert_eq!(
628 reader
629 .seek(SeekFrom::End(-(test_data.len() as i64)))
630 .unwrap(),
631 0
632 );
633 assert_eq!(reader.position, 0);
634 }
635
636 #[test]
637 fn test_mapped_reader_seek_out_of_bounds() {
638 let mut temp_file = NamedTempFile::new().unwrap();
639 let test_data = b"Bounds test";
640 temp_file.write_all(test_data).unwrap();
641 temp_file.flush().unwrap();
642
643 let mut reader = MappedReader::new(temp_file.path()).unwrap();
644
645 let result = reader.seek(SeekFrom::Start(u64::MAX));
647 assert!(result.is_err());
648 assert_eq!(reader.position, 0); let result = reader.seek(SeekFrom::Start((test_data.len() + 1) as u64));
652 assert!(result.is_err());
653 assert_eq!(reader.position, 0);
654
655 let result = reader.seek(SeekFrom::Current(-1));
657 assert!(result.is_err());
658 assert_eq!(reader.position, 0);
659
660 let result = reader.seek(SeekFrom::End(-((test_data.len() + 1) as i64)));
662 assert!(result.is_err());
663 assert_eq!(reader.position, 0);
664 }
665
666 #[test]
667 fn test_mapped_reader_seek_and_read_combination() {
668 let mut temp_file = NamedTempFile::new().unwrap();
669 let test_data = b"0123456789";
670 temp_file.write_all(test_data).unwrap();
671 temp_file.flush().unwrap();
672
673 let mut reader = MappedReader::new(temp_file.path()).unwrap();
674
675 reader.seek(SeekFrom::Start(3)).unwrap();
677 let mut buf = [0u8; 3];
678 let _bytes_read = reader.read(&mut buf).unwrap();
679 assert_eq!(&buf, b"345");
680
681 reader.seek(SeekFrom::Start(1)).unwrap();
683 let _bytes_read = reader.read(&mut buf).unwrap();
684 assert_eq!(&buf, b"123");
685
686 reader.seek(SeekFrom::Current(2)).unwrap(); let mut buf = [0u8; 2];
689 let _bytes_read = reader.read(&mut buf).unwrap();
690 assert_eq!(&buf, b"67");
691 }
692
693 #[test]
694 fn test_get_slice_edge_cases() {
695 let mut temp_file = NamedTempFile::new().unwrap();
696 let test_data = b"Edge case testing";
697 temp_file.write_all(test_data).unwrap();
698 temp_file.flush().unwrap();
699
700 let reader = MappedReader::new(temp_file.path()).unwrap();
701
702 assert_eq!(reader.get_slice(5, 5), Some(&b""[..]));
704
705 assert_eq!(reader.get_slice(0, 1), Some(&b"E"[..]));
707 assert_eq!(
708 reader.get_slice(test_data.len() - 1, test_data.len()),
709 Some(&b"g"[..])
710 );
711
712 assert_eq!(
714 reader.get_slice(0, test_data.len()),
715 Some(test_data.as_ref())
716 );
717
718 assert_eq!(
720 reader.get_slice(test_data.len(), test_data.len()),
721 Some(&b""[..])
722 );
723
724 assert_eq!(reader.get_slice(test_data.len(), test_data.len() + 1), None);
726 assert_eq!(
727 reader.get_slice(test_data.len() + 1, test_data.len() + 2),
728 None
729 );
730 assert_eq!(reader.get_slice(10, 5), None); }
732
733 #[test]
734 fn test_mapped_reader_zero_length_read() {
735 let mut temp_file = NamedTempFile::new().unwrap();
736 let test_data = b"Zero length test";
737 temp_file.write_all(test_data).unwrap();
738 temp_file.flush().unwrap();
739
740 let mut reader = MappedReader::new(temp_file.path()).unwrap();
741
742 let mut buf = [];
744 assert_eq!(reader.read(&mut buf).unwrap(), 0);
745 assert_eq!(reader.position, 0); }
747
748 #[test]
749 fn test_mapped_reader_large_buffer_read() {
750 let mut temp_file = NamedTempFile::new().unwrap();
751 let test_data = b"Small data";
752 temp_file.write_all(test_data).unwrap();
753 temp_file.flush().unwrap();
754
755 let mut reader = MappedReader::new(temp_file.path()).unwrap();
756
757 let mut buf = vec![0u8; 100];
759 let bytes_read = reader.read(&mut buf).unwrap();
760
761 assert_eq!(bytes_read, test_data.len());
762 assert_eq!(&buf[..bytes_read], test_data);
763 assert_eq!(reader.position, test_data.len());
764 }
765
766 #[test]
767 fn test_memory_mapped_file_utf8_content() {
768 let mut temp_file = NamedTempFile::new().unwrap();
769 let test_data = "Hello, δΈη! π¦".as_bytes();
770 temp_file.write_all(test_data).unwrap();
771 temp_file.flush().unwrap();
772
773 let mmap = MemoryMappedFile::new(temp_file.path()).unwrap();
774
775 assert_eq!(mmap.len(), test_data.len());
776 assert_eq!(&mmap[..], test_data);
777
778 let content = String::from_utf8_lossy(&mmap);
780 assert_eq!(content, "Hello, δΈη! π¦");
781 }
782
783 #[test]
784 fn test_mapped_reader_error_propagation() {
785 let nonexistent_path = "/definitely/does/not/exist/test.pdf";
786 let result = MappedReader::new(nonexistent_path);
787
788 assert!(result.is_err());
789 match result {
790 Err(PdfError::Io(_)) => {}
791 _ => panic!("Expected IO error"),
792 }
793 }
794
795 #[test]
796 fn test_get_slice_exact_boundaries() {
797 let mut temp_file = NamedTempFile::new().unwrap();
798 let test_data = b"Boundary test";
799 temp_file.write_all(test_data).unwrap();
800 temp_file.flush().unwrap();
801
802 let reader = MappedReader::new(temp_file.path()).unwrap();
803
804 let len = test_data.len();
806
807 assert_eq!(reader.get_slice(0, 1), Some(&b"B"[..]));
809
810 assert_eq!(reader.get_slice(len - 1, len), Some(&b"t"[..]));
812
813 assert_eq!(reader.get_slice(0, len), Some(test_data.as_ref()));
815
816 assert_eq!(reader.get_slice(len, len), Some(&b""[..]));
818
819 assert_eq!(reader.get_slice(len, len + 1), None);
821 assert_eq!(reader.get_slice(len + 1, len + 1), None);
822 }
823
824 #[test]
825 fn test_memory_mapped_file_clone_and_share() {
826 use std::sync::Arc;
827 use std::thread;
828
829 let mut temp_file = NamedTempFile::new().unwrap();
830 let test_data = b"Shared mmap test data";
831 temp_file.write_all(test_data).unwrap();
832 temp_file.flush().unwrap();
833
834 let mmap = Arc::new(MemoryMappedFile::new(temp_file.path()).unwrap());
835 let mmap_clone = mmap.clone();
836
837 let handle = thread::spawn(move || {
838 assert_eq!(mmap_clone.len(), test_data.len());
839 assert_eq!(&mmap_clone[..5], b"Share");
840 });
841
842 handle.join().unwrap();
843
844 assert_eq!(&mmap[..], test_data);
846 }
847
848 #[test]
849 fn test_mapped_reader_position_consistency() {
850 let mut temp_file = NamedTempFile::new().unwrap();
851 let test_data = b"Position consistency test";
852 temp_file.write_all(test_data).unwrap();
853 temp_file.flush().unwrap();
854
855 let mut reader = MappedReader::new(temp_file.path()).unwrap();
856
857 assert_eq!(reader.position, 0);
858
859 let mut buf = [0u8; 8];
861 let _bytes_read = reader.read(&mut buf).unwrap();
862 assert_eq!(reader.position, 8);
863
864 reader.seek(SeekFrom::Start(5)).unwrap();
866 assert_eq!(reader.position, 5);
867
868 let _bytes_read = reader.read(&mut buf).unwrap();
870 assert_eq!(reader.position, 13);
871
872 reader.seek(SeekFrom::Current(-3)).unwrap();
874 assert_eq!(reader.position, 10);
875 }
876}