summaryrefslogtreecommitdiff
path: root/src/devices/file_device/buffered_file.rs
diff options
context:
space:
mode:
authorBen Bridle <bridle.benjamin@gmail.com>2024-10-28 20:25:01 +1300
committerBen Bridle <bridle.benjamin@gmail.com>2024-10-28 20:29:12 +1300
commit1a830a3d1b9d99653322d5ae49ea8165de7ed9d0 (patch)
tree798e77b6fcf2438b1c2538a67efe856a2f7cb979 /src/devices/file_device/buffered_file.rs
parent03c4b069e1806af256730639cefdae115b24401a (diff)
downloadbedrock-pc-1a830a3d1b9d99653322d5ae49ea8165de7ed9d0.zip
Rewrite emulatorv1.0.0-alpha1
This is a complete rewrite and restructure of the entire emulator project, as part of the effort in locking down the Bedrock specification and in creating much better tooling for creating and using Bedrock programs. This commit adds a command-line argument scheme, an embedded assembler, a headless emulator for use in non-graphical environments, deferred window creation for programs that do not access the screen device, and new versions of phosphor and bedrock-core. The new version of phosphor supports multi-window programs, which will make it possible to implement program forking in the system device later on, and the new version of bedrock-core implements the final core specification.
Diffstat (limited to 'src/devices/file_device/buffered_file.rs')
-rw-r--r--src/devices/file_device/buffered_file.rs146
1 files changed, 146 insertions, 0 deletions
diff --git a/src/devices/file_device/buffered_file.rs b/src/devices/file_device/buffered_file.rs
new file mode 100644
index 0000000..3487d54
--- /dev/null
+++ b/src/devices/file_device/buffered_file.rs
@@ -0,0 +1,146 @@
+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 {
+ writer.flush().unwrap();
+ }
+ }
+}
+
+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
+ }
+}