pros_simulator/host/
memory.rs1use anyhow::Context;
2use snafu::Snafu;
3use wasmtime::SharedMemory;
4
5#[derive(Debug, Snafu)]
6pub struct OutOfBoundsError;
7
8pub trait SharedMemoryExt {
9 fn read_c_str(&self, ptr: u32) -> anyhow::Result<String>;
10 fn write_relaxed(&self, offset: usize, buffer: &[u8]) -> Result<(), OutOfBoundsError>;
11 fn read_relaxed(&self, offset: usize, length: usize) -> Result<Vec<u8>, OutOfBoundsError>;
12}
13
14impl SharedMemoryExt for SharedMemory {
15 fn read_c_str(&self, ptr: u32) -> anyhow::Result<String> {
16 let data = self
17 .data()
18 .get(ptr as usize..)
19 .with_context(|| format!("invalid pointer: {}", ptr))?;
20 for (index, cell) in data.iter().enumerate() {
21 if unsafe { cell.get().read() } == 0 {
22 return Ok(String::from_utf8(
23 data[..index]
24 .iter()
25 .map(|c| unsafe { c.get().read() })
26 .collect::<Vec<_>>(),
27 )
28 .expect("invalid UTF-8 string"));
29 }
30 }
31
32 Err(anyhow::anyhow!("C string must be null-terminated"))
33 }
34 fn write_relaxed(&self, offset: usize, buffer: &[u8]) -> Result<(), OutOfBoundsError> {
35 let Some(data) = self.data().get(offset..offset + buffer.len()) else {
36 return Err(OutOfBoundsError);
37 };
38 for (cell, byte) in data.iter().zip(buffer) {
39 unsafe { cell.get().write(*byte) };
40 }
41 Ok(())
42 }
43 fn read_relaxed(&self, offset: usize, length: usize) -> Result<Vec<u8>, OutOfBoundsError> {
44 let Some(data) = self.data().get(offset..offset + length) else {
45 return Err(OutOfBoundsError);
46 };
47 let mut buffer = Vec::with_capacity(length);
48 for cell in data.iter() {
49 buffer.push(unsafe { cell.get().read() });
50 }
51 Ok(buffer)
52 }
53}