luanti_protocol/types/
strings.rs

1use crate::wire::{
2    deser::{Deserialize, DeserializeError, DeserializeResult, Deserializer},
3    ser::{Serialize, SerializeResult, Serializer},
4};
5use anyhow::bail;
6use log::trace;
7use std::ops::DerefMut;
8use std::{marker::PhantomData, ops::Deref};
9
10/// Rust String's must be valid UTF8. But Luanti's strings can contain arbitrary
11/// binary data. The only way to store arbitrary bytes is with something like Vec<u8>,
12/// which is not String-like. This provides a String-like alternative, that looks nice
13/// in debug output.
14#[derive(Clone, PartialEq)]
15pub struct ByteString(pub Vec<u8>);
16
17impl std::fmt::Debug for ByteString {
18    fn fmt(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
19        // Format it as an escaped string
20        std::fmt::Debug::fmt(&self.escape_ascii(), formatter)
21    }
22}
23
24impl ByteString {
25    #[must_use]
26    pub fn as_bytes(&self) -> &[u8] {
27        &self.0
28    }
29
30    #[must_use]
31    pub fn len(&self) -> usize {
32        self.0.len()
33    }
34
35    #[must_use]
36    pub fn is_empty(&self) -> bool {
37        self.0.is_empty()
38    }
39
40    #[must_use]
41    pub fn escape_ascii(&self) -> String {
42        self.0.escape_ascii().to_string()
43    }
44}
45
46impl Deref for ByteString {
47    type Target = [u8];
48
49    fn deref(&self) -> &Self::Target {
50        self.as_bytes()
51    }
52}
53
54impl DerefMut for ByteString {
55    fn deref_mut(&mut self) -> &mut Self::Target {
56        self.0.as_mut_slice()
57    }
58}
59
60impl From<Vec<u8>> for ByteString {
61    fn from(value: Vec<u8>) -> Self {
62        Self(value)
63    }
64}
65
66impl From<&[u8]> for ByteString {
67    fn from(value: &[u8]) -> Self {
68        Self(value.to_vec())
69    }
70}
71
72/// str implements Serialize but not Deserialize
73impl Serialize for str {
74    type Input = Self;
75
76    fn serialize<S: Serializer>(value: &Self::Input, ser: &mut S) -> SerializeResult {
77        u16::serialize(&u16::try_from(value.len())?, ser)?;
78        ser.write_bytes(value.as_bytes())
79    }
80}
81
82impl Serialize for String {
83    type Input = Self;
84    fn serialize<S: Serializer>(value: &Self::Input, ser: &mut S) -> SerializeResult {
85        <str as Serialize>::serialize(value, ser)
86    }
87}
88
89impl Deserialize for String {
90    type Output = Self;
91    fn deserialize(deser: &mut Deserializer<'_>) -> DeserializeResult<Self> {
92        let num_bytes = u16::deserialize(deser)? as usize;
93        trace!(
94            "String with {} bytes - {} bytes remaining",
95            num_bytes,
96            deser.remaining()
97        );
98        match std::str::from_utf8(deser.take(num_bytes)?) {
99            Ok(str) => Ok(str.into()),
100            Err(error) => bail!(DeserializeError::InvalidValue(error.to_string())),
101        }
102    }
103}
104
105#[derive(Debug, Clone, PartialEq)]
106pub struct LongString(PhantomData<String>);
107
108impl Serialize for LongString {
109    type Input = String;
110    fn serialize<S: Serializer>(value: &Self::Input, ser: &mut S) -> SerializeResult {
111        u32::serialize(&u32::try_from(value.len())?, ser)?;
112        ser.write_bytes(value.as_bytes())
113    }
114}
115
116impl Deserialize for LongString {
117    type Output = String;
118    fn deserialize(deser: &mut Deserializer<'_>) -> DeserializeResult<Self::Output> {
119        let num_bytes = u32::deserialize(deser)? as usize;
120        match std::str::from_utf8(deser.take(num_bytes)?) {
121            Ok(str) => Ok(str.into()),
122            Err(error) => bail!(DeserializeError::InvalidValue(error.to_string())),
123        }
124    }
125}
126
127/// Corresponds to `std::wstring` in C++ land
128#[derive(Debug, Clone, PartialEq)]
129pub struct WString(PhantomData<String>);
130
131impl Serialize for WString {
132    type Input = String;
133    fn serialize<S: Serializer>(value: &Self::Input, ser: &mut S) -> SerializeResult {
134        let enc: Vec<u16> = value.encode_utf16().collect();
135
136        u16::serialize(&u16::try_from(enc.len())?, ser)?;
137        // TODO: This could be made more efficient.
138        let mut buf: Vec<u8> = vec![0; 2 * enc.len()];
139        let mut index: usize = 0;
140        for codepoint in enc {
141            buf[index] = (codepoint >> 8) as u8;
142            buf[index + 1] = codepoint as u8;
143            index += 2;
144        }
145        ser.write_bytes(&buf)
146    }
147}
148
149impl Deserialize for WString {
150    type Output = String;
151    fn deserialize(deser: &mut Deserializer<'_>) -> DeserializeResult<Self::Output> {
152        let length = u16::deserialize(deser)? as usize;
153        let raw = deser.take(2 * length)?;
154        let mut seq: Vec<u16> = vec![0; length];
155        for i in 0..length {
156            seq[i] = u16::from_be_bytes(raw[2 * i..2 * i + 2].try_into().unwrap());
157        }
158        match String::from_utf16(&seq) {
159            Ok(str) => Ok(str),
160            Err(err) => bail!(DeserializeError::InvalidValue(err.to_string())),
161        }
162    }
163}