1pub mod controllers;
2pub mod lcd;
3pub mod memory;
4pub mod multitasking;
5pub mod task;
6pub mod thread_local;
7
8use std::{alloc::Layout, sync::Arc, time::Instant};
9
10use async_trait::async_trait;
11use lcd::Lcd;
12use pros_simulator_interface::CompetitionPhase;
13use tokio::sync::{Mutex, MutexGuard};
14use wasmtime::{
15 AsContext, AsContextMut, Caller, Engine, Instance, Module, SharedMemory, TypedFunc,
16};
17
18use self::{
19 controllers::Controllers,
20 multitasking::MutexPool,
21 task::{TaskHandle, TaskPool},
22};
23use crate::interface::SimulatorInterface;
24
25#[derive(Clone)]
33pub struct WasmAllocator {
34 wasm_memalign: TypedFunc<(u32, u32), u32>,
35 wasm_free: TypedFunc<u32, ()>,
36}
37
38impl WasmAllocator {
39 pub fn new(mut store: impl AsContextMut, instance: &Instance) -> Self {
40 Self {
41 wasm_memalign: instance
42 .get_typed_func::<(u32, u32), u32>(&mut store, "wasm_memalign")
43 .unwrap(),
44 wasm_free: instance
45 .get_typed_func::<u32, ()>(&mut store, "wasm_free")
46 .unwrap(),
47 }
48 }
49
50 pub async fn memalign(
51 &self,
52 mut store: impl AsContextMut<Data = impl Send>,
53 layout: Layout,
54 ) -> u32 {
55 let size = layout.size().try_into().unwrap();
56 let alignment = layout.align().try_into().unwrap();
57 let ptr = self
58 .wasm_memalign
59 .call_async(&mut store, (alignment, size))
60 .await
61 .unwrap();
62 if ptr == 0 {
63 panic!("wasm_memalign failed");
64 }
65 ptr
66 }
67
68 pub async fn free(&self, mut store: impl AsContextMut<Data = impl Send>, ptr: u32) {
69 self.wasm_free.call_async(&mut store, ptr).await.unwrap()
70 }
71}
72
73#[derive(Clone)]
74pub struct Host {
75 memory: SharedMemory,
76 module: Module,
77 interface: SimulatorInterface,
79 lcd: Arc<Mutex<Lcd>>,
80 mutexes: Arc<Mutex<MutexPool>>,
82 tasks: Arc<Mutex<TaskPool>>,
83 controllers: Arc<Mutex<Controllers>>,
84 competition_phase: Arc<Mutex<CompetitionPhase>>,
85 start_time: Instant,
86}
87
88impl Host {
89 pub fn new(
90 engine: Engine,
91 memory: SharedMemory,
92 interface: SimulatorInterface,
93 module: Module,
94 ) -> anyhow::Result<Self> {
95 let lcd = Lcd::new(interface.clone());
96 let mutexes = MutexPool::default();
97 let tasks = TaskPool::new(engine, memory.clone(), interface.clone())?;
98 let controllers = Controllers::new(None, None);
99
100 Ok(Self {
101 memory,
102 module,
103 interface,
104 lcd: Arc::new(Mutex::new(lcd)),
105 mutexes: Arc::new(Mutex::new(mutexes)),
106 tasks: Arc::new(Mutex::new(tasks)),
107 controllers: Arc::new(Mutex::new(controllers)),
108 competition_phase: Default::default(),
109 start_time: Instant::now(),
110 })
111 }
112}
113
114#[async_trait]
115pub trait HostCtx {
116 fn memory(&self) -> SharedMemory;
117 fn module(&self) -> Module;
118 fn interface(&self) -> SimulatorInterface;
119 fn lcd(&self) -> Arc<Mutex<Lcd>>;
120 async fn lcd_lock(&self) -> MutexGuard<'_, Lcd>;
121 fn mutexes(&self) -> Arc<Mutex<MutexPool>>;
122 async fn mutexes_lock(&self) -> MutexGuard<'_, MutexPool>;
123 fn tasks(&self) -> Arc<Mutex<TaskPool>>;
124 async fn tasks_lock(&self) -> MutexGuard<'_, TaskPool>;
125 fn start_time(&self) -> Instant;
126 async fn current_task(&self) -> TaskHandle;
127 fn controllers(&self) -> Arc<Mutex<Controllers>>;
128 async fn controllers_lock(&self) -> MutexGuard<'_, Controllers>;
129 fn competition_phase(&self) -> Arc<Mutex<CompetitionPhase>>;
130 async fn competition_phase_lock(&self) -> MutexGuard<'_, CompetitionPhase>;
131}
132
133#[async_trait]
134impl HostCtx for Host {
135 fn memory(&self) -> SharedMemory {
136 self.memory.clone()
137 }
138
139 fn module(&self) -> Module {
140 self.module.clone()
141 }
142
143 fn interface(&self) -> SimulatorInterface {
144 self.interface.clone()
145 }
146
147 fn lcd(&self) -> Arc<Mutex<Lcd>> {
148 self.lcd.clone()
149 }
150
151 async fn lcd_lock(&self) -> MutexGuard<'_, Lcd> {
152 self.lcd.lock().await
153 }
154
155 fn mutexes(&self) -> Arc<Mutex<MutexPool>> {
156 self.mutexes.clone()
157 }
158
159 async fn mutexes_lock(&self) -> MutexGuard<'_, MutexPool> {
160 self.mutexes.lock().await
161 }
162
163 fn tasks(&self) -> Arc<Mutex<TaskPool>> {
164 self.tasks.clone()
165 }
166
167 async fn tasks_lock(&self) -> MutexGuard<'_, TaskPool> {
168 self.tasks.lock().await
169 }
170
171 fn start_time(&self) -> Instant {
172 self.start_time
173 }
174
175 async fn current_task(&self) -> TaskHandle {
176 self.tasks.lock().await.current()
177 }
178
179 fn controllers(&self) -> Arc<Mutex<Controllers>> {
180 self.controllers.clone()
181 }
182
183 async fn controllers_lock(&self) -> MutexGuard<'_, Controllers> {
184 self.controllers.lock().await
185 }
186
187 fn competition_phase(&self) -> Arc<Mutex<CompetitionPhase>> {
188 self.competition_phase.clone()
189 }
190
191 async fn competition_phase_lock(&self) -> MutexGuard<'_, CompetitionPhase> {
192 self.competition_phase.lock().await
193 }
194}
195
196#[async_trait]
197impl<T> HostCtx for T
198where
199 T: AsContext<Data = Host> + Sync,
200{
201 fn memory(&self) -> SharedMemory {
202 self.as_context().data().memory()
203 }
204
205 fn module(&self) -> Module {
206 self.as_context().data().module()
207 }
208
209 fn interface(&self) -> SimulatorInterface {
210 self.as_context().data().interface()
211 }
212
213 fn lcd(&self) -> Arc<Mutex<Lcd>> {
214 self.as_context().data().lcd()
215 }
216
217 async fn lcd_lock(&self) -> MutexGuard<'_, Lcd> {
218 self.as_context().data().lcd_lock().await
219 }
220
221 fn mutexes(&self) -> Arc<Mutex<MutexPool>> {
222 self.as_context().data().mutexes()
223 }
224
225 async fn mutexes_lock(&self) -> MutexGuard<'_, MutexPool> {
226 self.as_context().data().mutexes_lock().await
227 }
228
229 fn tasks(&self) -> Arc<Mutex<TaskPool>> {
230 self.as_context().data().tasks()
231 }
232
233 async fn tasks_lock(&self) -> MutexGuard<'_, TaskPool> {
234 self.as_context().data().tasks_lock().await
235 }
236
237 fn start_time(&self) -> Instant {
238 self.as_context().data().start_time()
239 }
240
241 async fn current_task(&self) -> TaskHandle {
242 self.as_context().data().tasks_lock().await.current()
243 }
244
245 fn controllers(&self) -> Arc<Mutex<Controllers>> {
246 self.as_context().data().controllers()
247 }
248
249 async fn controllers_lock(&self) -> MutexGuard<'_, Controllers> {
250 self.as_context().data().controllers_lock().await
251 }
252
253 fn competition_phase(&self) -> Arc<Mutex<CompetitionPhase>> {
254 self.as_context().data().competition_phase()
255 }
256
257 async fn competition_phase_lock(&self) -> MutexGuard<'_, CompetitionPhase> {
258 self.as_context().data().competition_phase_lock().await
259 }
260}
261
262#[async_trait]
263pub trait ResultExt<T> {
264 async fn unwrap_or_errno(self, caller: &mut Caller<'_, Host>) -> bool;
274
275 async fn unwrap_or_errno_as(self, caller: &mut Caller<'_, Host>, error_value: T) -> T;
285}
286
287#[async_trait]
288impl<T: Send> ResultExt<T> for Result<T, i32> {
289 async fn unwrap_or_errno(self, caller: &mut Caller<'_, Host>) -> bool {
290 if let Err(code) = self {
291 let current_task = caller.data().tasks_lock().await.current();
292 let memory = caller.data().memory();
293 let errno = current_task.lock().await.errno(&mut *caller).await;
294 errno.set(&memory, code);
295 }
296 self.is_ok()
297 }
298
299 async fn unwrap_or_errno_as(self, caller: &mut Caller<'_, Host>, error_value: T) -> T {
300 match self {
301 Err(code) => {
302 let current_task = caller.data().tasks_lock().await.current();
303 let memory = caller.data().memory();
304 let errno = current_task.lock().await.errno(&mut *caller).await;
305 errno.set(&memory, code);
306 error_value
307 }
308 Ok(value) => value,
309 }
310 }
311}