1 use crate::{Error, ErrorExt}; 2 use wiggle::GuestPtr; 3 4 pub struct StringArray { 5 elems: Vec<String>, 6 } 7 8 #[derive(Debug, thiserror::Error)] 9 pub 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 18 impl 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<'a>( 49 &self, 50 buffer: &GuestPtr<'a, u8>, 51 element_heads: &GuestPtr<'a, GuestPtr<'a, u8>>, 52 ) -> Result<(), Error> { 53 let element_heads = element_heads.as_array(self.number_elements()); 54 let buffer = buffer.as_array(self.cumulative_size()); 55 let mut cursor = 0; 56 for (elem, head) in self.elems.iter().zip(element_heads.iter()) { 57 let bytes = elem.as_bytes(); 58 let len = bytes.len() as u32; 59 { 60 let elem_buffer = buffer 61 .get_range(cursor..(cursor + len)) 62 .ok_or(Error::invalid_argument())?; // Elements don't fit in buffer provided 63 elem_buffer.copy_from_slice(bytes)?; 64 } 65 buffer 66 .get(cursor + len) 67 .ok_or(Error::invalid_argument())? 68 .write(0)?; // 0 terminate 69 head?.write(buffer.get(cursor).expect("already validated"))?; 70 cursor += len + 1; 71 } 72 Ok(()) 73 } 74 } 75