1use std::fs::File;
4use std::path::Path;
5use std::sync::Arc;
6
7use memmap2::Mmap;
8
9use crate::error::{Error, Result};
10
11pub trait TiffSource: Send + Sync {
13 fn len(&self) -> u64;
15
16 fn is_empty(&self) -> bool {
18 self.len() == 0
19 }
20
21 fn read_exact_at(&self, offset: u64, len: usize) -> Result<Vec<u8>>;
23
24 fn as_slice(&self) -> Option<&[u8]> {
26 None
27 }
28}
29
30pub type SharedSource = Arc<dyn TiffSource>;
32
33pub struct MmapSource {
35 mmap: Mmap,
36}
37
38impl MmapSource {
39 pub fn open(path: &Path) -> Result<Self> {
40 let file = File::open(path).map_err(|e| Error::Io(e, path.display().to_string()))?;
41 let mmap =
42 unsafe { Mmap::map(&file) }.map_err(|e| Error::Io(e, path.display().to_string()))?;
43 Ok(Self { mmap })
44 }
45}
46
47impl TiffSource for MmapSource {
48 fn len(&self) -> u64 {
49 self.mmap.len() as u64
50 }
51
52 fn read_exact_at(&self, offset: u64, len: usize) -> Result<Vec<u8>> {
53 let start = usize::try_from(offset).map_err(|_| Error::OffsetOutOfBounds {
54 offset,
55 length: len as u64,
56 data_len: self.len(),
57 })?;
58 let end = start.checked_add(len).ok_or(Error::OffsetOutOfBounds {
59 offset,
60 length: len as u64,
61 data_len: self.len(),
62 })?;
63 if end > self.mmap.len() {
64 return Err(Error::OffsetOutOfBounds {
65 offset,
66 length: len as u64,
67 data_len: self.len(),
68 });
69 }
70 Ok(self.mmap[start..end].to_vec())
71 }
72
73 fn as_slice(&self) -> Option<&[u8]> {
74 Some(&self.mmap)
75 }
76}
77
78pub struct BytesSource {
80 bytes: Vec<u8>,
81}
82
83impl BytesSource {
84 pub fn new(bytes: Vec<u8>) -> Self {
85 Self { bytes }
86 }
87}
88
89impl TiffSource for BytesSource {
90 fn len(&self) -> u64 {
91 self.bytes.len() as u64
92 }
93
94 fn read_exact_at(&self, offset: u64, len: usize) -> Result<Vec<u8>> {
95 let start = usize::try_from(offset).map_err(|_| Error::OffsetOutOfBounds {
96 offset,
97 length: len as u64,
98 data_len: self.len(),
99 })?;
100 let end = start.checked_add(len).ok_or(Error::OffsetOutOfBounds {
101 offset,
102 length: len as u64,
103 data_len: self.len(),
104 })?;
105 if end > self.bytes.len() {
106 return Err(Error::OffsetOutOfBounds {
107 offset,
108 length: len as u64,
109 data_len: self.len(),
110 });
111 }
112 Ok(self.bytes[start..end].to_vec())
113 }
114
115 fn as_slice(&self) -> Option<&[u8]> {
116 Some(&self.bytes)
117 }
118}