micromegas_transit/
dyn_string.rs

1use crate::{
2    InProcSerialize, InProcSize, advance_window, read_consume_pod, string_codec::StringCodec,
3    write_any,
4};
5use anyhow::Result;
6
7#[derive(Debug)]
8pub struct LegacyDynString(pub String);
9
10impl InProcSerialize for LegacyDynString {
11    const IN_PROC_SIZE: InProcSize = InProcSize::Dynamic;
12
13    fn get_value_size(&self) -> Option<u32> {
14        Some(self.0.len() as u32)
15    }
16
17    fn write_value(&self, buffer: &mut Vec<u8>) {
18        buffer.extend_from_slice(self.0.as_bytes());
19    }
20
21    #[allow(unsafe_code)]
22    unsafe fn read_value(window: &[u8]) -> Self {
23        Self(String::from_utf8(window.to_vec()).unwrap())
24    }
25}
26
27#[derive(Debug)]
28pub struct DynString(pub String);
29
30impl InProcSerialize for DynString {
31    const IN_PROC_SIZE: InProcSize = InProcSize::Dynamic;
32
33    fn get_value_size(&self) -> Option<u32> {
34        let header_size = 1 + // codec
35			std::mem::size_of::<u32>() as u32 // size in bytes
36			;
37        let string_size = self.0.len() as u32;
38        Some(header_size + string_size)
39    }
40
41    fn write_value(&self, buffer: &mut Vec<u8>) {
42        let codec = StringCodec::Utf8 as u8;
43        write_any(buffer, &codec);
44        let len = self.0.len() as u32;
45        write_any(buffer, &len);
46        buffer.extend_from_slice(self.0.as_bytes());
47    }
48
49    #[allow(unsafe_code)]
50    unsafe fn read_value(mut window: &[u8]) -> Self {
51        let res = read_advance_string(&mut window).unwrap();
52        assert_eq!(window.len(), 0);
53        Self(res)
54    }
55}
56
57/// Parse string from buffer, move buffer pointer forward.
58#[allow(unsafe_code, clippy::cast_ptr_alignment)]
59pub fn read_advance_string(window: &mut &[u8]) -> Result<String> {
60    unsafe {
61        let codec = StringCodec::try_from(read_consume_pod::<u8>(window))?;
62        let string_len_bytes: u32 = read_consume_pod(window);
63        let string_buffer = &window[0..(string_len_bytes as usize)];
64        *window = advance_window(window, string_len_bytes as usize);
65        match codec {
66            StringCodec::Ansi => {
67                // this would be typically be windows 1252, an extension to ISO-8859-1/latin1
68                // random people on the interwebs tell me that latin1's codepoints are a subset of utf8
69                // so I guess it's ok to treat it as utf8
70                Ok(String::from_utf8_lossy(string_buffer).to_string())
71            }
72            StringCodec::Wide => {
73                //wide
74                let ptr = string_buffer.as_ptr().cast::<u16>();
75                if !string_len_bytes.is_multiple_of(2) {
76                    anyhow::bail!("wrong utf-16 buffer size");
77                }
78                let wide_slice = std::ptr::slice_from_raw_parts(ptr, string_len_bytes as usize / 2);
79                Ok(String::from_utf16_lossy(&*wide_slice))
80            }
81            StringCodec::Utf8 => Ok(String::from_utf8_lossy(string_buffer).to_string()),
82        }
83    }
84}