summary refs log tree commit diff
diff options
context:
space:
mode:
authorSophie Forrest <git@sophieforrest.com>2024-08-30 23:35:45 +1200
committerSophie Forrest <git@sophieforrest.com>2024-08-30 23:35:45 +1200
commit13b95941183666fadd090314e4e9af33283084cd (patch)
tree2831968068a77b7a37a37d1356e9673d4dcc3275
parentf5f789540ad7d3f7f4f855c9db69d65cfc190ee0 (diff)
feat(engine)!: implement u32 engine
-rw-r--r--Cargo.lock14
-rw-r--r--Cargo.toml7
-rw-r--r--src/engine.rs54
-rw-r--r--src/executor.rs12
-rw-r--r--src/lib.rs1
-rw-r--r--src/main.rs1
-rw-r--r--src/utility.rs5
7 files changed, 78 insertions, 16 deletions
diff --git a/Cargo.lock b/Cargo.lock
index 0be8c23..d4c6389 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -106,14 +106,22 @@ checksum = "630be753d4e58660abd17930c71b647fe46c27ea6b63cc59e1e3851406972e42"
 name = "brainf_rs"
 version = "0.1.0"
 dependencies = [
+ "byteorder",
  "clap",
  "fs-err",
  "miette",
  "num-traits",
  "thiserror",
+ "widestring",
 ]
 
 [[package]]
+name = "byteorder"
+version = "1.4.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610"
+
+[[package]]
 name = "cc"
 version = "1.0.82"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -480,6 +488,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a"
 
 [[package]]
+name = "widestring"
+version = "1.0.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "653f141f39ec16bba3c5abe400a0c60da7468261cc2cbf36805022876bc721a8"
+
+[[package]]
 name = "winapi"
 version = "0.3.9"
 source = "registry+https://github.com/rust-lang/crates.io-index"
diff --git a/Cargo.toml b/Cargo.toml
index eca44e9..b3403d7 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -5,12 +5,17 @@ edition = "2021"
 resolver = "2"
 
 [dependencies]
+byteorder = { optional = true, version = "1.4.3" }
 clap = { features = ["derive"], version = "4.3.21" }
 num-traits = "0.2.16"
 fs-err = "2.9.0"
 miette = { features = ["fancy"], version = "5.10.0" }
 thiserror = "1.0.44"
+widestring = { default-features = false, optional = true, version = "1.0.2" }
 
 [features]
-default = ["utilities"]
+default = ["engine-u16", "engine-u32", "utilities"]
+bigint-engine = ["dep:byteorder", "dep:widestring"]
+engine-u16 = ["bigint-engine"]
+engine-u32 = ["bigint-engine"]
 utilities = []
diff --git a/src/engine.rs b/src/engine.rs
index 8cf2726..6c69bc1 100644
--- a/src/engine.rs
+++ b/src/engine.rs
@@ -2,11 +2,29 @@
 //!
 //! This predominantly allows implementation of a [`u16`] executor.
 
-use std::io::Read;
+use std::io::{Cursor, Read};
 
+use byteorder::{BigEndian, ReadBytesExt};
 use num_traits::{One, Unsigned, WrappingAdd, WrappingSub, Zero};
+use thiserror::Error;
 
