1use bytes::BytesMut;
27
28#[derive(Debug, Clone, PartialEq, Eq)]
30pub struct EncodingError {
31 pub message: String,
32}
33
34impl std::error::Error for EncodingError {}
35
36impl std::fmt::Display for EncodingError {
37 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
38 write!(f, "{}", self.message)
39 }
40}
41
42impl From<super::DeserializeError> for EncodingError {
43 fn from(err: super::DeserializeError) -> Self {
44 EncodingError {
45 message: err.message,
46 }
47 }
48}
49
50pub fn encode_utf8(s: &str, buf: &mut BytesMut) {
54 let bytes = s.as_bytes();
55 let len = bytes.len();
56 if len > u16::MAX as usize {
57 panic!("String too long for UTF-8 encoding: {} bytes", len);
58 }
59 buf.extend_from_slice(&(len as u16).to_le_bytes());
60 buf.extend_from_slice(bytes);
61}
62
63pub fn decode_utf8(buf: &mut &[u8]) -> Result<String, EncodingError> {
67 if buf.len() < 2 {
68 return Err(EncodingError {
69 message: "Buffer too short for UTF-8 length".to_string(),
70 });
71 }
72 let len = u16::from_le_bytes([buf[0], buf[1]]) as usize;
73 *buf = &buf[2..];
74
75 if buf.len() < len {
76 return Err(EncodingError {
77 message: format!(
78 "Buffer too short for UTF-8 payload: need {} bytes, have {}",
79 len,
80 buf.len()
81 ),
82 });
83 }
84
85 let bytes = &buf[..len];
86 *buf = &buf[len..];
87
88 String::from_utf8(bytes.to_vec()).map_err(|e| EncodingError {
89 message: format!("Invalid UTF-8: {}", e),
90 })
91}
92
93pub fn encode_optional_utf8(opt: Option<&str>, buf: &mut BytesMut) {
97 match opt {
98 Some(s) => encode_utf8(s, buf),
99 None => {
100 buf.extend_from_slice(&0u16.to_le_bytes());
101 }
102 }
103}
104
105pub fn decode_optional_utf8(buf: &mut &[u8]) -> Result<Option<String>, EncodingError> {
109 if buf.len() < 2 {
110 return Err(EncodingError {
111 message: "Buffer too short for optional UTF-8 length".to_string(),
112 });
113 }
114 let len = u16::from_le_bytes([buf[0], buf[1]]);
115 if len == 0 {
116 *buf = &buf[2..];
117 return Ok(None);
118 }
119 decode_utf8(buf).map(Some)
120}
121
122pub fn decode_array_count(buf: &mut &[u8]) -> Result<usize, EncodingError> {
126 if buf.len() < 2 {
127 return Err(EncodingError {
128 message: "Buffer too short for array count".to_string(),
129 });
130 }
131 let count = u16::from_le_bytes([buf[0], buf[1]]) as usize;
132 *buf = &buf[2..];
133 Ok(count)
134}
135
136pub fn encode_array_count(count: usize, buf: &mut BytesMut) {
140 if count > u16::MAX as usize {
141 panic!("Array too long: {} items", count);
142 }
143 buf.extend_from_slice(&(count as u16).to_le_bytes());
144}
145
146pub fn validate_fixed_element_array_len(
148 buf_len: usize,
149 element_size: usize,
150) -> Result<usize, EncodingError> {
151 if !buf_len.is_multiple_of(element_size) {
152 return Err(EncodingError {
153 message: format!(
154 "Buffer length {} is not divisible by element size {}",
155 buf_len, element_size
156 ),
157 });
158 }
159 Ok(buf_len / element_size)
160}
161
162pub fn encode_u64(value: u64, buf: &mut BytesMut) {
166 buf.extend_from_slice(&value.to_le_bytes());
167}
168
169pub fn decode_u64(buf: &mut &[u8]) -> Result<u64, EncodingError> {
173 if buf.len() < 8 {
174 return Err(EncodingError {
175 message: format!("Buffer too short for u64: need 8 bytes, have {}", buf.len()),
176 });
177 }
178 let bytes: [u8; 8] = buf[..8].try_into().map_err(|_| EncodingError {
179 message: "Failed to extract 8 bytes for u64".to_string(),
180 })?;
181 *buf = &buf[8..];
182 Ok(u64::from_le_bytes(bytes))
183}
184
185#[cfg(test)]
186mod tests {
187 use super::*;
188
189 #[test]
190 fn should_encode_and_decode_utf8() {
191 let s = "Hello, World!";
193 let mut buf = BytesMut::new();
194
195 encode_utf8(s, &mut buf);
197 let mut slice = buf.as_ref();
198 let decoded = decode_utf8(&mut slice).unwrap();
199
200 assert_eq!(decoded, s);
202 assert!(slice.is_empty());
203 }
204
205 #[test]
206 fn should_encode_and_decode_utf8_with_unicode() {
207 let s = "Hello, 世界!";
209 let mut buf = BytesMut::new();
210
211 encode_utf8(s, &mut buf);
213 let mut slice = buf.as_ref();
214 let decoded = decode_utf8(&mut slice).unwrap();
215
216 assert_eq!(decoded, s);
218 assert!(slice.is_empty());
219 }
220
221 #[test]
222 fn should_encode_and_decode_optional_utf8_some() {
223 let s = Some("test");
225 let mut buf = BytesMut::new();
226
227 encode_optional_utf8(s, &mut buf);
229 let mut slice = buf.as_ref();
230 let decoded = decode_optional_utf8(&mut slice).unwrap();
231
232 assert_eq!(decoded, s.map(|s| s.to_string()));
234 assert!(slice.is_empty());
235 }
236
237 #[test]
238 fn should_encode_and_decode_optional_utf8_none() {
239 let s: Option<&str> = None;
241 let mut buf = BytesMut::new();
242
243 encode_optional_utf8(s, &mut buf);
245 let mut slice = buf.as_ref();
246 let decoded = decode_optional_utf8(&mut slice).unwrap();
247
248 assert_eq!(decoded, None);
250 assert!(slice.is_empty());
251 }
252
253 #[test]
254 fn should_return_error_for_truncated_utf8() {
255 let mut buf = BytesMut::new();
257 buf.extend_from_slice(&10u16.to_le_bytes()); buf.extend_from_slice(b"short"); let mut slice = buf.as_ref();
262 let result = decode_utf8(&mut slice);
263
264 assert!(result.is_err());
266 assert!(result.unwrap_err().message.contains("Buffer too short"));
267 }
268
269 #[test]
270 fn should_encode_and_decode_u64() {
271 let value = 0x0123456789ABCDEFu64;
273 let mut buf = BytesMut::new();
274
275 encode_u64(value, &mut buf);
277 let mut slice = buf.as_ref();
278 let decoded = decode_u64(&mut slice).unwrap();
279
280 assert_eq!(decoded, value);
282 assert!(slice.is_empty());
283 }
284
285 #[test]
286 fn should_encode_and_decode_u64_zero() {
287 let value = 0u64;
289 let mut buf = BytesMut::new();
290
291 encode_u64(value, &mut buf);
293 let mut slice = buf.as_ref();
294 let decoded = decode_u64(&mut slice).unwrap();
295
296 assert_eq!(decoded, value);
298 assert!(slice.is_empty());
299 }
300
301 #[test]
302 fn should_encode_and_decode_u64_max() {
303 let value = u64::MAX;
305 let mut buf = BytesMut::new();
306
307 encode_u64(value, &mut buf);
309 let mut slice = buf.as_ref();
310 let decoded = decode_u64(&mut slice).unwrap();
311
312 assert_eq!(decoded, value);
314 assert!(slice.is_empty());
315 }
316
317 #[test]
318 fn should_return_error_for_truncated_u64() {
319 let mut buf = BytesMut::new();
321 buf.extend_from_slice(&[1, 2, 3]); let mut slice = buf.as_ref();
325 let result = decode_u64(&mut slice);
326
327 assert!(result.is_err());
329 assert!(result.unwrap_err().message.contains("Buffer too short"));
330 }
331}