#![allow(clippy::await_holding_refcell_ref)]
#![allow(clippy::collapsible_else_if)]
#![warn(anonymous_parameters, bad_style, missing_docs)]
#![warn(unused, unused_extern_crates, unused_import_braces, unused_qualifications)]
#![warn(unsafe_code)]
use async_channel::{Receiver, Sender};
use endbasic_core::exec::{Machine, Result, Signal, YieldNowFn};
use std::cell::RefCell;
use std::rc::Rc;
pub mod arrays;
pub mod console;
pub mod data;
pub mod exec;
pub mod gfx;
pub mod gpio;
pub mod help;
pub mod numerics;
pub mod program;
pub mod storage;
pub mod strings;
pub mod testutils;
#[derive(Default)]
pub struct MachineBuilder {
console: Option<Rc<RefCell<dyn console::Console>>>,
gpio_pins: Option<Rc<RefCell<dyn gpio::Pins>>>,
sleep_fn: Option<exec::SleepFn>,
yield_now_fn: Option<YieldNowFn>,
signals_chan: Option<(Sender<Signal>, Receiver<Signal>)>,
}
impl MachineBuilder {
pub fn with_console(mut self, console: Rc<RefCell<dyn console::Console>>) -> Self {
self.console = Some(console);
self
}
pub fn with_gpio_pins(mut self, pins: Rc<RefCell<dyn gpio::Pins>>) -> Self {
self.gpio_pins = Some(pins);
self
}
pub fn with_sleep_fn(mut self, sleep_fn: exec::SleepFn) -> Self {
self.sleep_fn = Some(sleep_fn);
self
}
pub fn with_yield_now_fn(mut self, yield_now_fn: YieldNowFn) -> Self {
self.yield_now_fn = Some(yield_now_fn);
self
}
pub fn with_signals_chan(mut self, chan: (Sender<Signal>, Receiver<Signal>)) -> Self {
self.signals_chan = Some(chan);
self
}
pub fn get_console(&mut self) -> Rc<RefCell<dyn console::Console>> {
if self.console.is_none() {
self.console = Some(Rc::from(RefCell::from(console::TrivialConsole::default())));
}
self.console.clone().unwrap()
}
fn get_gpio_pins(&mut self) -> Rc<RefCell<dyn gpio::Pins>> {
if self.gpio_pins.is_none() {
self.gpio_pins = Some(Rc::from(RefCell::from(gpio::NoopPins::default())))
}
self.gpio_pins.as_ref().expect("Must have been initialized above").clone()
}
pub fn build(mut self) -> Result<Machine> {
let console = self.get_console();
let gpio_pins = self.get_gpio_pins();
let signals_chan = match self.signals_chan {
Some(pair) => pair,
None => async_channel::unbounded(),
};
let mut machine =
Machine::with_signals_chan_and_yield_now_fn(signals_chan, self.yield_now_fn);
arrays::add_all(&mut machine);
console::add_all(&mut machine, console.clone());
data::add_all(&mut machine);
gfx::add_all(&mut machine, console);
gpio::add_all(&mut machine, gpio_pins);
exec::add_all(&mut machine, self.sleep_fn);
numerics::add_all(&mut machine);
strings::add_all(&mut machine);
Ok(machine)
}
pub fn make_interactive(self) -> InteractiveMachineBuilder {
InteractiveMachineBuilder::from(self)
}
}
pub struct InteractiveMachineBuilder {
builder: MachineBuilder,
program: Option<Rc<RefCell<dyn program::Program>>>,
storage: Rc<RefCell<storage::Storage>>,
}
impl InteractiveMachineBuilder {
fn from(builder: MachineBuilder) -> Self {
let storage = Rc::from(RefCell::from(storage::Storage::default()));
InteractiveMachineBuilder { builder, program: None, storage }
}
pub fn get_console(&mut self) -> Rc<RefCell<dyn console::Console>> {
self.builder.get_console()
}
pub fn get_program(&mut self) -> Rc<RefCell<dyn program::Program>> {
if self.program.is_none() {
self.program = Some(Rc::from(RefCell::from(program::ImmutableProgram::default())));
}
self.program.clone().unwrap()
}
pub fn get_storage(&mut self) -> Rc<RefCell<storage::Storage>> {
self.storage.clone()
}
pub fn with_program(mut self, program: Rc<RefCell<dyn program::Program>>) -> Self {
self.program = Some(program);
self
}
pub fn build(mut self) -> Result<Machine> {
let console = self.builder.get_console();
let program = self.get_program();
let storage = self.get_storage();
let mut machine = self.builder.build()?;
help::add_all(&mut machine, console.clone());
program::add_all(&mut machine, program, console.clone(), storage.clone());
storage::add_all(&mut machine, console, storage);
Ok(machine)
}
}