diff options
Diffstat (limited to 'src/types/buffered_file.rs')
-rw-r--r-- | src/types/buffered_file.rs | 143 |
1 files changed, 143 insertions, 0 deletions
diff --git a/src/types/buffered_file.rs b/src/types/buffered_file.rs new file mode 100644 index 0000000..5cdf0ea --- /dev/null +++ b/src/types/buffered_file.rs @@ -0,0 +1,143 @@ +use std::fs::File; +use std::io::{BufReader, BufWriter, Read, Write}; +use std::io::{ErrorKind, Seek, SeekFrom}; + + +pub struct BufferedFile { + file: AccessMode, +} + +impl BufferedFile { + pub fn new(file: File) -> Self { + Self { + file: AccessMode::Read(BufReader::new(file)), + } + } + + pub fn close(&mut self) { + self.file = AccessMode::None; + } + + pub fn read(&mut self) -> u8 { + let mut buffer = [0u8; 1]; + + let read_result = match &mut self.file { + AccessMode::Read(reader) => reader.read_exact(&mut buffer), + AccessMode::Write(writer) => { + let address = writer.stream_position().unwrap(); + let file = std::mem::take(&mut self.file).unwrap(); + let mut reader = BufReader::new(file); + reader.seek(SeekFrom::Start(address)).unwrap(); + let read_result = reader.read_exact(&mut buffer); + self.file = AccessMode::Read(reader); + read_result + } + AccessMode::None => unreachable!(), + }; + + match read_result { + Ok(_) => buffer[0], + Err(error) => match error.kind() { + ErrorKind::UnexpectedEof => 0, + _ => { log::error!("BufferedFile::read: {error:?}"); 0 }, + } + } + } + + pub fn write(&mut self, byte: u8) { + let mut buffer = [byte; 1]; + + let write_result = match &mut self.file { + AccessMode::Write(writer) => writer.write_all(&mut buffer), + AccessMode::Read(reader) => { + let address = reader.stream_position().unwrap(); + let file = std::mem::take(&mut self.file).unwrap(); + let mut writer = BufWriter::new(file); + writer.seek(SeekFrom::Start(address)).unwrap(); + let write_result = writer.write_all(&mut buffer); + self.file = AccessMode::Write(writer); + write_result + } + AccessMode::None => unreachable!(), + }; + + write_result.unwrap(); + } + + pub fn pointer(&mut self) -> u32 { + let position = match &mut self.file { + AccessMode::Read(reader) => reader.stream_position(), + AccessMode::Write(writer) => writer.stream_position(), + AccessMode::None => unreachable!(), + }; + u32::try_from(position.unwrap()).unwrap_or(u32::MAX) + } + + pub fn set_pointer(&mut self, pointer: u32) { + let position = SeekFrom::Start(pointer as u64); + match &mut self.file { + AccessMode::Read(reader) => reader.seek(position).unwrap(), + AccessMode::Write(writer) => writer.seek(position).unwrap(), + AccessMode::None => unreachable!(), + }; + } + + pub fn length(&mut self) -> u32 { + let length = match &mut self.file { + AccessMode::Read(reader) => reader.stream_len(), + AccessMode::Write(writer) => writer.stream_len(), + AccessMode::None => unreachable!(), + }; + u32::try_from(length.unwrap()).unwrap_or(u32::MAX) + } + + pub fn set_length(&mut self, length: u32) { + match &mut self.file { + AccessMode::Read(_) => { + let file = std::mem::take(&mut self.file).unwrap(); + file.set_len(length as u64).unwrap(); + self.file = AccessMode::Read(BufReader::new(file)); + } + AccessMode::Write(_) => { + let file = std::mem::take(&mut self.file).unwrap(); + file.set_len(length as u64).unwrap(); + self.file = AccessMode::Read(BufReader::new(file)); + } + AccessMode::None => unreachable!(), + }; + } + + pub fn flush(&mut self) { + if let AccessMode::Write(writer) = &mut self.file { + let _ = writer.flush(); + } + } +} + +impl Drop for BufferedFile { + fn drop(&mut self) { + self.flush() + } +} + +enum AccessMode { + Read(BufReader<File>), + Write(BufWriter<File>), + None, +} + +impl AccessMode { + pub fn unwrap(self) -> File { + match self { + Self::Read(reader) => reader.into_inner(), + Self::Write(writer) => writer.into_inner().unwrap(), + Self::None => unreachable!(), + } + } +} + +impl Default for AccessMode { + fn default() -> Self { + Self::None + } +} |