1use std::fmt;
4use std::hash::{Hash, Hasher};
5use std::io;
6use std::sync::Arc;
7
8#[cfg(all(target_pointer_width = "64", any(unix, windows)))]
9use crate::runtime_support::native_record_arena::ArenaMapping;
10
11use super::file::RecordFile;
12use super::metadata::{RecordMetadata, trusted_data_offset, trusted_head_data_offset};
13use super::validator::{RecordError, RecordValidator, ValidatedHeader};
14use crate::hash::{RecordHash, RecordKind};
15use crate::util::MAX_RECORD_METADATA_BYTES;
16
17const FIRST_PREFIX_READ: usize = 1024;
20
21#[derive(Clone)]
23enum RecordSource {
24 Memory(Arc<[u8]>),
25 #[cfg(all(target_pointer_width = "64", any(unix, windows)))]
28 Mmap {
29 mmap: Arc<ArenaMapping>,
30 offset: usize,
31 len: usize,
32 },
33 File {
36 file: Arc<RecordFile>,
37 offset: u64,
38 len: usize,
39 prefix: Arc<[u8]>,
40 },
41}
42
43impl RecordSource {
44 fn contiguous(&self) -> Option<&[u8]> {
45 Some(match self {
46 Self::Memory(bytes) => bytes,
47 #[cfg(all(target_pointer_width = "64", any(unix, windows)))]
48 Self::Mmap { mmap, offset, len } => {
49 unsafe { std::slice::from_raw_parts(mmap.as_ptr().add(*offset), *len) }
55 }
56 Self::File { .. } => return None,
57 })
58 }
59}
60
61#[derive(Clone)]
68pub struct Record {
69 source: RecordSource,
70 data_offset: usize,
71}
72
73impl fmt::Debug for Record {
74 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
75 formatter
76 .debug_struct("Record")
77 .field("hash", &self.hash())
78 .field("canonical_len", &self.canonical_len())
79 .finish()
80 }
81}
82
83impl PartialEq for Record {
84 fn eq(&self, other: &Self) -> bool {
85 self.hash() == other.hash()
86 }
87}
88impl Eq for Record {}
89impl Hash for Record {
90 fn hash<H: Hasher>(&self, state: &mut H) {
91 self.hash().hash(state);
92 }
93}
94
95#[derive(Debug)]
97pub enum RecordReadError {
98 TooLarge { length: usize, limit: usize },
100 Io(io::Error),
102}
103
104impl fmt::Display for RecordReadError {
105 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
106 match self {
107 Self::TooLarge { length, limit } => {
108 write!(
109 formatter,
110 "record bytes ({length}) exceed the limit ({limit})"
111 )
112 }
113 Self::Io(error) => write!(formatter, "record bytes could not be read: {error}"),
114 }
115 }
116}
117
118impl std::error::Error for RecordReadError {
119 fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
120 match self {
121 Self::TooLarge { .. } => None,
122 Self::Io(error) => Some(error),
123 }
124 }
125}
126
127impl Record {
128 pub(super) fn from_constructed(bytes: Vec<u8>, data_offset: usize) -> Self {
129 Self {
130 source: RecordSource::Memory(Arc::from(bytes)),
131 data_offset,
132 }
133 }
134
135 pub(crate) fn from_validated(bytes: Arc<[u8]>, header: &ValidatedHeader) -> Self {
138 debug_assert_eq!(bytes.len(), header.canonical_len());
139 Self {
140 data_offset: header.prefix().len(),
141 source: RecordSource::Memory(bytes),
142 }
143 }
144
145 pub(crate) fn from_validated_file(
148 file: Arc<RecordFile>,
149 offset: u64,
150 header: &ValidatedHeader,
151 ) -> Self {
152 Self {
153 data_offset: header.prefix().len(),
154 source: RecordSource::File {
155 file,
156 offset,
157 len: header.canonical_len(),
158 prefix: Arc::from(header.prefix()),
159 },
160 }
161 }
162
163 pub fn from_bytes(bytes: impl Into<Vec<u8>>) -> Result<Self, RecordError> {
165 let bytes = bytes.into();
166 let mut validator = RecordValidator::new();
167 if validator.feed(&bytes)? != bytes.len() {
168 return Err(RecordError::InvalidFormat(
169 "trailing bytes after a complete record".into(),
170 ));
171 }
172 let header = validator.finish()?;
173 Ok(Self {
174 data_offset: header.prefix().len(),
175 source: RecordSource::Memory(Arc::from(bytes)),
176 })
177 }
178
179 #[doc(hidden)]
183 pub unsafe fn try_from_trusted_record_bytes(
184 bytes: impl Into<Vec<u8>>,
185 ) -> Result<Self, RecordError> {
186 let bytes = bytes.into();
187 Ok(Self {
188 data_offset: trusted_data_offset(&bytes)?,
189 source: RecordSource::Memory(Arc::from(bytes)),
190 })
191 }
192
193 pub(crate) unsafe fn try_from_trusted_file(
202 file: Arc<RecordFile>,
203 offset: u64,
204 len: usize,
205 ) -> io::Result<Self> {
206 let invalid = |error: RecordError| io::Error::new(io::ErrorKind::InvalidData, error);
207 let mut head = vec![0; len.min(FIRST_PREFIX_READ)];
208 file.read_exact_at(&mut head, offset)?;
209 let data_offset = match trusted_head_data_offset(&head, len).map_err(invalid)? {
210 Some(data_offset) => data_offset,
211 None => {
212 head.resize(len.min(MAX_RECORD_METADATA_BYTES), 0);
213 file.read_exact_at(
214 &mut head[FIRST_PREFIX_READ..],
215 offset + FIRST_PREFIX_READ as u64,
216 )?;
217 trusted_head_data_offset(&head, len)
218 .map_err(invalid)?
219 .ok_or_else(|| invalid(RecordError::InvalidFormat("no record prefix".into())))?
220 }
221 };
222 head.truncate(data_offset);
223 Ok(Self {
224 data_offset,
225 source: RecordSource::File {
226 file,
227 offset,
228 len,
229 prefix: Arc::from(head),
230 },
231 })
232 }
233
234 #[cfg(all(target_pointer_width = "64", any(unix, windows)))]
240 pub(crate) unsafe fn try_from_trusted_raw_mmap_record_bytes(
241 mmap: Arc<ArenaMapping>,
242 offset: usize,
243 len: usize,
244 ) -> Result<Self, RecordError> {
245 let end = offset.checked_add(len).ok_or_else(|| {
246 RecordError::InvalidFormat("mapped record byte range overflow".into())
247 })?;
248 if end > mmap.len() {
249 return Err(RecordError::InvalidFormat(
250 "mapped record byte range exceeds mapping".into(),
251 ));
252 }
253 let source = RecordSource::Mmap { mmap, offset, len };
254 Ok(Self {
255 data_offset: trusted_data_offset(source.contiguous().expect("mapped bytes"))?,
256 source,
257 })
258 }
259
260 pub fn hash(&self) -> RecordHash {
261 self.metadata().hash()
262 }
263
264 pub fn kind(&self) -> RecordKind {
265 self.hash().kind()
266 }
267
268 pub fn canonical_len(&self) -> usize {
270 match &self.source {
271 RecordSource::Memory(bytes) => bytes.len(),
272 #[cfg(all(target_pointer_width = "64", any(unix, windows)))]
273 RecordSource::Mmap { len, .. } => *len,
274 RecordSource::File { len, .. } => *len,
275 }
276 }
277
278 pub fn metadata(&self) -> RecordMetadata<'_> {
280 let prefix = match &self.source {
281 RecordSource::File { prefix, .. } => prefix,
282 source => &source.contiguous().expect("contiguous source")[..self.data_offset],
283 };
284 RecordMetadata::new_trusted(prefix)
285 }
286
287 pub fn contiguous_bytes(&self) -> Option<&[u8]> {
290 self.source.contiguous()
291 }
292
293 pub fn contiguous_data(&self) -> Option<&[u8]> {
295 Some(&self.source.contiguous()?[self.data_offset..])
296 }
297
298 pub fn read_at(&self, offset: usize, buffer: &mut [u8]) -> io::Result<usize> {
302 let len = self.canonical_len();
303 if offset > len {
304 return Err(io::Error::new(
305 io::ErrorKind::InvalidInput,
306 "read offset is beyond the record",
307 ));
308 }
309 let count = (len - offset).min(buffer.len());
310 match &self.source {
311 RecordSource::File {
312 file,
313 offset: start,
314 ..
315 } => file.read_exact_at(&mut buffer[..count], start + offset as u64)?,
316 source => {
317 let bytes = source.contiguous().expect("contiguous source");
318 buffer[..count].copy_from_slice(&bytes[offset..offset + count]);
319 }
320 }
321 Ok(count)
322 }
323
324 pub fn to_vec(&self, limit: usize) -> Result<Vec<u8>, RecordReadError> {
326 self.read_range_to_vec(0, limit)
327 }
328
329 pub fn data_to_vec(&self, limit: usize) -> Result<Vec<u8>, RecordReadError> {
331 self.read_range_to_vec(self.data_offset, limit)
332 }
333
334 fn read_range_to_vec(&self, start: usize, limit: usize) -> Result<Vec<u8>, RecordReadError> {
335 let length = self.canonical_len() - start;
336 if length > limit {
337 return Err(RecordReadError::TooLarge { length, limit });
338 }
339 let mut bytes = vec![0; length];
340 self.read_at(start, &mut bytes)
341 .map_err(RecordReadError::Io)?;
342 Ok(bytes)
343 }
344}