1use std::{cell::Cell, error::Error, fs::File, io::{Read, Write}, path::Path};
2use log::debug;
3
4use color_eyre::eyre::eyre;
5
6#[cfg(feature = "wasmtime")]
7use wasmtime::*;
8
9#[cfg(feature = "wasmi")]
10use wasmi::*;
11
12use crate::ElytraDevice;
13
14pub struct WasmDevice {
15 instance: Instance,
16 store: Store<HostState>,
17 log: Cell<Vec<([u8; 64], [u8; 64])>>
18}
19
20type HostState = u32;
21
22type Message = (u64, u64, u64, u64, u64, u64, u64, u64);
23
24fn pack64(value: [u8; 64]) -> Message {
25 let mut buf = [0u64; 8];
26 for (i, bytes) in value.chunks(8).enumerate() {
27 buf[i] = u64::from_be_bytes(bytes.try_into().unwrap());
28 }
29 buf.into()
30}
31
32impl WasmDevice {
33 pub fn new(file_path: &Path) -> Result<Self, Box<dyn Error>> {
34
35 let engine = Engine::default();
36 let mut file = File::open(file_path)?;
39 let mut bytes = Vec::new();
40 file.read_to_end(&mut bytes)?;
41 let module = Module::new(&engine, bytes)?;
42
43 for e in module.exports() {
44 debug!("WASM Export {}: {:#?}", e.name(), e.ty());
45 }
46
47 let mut store = Store::new(&engine, 0);
48 let linker = <Linker<HostState>>::new(&engine);
49
50
51 #[cfg(feature = "wasmtime")]
52 let instance = linker.instantiate(&mut store, &module)?;
53
54 #[cfg(feature = "wasmi")]
55 let instance = linker.instantiate_and_start(&mut store, &module)?;
56
57 Ok(Self {
58 instance, store, log: Cell::new(vec![])
59 })
60 }
61}
62
63impl ElytraDevice for WasmDevice {
64 fn send_command_raw(&mut self, bytes: [u8; 64]) -> Result<[u8; 64], Box<dyn std::error::Error>> {
65 let msg_in = pack64(bytes);
66 let send_fn = self.instance.get_typed_func::<Message, u32>(&mut self.store, "send")
67 .unwrap();
68 let recieve_fn = self.instance.get_typed_func::<u32, u64>(&mut self.store, "recieve")
69 .unwrap();
70
71
72 let res_pack_count: u32 = send_fn.call(&mut self.store, msg_in)?;
73
74 if res_pack_count == 0 {
75 return Err(eyre!("Error response from WASM device"))?
76 }
77
78 let mut out_data = [0u8; 64];
79 let mut cursor = out_data.as_mut_slice();
80 for i in 0..res_pack_count {
81 let packed = recieve_fn.call(&mut self.store, i)?;
82 let _ = cursor.write(&packed.to_be_bytes())?;
83 }
84
85 Ok(out_data)
86 }
87
88 fn log_chat(&mut self, bytes_out: [u8; 64], bytes_in: [u8; 64]) {
89 self.log.get_mut().push((bytes_out, bytes_in));
90 }
91
92 fn get_log(&mut self) -> Vec<([u8; 64], [u8; 64])> {
93 self.log.replace(vec![])
94 }
95}