shared_file/
lib.rs

1use std::fs::File;
2use std::io::{self, Seek};
3use std::io::{prelude::*, SeekFrom};
4use std::os::unix::fs::FileExt;
5use std::sync::Arc;
6
7#[derive(Clone)]
8pub struct SharedFile {
9    cur_pos: u64,
10    file: Arc<File>,
11}
12
13impl SharedFile {
14    pub fn new(mut file: File) -> io::Result<Self> {
15        Ok(Self {
16            cur_pos: file.stream_position()?,
17            file: Arc::new(file),
18        })
19    }
20
21    pub fn len(&self) -> io::Result<u64> {
22        Ok(self.file.metadata()?.len())
23    }
24
25    pub fn is_empty(&self) -> io::Result<bool> {
26        self.len().map(|l| l == 0)
27    }
28}
29
30impl Read for SharedFile {
31    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
32        let readed = self.file.read_at(buf, self.cur_pos)?;
33
34        self.cur_pos += readed as u64;
35
36        Ok(readed)
37    }
38}
39
40impl Write for SharedFile {
41    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
42        let writed = self.file.write_at(buf, self.cur_pos)?;
43
44        self.cur_pos += writed as u64;
45
46        Ok(writed)
47    }
48
49    fn flush(&mut self) -> io::Result<()> {
50        self.file.flush()
51    }
52}
53
54impl Seek for SharedFile {
55    fn seek(&mut self, pos: SeekFrom) -> io::Result<u64> {
56        let file_len = self.len()?;
57
58        let new_pos = match pos {
59            SeekFrom::Start(offset) => offset,
60            SeekFrom::End(offset) => (file_len as i64 - offset) as u64,
61            SeekFrom::Current(offset) => (self.cur_pos as i64 + offset) as u64,
62        };
63
64        if new_pos > file_len {
65            return Err(io::Error::new(
66                io::ErrorKind::InvalidInput,
67                "seek position out of bounds",
68            ));
69        }
70
71        self.cur_pos = new_pos;
72
73        Ok(new_pos)
74    }
75}