1#![allow(clippy::await_holding_refcell_ref)]
20#![allow(clippy::collapsible_else_if)]
21#![warn(anonymous_parameters, bad_style, missing_docs)]
22#![warn(unused, unused_extern_crates, unused_import_braces, unused_qualifications)]
23#![warn(unsafe_code)]
24
25use async_channel::{Receiver, Sender};
26use endbasic_core::exec::{Machine, Result, Signal, YieldNowFn};
27use std::cell::RefCell;
28use std::rc::Rc;
29
30pub mod arrays;
32pub mod console;
33pub mod data;
34pub mod exec;
35pub mod gfx;
36pub mod gpio;
37pub mod help;
38pub mod numerics;
39pub mod program;
40pub mod storage;
41pub mod strings;
42pub mod testutils;
43
44#[derive(Default)]
48pub struct MachineBuilder {
49 console: Option<Rc<RefCell<dyn console::Console>>>,
50 gpio_pins: Option<Rc<RefCell<dyn gpio::Pins>>>,
51 sleep_fn: Option<exec::SleepFn>,
52 yield_now_fn: Option<YieldNowFn>,
53 signals_chan: Option<(Sender<Signal>, Receiver<Signal>)>,
54}
55
56impl MachineBuilder {
57 pub fn with_console(mut self, console: Rc<RefCell<dyn console::Console>>) -> Self {
59 self.console = Some(console);
60 self
61 }
62
63 pub fn with_gpio_pins(mut self, pins: Rc<RefCell<dyn gpio::Pins>>) -> Self {
65 self.gpio_pins = Some(pins);
66 self
67 }
68
69 pub fn with_sleep_fn(mut self, sleep_fn: exec::SleepFn) -> Self {
71 self.sleep_fn = Some(sleep_fn);
72 self
73 }
74
75 pub fn with_yield_now_fn(mut self, yield_now_fn: YieldNowFn) -> Self {
77 self.yield_now_fn = Some(yield_now_fn);
78 self
79 }
80
81 pub fn with_signals_chan(mut self, chan: (Sender<Signal>, Receiver<Signal>)) -> Self {
83 self.signals_chan = Some(chan);
84 self
85 }
86
87 pub fn get_console(&mut self) -> Rc<RefCell<dyn console::Console>> {
89 if self.console.is_none() {
90 self.console = Some(Rc::from(RefCell::from(console::TrivialConsole::default())));
91 }
92 self.console.clone().unwrap()
93 }
94
95 fn get_gpio_pins(&mut self) -> Rc<RefCell<dyn gpio::Pins>> {
97 if self.gpio_pins.is_none() {
98 self.gpio_pins = Some(Rc::from(RefCell::from(gpio::NoopPins::default())))
99 }
100 self.gpio_pins.as_ref().expect("Must have been initialized above").clone()
101 }
102
103 pub fn build(mut self) -> Result<Machine> {
105 let console = self.get_console();
106 let gpio_pins = self.get_gpio_pins();
107
108 let signals_chan = match self.signals_chan {
109 Some(pair) => pair,
110 None => async_channel::unbounded(),
111 };
112
113 let mut machine =
114 Machine::with_signals_chan_and_yield_now_fn(signals_chan, self.yield_now_fn);
115 arrays::add_all(&mut machine);
116 console::add_all(&mut machine, console.clone());
117 data::add_all(&mut machine);
118 gfx::add_all(&mut machine, console);
119 gpio::add_all(&mut machine, gpio_pins);
120 exec::add_scripting(&mut machine, self.sleep_fn);
121 numerics::add_all(&mut machine);
122 strings::add_all(&mut machine);
123 Ok(machine)
124 }
125
126 pub fn make_interactive(self) -> InteractiveMachineBuilder {
128 InteractiveMachineBuilder::from(self)
129 }
130}
131
132pub struct InteractiveMachineBuilder {
139 builder: MachineBuilder,
140 program: Option<Rc<RefCell<dyn program::Program>>>,
141 storage: Rc<RefCell<storage::Storage>>,
142}
143
144impl InteractiveMachineBuilder {
145 fn from(builder: MachineBuilder) -> Self {
147 let storage = Rc::from(RefCell::from(storage::Storage::default()));
148 InteractiveMachineBuilder { builder, program: None, storage }
149 }
150
151 pub fn get_console(&mut self) -> Rc<RefCell<dyn console::Console>> {
153 self.builder.get_console()
154 }
155
156 pub fn get_program(&mut self) -> Rc<RefCell<dyn program::Program>> {
158 if self.program.is_none() {
159 self.program = Some(Rc::from(RefCell::from(program::ImmutableProgram::default())));
160 }
161 self.program.clone().unwrap()
162 }
163
164 pub fn get_storage(&mut self) -> Rc<RefCell<storage::Storage>> {
166 self.storage.clone()
167 }
168
169 pub fn with_program(mut self, program: Rc<RefCell<dyn program::Program>>) -> Self {
171 self.program = Some(program);
172 self
173 }
174
175 pub fn build(mut self) -> Result<Machine> {
177 let console = self.builder.get_console();
178 let program = self.get_program();
179 let storage = self.get_storage();
180 let mut machine = self.builder.build()?;
181
182 exec::add_interactive(&mut machine);
183 help::add_all(&mut machine, console.clone());
184 program::add_all(&mut machine, program, console.clone(), storage.clone());
185 storage::add_all(&mut machine, console, storage);
186
187 Ok(machine)
188 }
189}