wasi_common/
string_array.rs1use crate::{Error, ErrorExt};
2use wiggle::{GuestMemory, GuestPtr};
3
4pub struct StringArray {
5 elems: Vec<String>,
6}
7
8#[derive(Debug, thiserror::Error)]
9pub enum StringArrayError {
10 #[error("Number of elements exceeds 2^32")]
11 NumberElements,
12 #[error("Element size exceeds 2^32")]
13 ElementSize,
14 #[error("Cumulative size exceeds 2^32")]
15 CumulativeSize,
16}
17
18impl StringArray {
19 pub fn new() -> Self {
20 StringArray { elems: Vec::new() }
21 }
22
23 pub fn push(&mut self, elem: String) -> Result<(), StringArrayError> {
24 if self.elems.len() + 1 > std::u32::MAX as usize {
25 return Err(StringArrayError::NumberElements);
26 }
27 if elem.as_bytes().len() + 1 > std::u32::MAX as usize {
28 return Err(StringArrayError::ElementSize);
29 }
30 if self.cumulative_size() as usize + elem.as_bytes().len() + 1 > std::u32::MAX as usize {
31 return Err(StringArrayError::CumulativeSize);
32 }
33 self.elems.push(elem);
34 Ok(())
35 }
36
37 pub fn number_elements(&self) -> u32 {
38 self.elems.len() as u32
39 }
40
41 pub fn cumulative_size(&self) -> u32 {
42 self.elems
43 .iter()
44 .map(|e| e.as_bytes().len() + 1)
45 .sum::<usize>() as u32
46 }
47
48 pub fn write_to_guest(
49 &self,
50 memory: &mut GuestMemory<'_>,
51 buffer: GuestPtr<u8>,
52 element_heads: GuestPtr<GuestPtr<u8>>,
53 ) -> Result<(), Error> {
54 let element_heads = element_heads.as_array(self.number_elements());
55 let buffer = buffer.as_array(self.cumulative_size());
56 let mut cursor = 0;
57 for (elem, head) in self.elems.iter().zip(element_heads.iter()) {
58 let bytes = elem.as_bytes();
59 let len = bytes.len() as u32;
60 {
61 let elem_buffer = buffer
62 .get_range(cursor..(cursor + len))
63 .ok_or(Error::invalid_argument())?; memory.copy_from_slice(bytes, elem_buffer)?;
65 }
66 memory.write(
67 buffer.get(cursor + len).ok_or(Error::invalid_argument())?,
68 0,
69 )?; memory.write(head?, buffer.get(cursor).expect("already validated"))?;
71 cursor += len + 1;
72 }
73 Ok(())
74 }
75}