pros_simulator/host/
memory.rs

1use 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}