1pub trait ReadAt: Send + Sync + 'static {
3 fn read_at(&self, buf: &mut [u8], offset: u64) -> std::io::Result<usize>;
10
11 fn size(&self) -> std::io::Result<u64>;
13}
14
15#[cfg(windows)]
16impl ReadAt for std::fs::File {
17 fn read_at(&self, buf: &mut [u8], offset: u64) -> std::io::Result<usize> {
18 use std::os::windows::fs::FileExt;
19 self.seek_read(buf, offset)
20 }
21
22 fn size(&self) -> std::io::Result<u64> {
23 self.metadata().map(|m| m.len())
24 }
25}
26
27#[cfg(unix)]
28impl ReadAt for std::fs::File {
29 fn read_at(&self, buf: &mut [u8], offset: u64) -> std::io::Result<usize> {
30 use std::os::unix::fs::FileExt;
31 FileExt::read_at(self, buf, offset)
32 }
33
34 fn size(&self) -> std::io::Result<u64> {
35 self.metadata().map(|m| m.len())
36 }
37}
38
39impl ReadAt for Vec<u8> {
40 fn read_at(&self, buf: &mut [u8], offset: u64) -> std::io::Result<usize> {
41 let start = usize::try_from(offset).expect("offset must fit in usize");
42 let end = start.saturating_add(buf.len()).min(self.len());
43 let slice = &self[start..end];
44 buf[..slice.len()].copy_from_slice(slice);
45 Ok(slice.len())
46 }
47
48 fn size(&self) -> std::io::Result<u64> {
49 Ok(self.len().try_into().expect("length must fit in u64"))
50 }
51}
52
53#[cfg(test)]
54mod tests {
55 use super::*;
56
57 #[test]
58 fn read_at_vec_middle() {
59 let data = vec![1, 2, 3, 4, 5];
60 let mut buf = [0; 3];
61 assert_eq!(data.read_at(&mut buf, 1).unwrap(), 3);
62 assert_eq!(&buf, &[2, 3, 4]);
63 }
64
65 #[test]
66 fn read_at_vec_end() {
67 let data = vec![1, 2, 3, 4, 5];
68 let mut buf = [0; 3];
69 assert_eq!(data.read_at(&mut buf, 3).unwrap(), 2);
70 assert_eq!(&buf, &[4, 5, 0]);
71 }
72}