//! Executor engine implementation for Brainfuck interpreter. //! //! This predominantly allows implementation of a [`u16`] executor. #[cfg(feature = "bigint-engine")] use std::io::Cursor; use std::io::Read; #[cfg(feature = "bigint-engine")] use byteorder::{BigEndian, ReadBytesExt}; use num_traits::{One, Unsigned, WrappingAdd, WrappingSub, Zero}; use thiserror::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 { /// Inner type of the Tape. type TapeInner: Clone + Copy + Unsigned + WrappingAdd + WrappingSub + One + Zero; /// Read one byte from stdin. /// /// # Errors /// /// This function will return an error if it is unable to read from stdin, /// or if it indexes out of bounds. fn read_byte() -> Result; /// Write the provided byte to stdout. /// /// # Errors /// /// This function will return an error if it is unable to write a byte to /// stdout. fn write_byte(byte: Self::TapeInner) -> Result<(), Error>; } impl Engine for executor::U8 { type TapeInner = u8; fn read_byte() -> Result { let mut input: [u8; 1] = [0; 1]; std::io::stdin().read_exact(&mut input)?; Ok(input[0]) } fn write_byte(byte: u8) -> Result<(), Error> { print!("{}", char::from(byte)); Ok(()) } } #[cfg(feature = "engine-u16")] impl Engine for executor::U16 { type TapeInner = u16; fn read_byte() -> Result { let mut input: [u8; 2] = [0; 2]; std::io::stdin().read_exact(&mut input)?; let mut reader = Cursor::new(input); Ok(reader.read_u16::()?) } fn write_byte(byte: u16) -> Result<(), Error> { print!( "{}", widestring::Utf16Str::from_slice(&[byte]).map_err(|_err| Error::Utf16)? ); Ok(()) } } #[cfg(feature = "engine-u32")] impl Engine for executor::U32 { type TapeInner = u32; fn read_byte() -> Result { let mut input: [u8; 4] = [0; 4]; std::io::stdin().read_exact(&mut input)?; let mut reader = Cursor::new(input); Ok(reader.read_u32::()?) } fn write_byte(byte: u32) -> Result<(), Error> { print!( "{}", widestring::Utf32Str::from_slice(&[byte]).map_err(|_err| Error::Utf32)? ); Ok(()) } }