147fec44cSPat Hickey use crate::{Error, ErrorExt}; 2*f1411653SAlex Crichton use wiggle::{GuestMemory, GuestPtr}; 347fec44cSPat Hickey 447fec44cSPat Hickey pub struct StringArray { 547fec44cSPat Hickey elems: Vec<String>, 647fec44cSPat Hickey } 747fec44cSPat Hickey 847fec44cSPat Hickey #[derive(Debug, thiserror::Error)] 947fec44cSPat Hickey pub enum StringArrayError { 1047fec44cSPat Hickey #[error("Number of elements exceeds 2^32")] 1147fec44cSPat Hickey NumberElements, 1247fec44cSPat Hickey #[error("Element size exceeds 2^32")] 1347fec44cSPat Hickey ElementSize, 1447fec44cSPat Hickey #[error("Cumulative size exceeds 2^32")] 1547fec44cSPat Hickey CumulativeSize, 1647fec44cSPat Hickey } 1747fec44cSPat Hickey 1847fec44cSPat Hickey impl StringArray { new() -> Self1947fec44cSPat Hickey pub fn new() -> Self { 2047fec44cSPat Hickey StringArray { elems: Vec::new() } 2147fec44cSPat Hickey } 2247fec44cSPat Hickey push(&mut self, elem: String) -> Result<(), StringArrayError>2347fec44cSPat Hickey pub fn push(&mut self, elem: String) -> Result<(), StringArrayError> { 2447fec44cSPat Hickey if self.elems.len() + 1 > std::u32::MAX as usize { 2547fec44cSPat Hickey return Err(StringArrayError::NumberElements); 2647fec44cSPat Hickey } 2747fec44cSPat Hickey if elem.as_bytes().len() + 1 > std::u32::MAX as usize { 2847fec44cSPat Hickey return Err(StringArrayError::ElementSize); 2947fec44cSPat Hickey } 3047fec44cSPat Hickey if self.cumulative_size() as usize + elem.as_bytes().len() + 1 > std::u32::MAX as usize { 3147fec44cSPat Hickey return Err(StringArrayError::CumulativeSize); 3247fec44cSPat Hickey } 3347fec44cSPat Hickey self.elems.push(elem); 3447fec44cSPat Hickey Ok(()) 3547fec44cSPat Hickey } 3647fec44cSPat Hickey number_elements(&self) -> u323747fec44cSPat Hickey pub fn number_elements(&self) -> u32 { 3847fec44cSPat Hickey self.elems.len() as u32 3947fec44cSPat Hickey } 4047fec44cSPat Hickey cumulative_size(&self) -> u324147fec44cSPat Hickey pub fn cumulative_size(&self) -> u32 { 4247fec44cSPat Hickey self.elems 4347fec44cSPat Hickey .iter() 4447fec44cSPat Hickey .map(|e| e.as_bytes().len() + 1) 4547fec44cSPat Hickey .sum::<usize>() as u32 4647fec44cSPat Hickey } 4747fec44cSPat Hickey write_to_guest( &self, memory: &mut GuestMemory<'_>, buffer: GuestPtr<u8>, element_heads: GuestPtr<GuestPtr<u8>>, ) -> Result<(), Error>48*f1411653SAlex Crichton pub fn write_to_guest( 4947fec44cSPat Hickey &self, 50*f1411653SAlex Crichton memory: &mut GuestMemory<'_>, 51*f1411653SAlex Crichton buffer: GuestPtr<u8>, 52*f1411653SAlex Crichton element_heads: GuestPtr<GuestPtr<u8>>, 5347fec44cSPat Hickey ) -> Result<(), Error> { 5447fec44cSPat Hickey let element_heads = element_heads.as_array(self.number_elements()); 5547fec44cSPat Hickey let buffer = buffer.as_array(self.cumulative_size()); 5647fec44cSPat Hickey let mut cursor = 0; 5747fec44cSPat Hickey for (elem, head) in self.elems.iter().zip(element_heads.iter()) { 5847fec44cSPat Hickey let bytes = elem.as_bytes(); 5947fec44cSPat Hickey let len = bytes.len() as u32; 6047fec44cSPat Hickey { 6147fec44cSPat Hickey let elem_buffer = buffer 6247fec44cSPat Hickey .get_range(cursor..(cursor + len)) 6347fec44cSPat Hickey .ok_or(Error::invalid_argument())?; // Elements don't fit in buffer provided 64*f1411653SAlex Crichton memory.copy_from_slice(bytes, elem_buffer)?; 6547fec44cSPat Hickey } 66*f1411653SAlex Crichton memory.write( 67*f1411653SAlex Crichton buffer.get(cursor + len).ok_or(Error::invalid_argument())?, 68*f1411653SAlex Crichton 0, 69*f1411653SAlex Crichton )?; // 0 terminate 70*f1411653SAlex Crichton memory.write(head?, buffer.get(cursor).expect("already validated"))?; 7147fec44cSPat Hickey cursor += len + 1; 7247fec44cSPat Hickey } 7347fec44cSPat Hickey Ok(()) 7447fec44cSPat Hickey } 7547fec44cSPat Hickey } 76