-use crate::executor::{self, Error};
+use crate::executor;
+
+/// Error type for engine errors
+#[derive(Debug, Error)]
+pub enum Error {
+	/// Engine ran into an io Error
+	#[error(transparent)]
+	Io(#[from] std::io::Error),
+
+	/// Utf16 error from widestring
+	#[error("could not convert byte to Utf16Str")]
+	Utf16,
+
+	/// Utf32 error from widestring
+	#[error("could not convert byte to Utf32Str")]
+	Utf32,
+}
 
 /// Generic engine implementation for the Brainfuck interpreter.
 pub trait Engine {
@@ -56,13 +74,39 @@ impl Engine for executor::U16 {
 
 		std::io::stdin().read_exact(&mut input)?;
 
-		let number = ((u16::from(input[0])) << 8i32) | u16::from(input[1]);
+		let mut reader = Cursor::new(input);
 
-		Ok(number)
+		Ok(reader.read_u16::<BigEndian>()?)
 	}
 
 	fn write_byte(byte: u16) -> Result<(), Error> {
-		print!("{}", String::from_utf16_lossy(&[byte]));
+		print!(
+			"{}",
+			widestring::Utf16Str::from_slice(&[byte]).map_err(|_err| Error::Utf16)?
+		);
+
+		Ok(())
+	}
+}
+
+impl Engine for executor::U32 {
+	type TapeInner = u32;
+
+	fn read_byte() -> Result<u32, Error> {
+		let mut input: [u8; 4] = [0; 4];
+
+		std::io::stdin().read_exact(&mut input)?;
+
+		let mut reader = Cursor::new(input);
+
+		Ok(reader.read_u32::<BigEndian>()?)
+	}
+
+	fn write_byte(byte: u32) -> Result<(), Error> {
+		print!(
+			"{}",
+			widestring::Utf32Str::from_slice(&[byte]).map_err(|_err| Error::Utf32)?
+		);
 
 		Ok(())
 	}
diff --git a/src/executor.rs b/src/executor.rs
index eddf443..da7d676 100644
--- a/src/executor.rs
+++ b/src/executor.rs
@@ -9,14 +9,14 @@ use crate::{engine::Engine, parser::Instruction};
 /// Runtime errors that can occur in brainfuck executor.
 #[derive(Debug, Diagnostic, Error)]
 pub enum Error {
+	/// Brainfuck engine ran into an error at runtime.
+	#[error(transparent)]
+	Engine(#[from] crate::engine::Error),
+
 	/// Brainfuck code performed an out of bounds index on the tape during
 	/// runtime.
 	#[error("tape indexed out of bounds, attempted index at `{0}`")]
 	IndexOutOfBounds(usize),
-
-	/// Executor was unable to read an input byte from stdin.
-	#[error("could not read input from stdin")]
-	ReadInput(#[from] std::io::Error),
 }
 
 /// Struct for executor implementation, allows u8 Engine to be implemented.
@@ -27,6 +27,10 @@ pub struct U8;
 #[derive(Clone, Copy, Debug)]
 pub struct U16;
 
+/// Struct for executor implementation, allows u32 Engine to be implemented.
+#[derive(Clone, Copy, Debug)]
+pub struct U32;
+
 /// Executes the provided instruction set, utilising the provided tape..
 ///
 /// # Errors
diff --git a/src/lib.rs b/src/lib.rs
index b806b4c..2c40797 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -3,7 +3,6 @@
 #![feature(custom_inner_attributes)]
 #![feature(lint_reasons)]
 #![feature(never_type)]
-#![feature(once_cell)]
 #![feature(test)]
 #![deny(clippy::complexity)]
 #![deny(clippy::nursery)]
diff --git a/src/main.rs b/src/main.rs
index f5c4740..13868a6 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -3,7 +3,6 @@
 #![feature(custom_inner_attributes)]
 #![feature(lint_reasons)]
 #![feature(never_type)]
-#![feature(once_cell)]
 #![deny(clippy::complexity)]
 #![deny(clippy::nursery)]
 #![deny(clippy::pedantic)]
diff --git a/src/utility.rs b/src/utility.rs
index 4eba853..514343c 100644
--- a/src/utility.rs
+++ b/src/utility.rs
@@ -37,10 +37,7 @@ pub fn execute_from_file<E: Engine>(
 /// This function will return an error if parsing or
 /// execution fails. See documentation for [`crate::parser::parse`] and
 /// [`crate::executor::execute`].
-pub fn execute_from_str<E: Engine<TapeInner = u8>>(
-	input: &str,
-	tape: &mut [E::TapeInner],
-) -> Result<(), Error> {
+pub fn execute_from_str<E: Engine>(input: &str, tape: &mut [E::TapeInner]) -> Result<(), Error> {
 	let operator_codes = lex(input);
 
 	let instructions = parse(input, &operator_codes)?;