#[derive(Clone)] struct CloneableFile { file: Arc<Mutex<File>>, pos: u64, // TODO determine and store this once instead of per cloneable file file_length: Option<u64>, }
impl CloneableFile { fn new(file: File) -> Self { Self { file: Arc::new(Mutex::new(file)), pos: 0u64, file_length: None, } } }
impl CloneableFile { fn ascertain_file_length(&mut self) -> u64 { match self.file_length { Some(file_length) => file_length, None => { let len = self.file.lock().unwrap().metadata().unwrap().len(); self.file_length = Some(len); len } } } }
impl Read for CloneableFile { fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize> { let mut underlying_file = self.file.lock().expect("Unable to get underlying file"); // TODO share an object which knows current position to avoid unnecessary // seeks underlying_file.seek(SeekFrom::Start(self.pos))?; let read_result = underlying_file.read(buf); if let Ok(bytes_read) = read_result { // TODO, once stabilised, use checked_add_signed self.pos += bytes_read as u64; } read_result } }
impl Seek for CloneableFile { fn seek(&mut self, pos: SeekFrom) -> std::io::Result<u64> { let new_pos = match pos { SeekFrom::Start(pos) => pos, SeekFrom::End(offset_from_end) => { let file_len = self.ascertain_file_length(); // TODO, once stabilised, use checked_add_signed file_len - (-offset_from_end as u64) } // TODO, once stabilised, use checked_add_signed SeekFrom::Current(offset_from_pos) => { if offset_from_pos == 0 { self.pos } else if offset_from_pos > 0 { self.pos + (offset_from_pos as u64) } else { self.pos - ((-offset_from_pos) as u64) } } }; self.pos = new_pos; Ok(new_pos) } }
|