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