use std::fs::File; use std::io::{BufReader, BufWriter}; use std::io::{Read, Write}; use std::io::{ErrorKind, Seek, SeekFrom}; use crate::*; 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, _ => { 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), Write(BufWriter), 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 } }