1use super::Blob;
7use async_trait::async_trait;
8use inspect::Inspect;
9use std::fs::File;
10use std::io;
11use std::sync::Arc;
12
13#[derive(Debug, Inspect)]
15pub struct FileBlob {
16 file: Arc<File>,
17 len: u64,
18}
19
20impl FileBlob {
21 pub fn new(file: File) -> io::Result<Self> {
23 let len = file.metadata()?.len();
24 Ok(Self {
25 file: Arc::new(file),
26 len,
27 })
28 }
29}
30
31#[async_trait]
32impl Blob for FileBlob {
33 async fn read(&self, buf: &mut [u8], offset: u64) -> io::Result<()> {
34 let file = self.file.clone();
35 let len = buf.len();
36 let data = blocking::unblock(move || {
37 let mut data = vec![0; len];
38 let n = file.read_at(&mut data, offset)?;
39 if n < data.len() {
40 return Err(io::ErrorKind::UnexpectedEof.into());
41 }
42 io::Result::Ok(data)
43 })
44 .await?;
45 buf.copy_from_slice(&data);
46 Ok(())
47 }
48
49 fn len(&self) -> u64 {
50 self.len
51 }
52}
53
54trait ReadAt {
61 fn read_at(&self, buf: &mut [u8], offset: u64) -> io::Result<usize>;
62}
63
64#[cfg(windows)]
65impl ReadAt for File {
66 fn read_at(&self, buf: &mut [u8], offset: u64) -> io::Result<usize> {
67 std::os::windows::fs::FileExt::seek_read(self, buf, offset)
68 }
69}
70
71#[cfg(unix)]
72impl ReadAt for File {
73 fn read_at(&self, buf: &mut [u8], offset: u64) -> io::Result<usize> {
74 std::os::unix::fs::FileExt::read_at(self, buf, offset)
75 }
76}