use anyhow::Result;
use crate::{
vm_reader::VMReader,
Program,
VirtualMachine,
};
#[derive(Default)]
#[allow(clippy::module_name_repetitions)]
pub struct VirtualMachineBuilder<R>
where
R: VMReader,
{
program: Option<Program>,
tape_size: Option<usize>,
input_device: Option<R>,
}
impl<R> VirtualMachineBuilder<R>
where
R: VMReader,
{
#[must_use]
pub const fn new() -> Self {
Self {
program: None,
tape_size: None,
input_device: None,
}
}
#[must_use]
pub fn program(mut self, program: Program) -> Self {
self.program = Some(program);
self
}
#[must_use]
pub const fn tape_size(mut self, tape_size: usize) -> Self {
self.tape_size = Some(tape_size);
self
}
#[must_use]
pub fn input_device(mut self, input_device: R) -> Self {
self.input_device = Some(input_device);
self
}
pub fn build(self) -> Result<VirtualMachine<R>> {
let program = self.program.unwrap_or_default();
let tape_size = self.tape_size.unwrap_or(30000);
let Some(input_device) = self.input_device else {
return Err(anyhow::anyhow!("Input device not set."));
};
Ok(VirtualMachine::new(tape_size, program, 0, 0, input_device))
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::vm_reader::{
MockReader,
VMReaderType,
};
#[test]
fn test_program() {
let program = Program::from("++++++[>++++++++++<-]>+++++.");
let input_device = MockReader {
data: std::io::Cursor::new("A".as_bytes().to_vec()),
};
let vm = VirtualMachine::builder()
.input_device(input_device)
.program(program)
.build()
.unwrap();
assert_eq!(vm.program(), Program::from("++++++[>++++++++++<-]>+++++."));
}
#[test]
fn test_tape_size() {
let input_device = MockReader {
data: std::io::Cursor::new("A".as_bytes().to_vec()),
};
let vm = VirtualMachine::builder()
.input_device(input_device)
.tape_size(100)
.build()
.unwrap();
assert_eq!(vm.tape_size(), 100);
}
#[test]
fn test_input_device() {
let input_device = MockReader {
data: std::io::Cursor::new("A".as_bytes().to_vec()),
};
let mut vm = VirtualMachine::builder()
.input_device(input_device)
.build()
.unwrap();
assert_eq!(vm.input_device().get_vmreader_type(), VMReaderType::Mock);
}
#[test]
fn test_build() {
let program = Program::from("++++++[>++++++++++<-]>+++++.");
let input_device = MockReader {
data: std::io::Cursor::new("A".as_bytes().to_vec()),
};
let vm = VirtualMachine::builder()
.input_device(input_device)
.tape_size(100)
.program(program)
.build()
.unwrap();
assert_eq!(vm.program(), Program::from("++++++[>++++++++++<-]>+++++."));
assert_eq!(vm.tape_size(), 100);
}
#[test]
fn test_default() {
let input_device = MockReader {
data: std::io::Cursor::new("A".as_bytes().to_vec()),
};
let vm = VirtualMachine::builder()
.input_device(input_device)
.build()
.unwrap();
assert_eq!(vm.program(), Program::default());
assert_eq!(vm.tape_size(), 30000);
}
}