1#![deny(missing_docs)]
2#![deny(clippy::all)]
3#![cfg_attr(docsrs, feature(doc_cfg))]
4#![doc = include_str!("../README.md")]
5
6use std::string::FromUtf8Error;
7
8use thiserror::Error;
9
10#[derive(Debug, Error, PartialEq)]
12pub enum DeserializationError {
13 #[error("Expected {0} bytes, found {1}")]
15 UnexpectedByteCount(usize, usize),
16 #[error("Could not deserialize to string, invalid UTF8")]
18 InvalidString {
19 #[from]
20 source: FromUtf8Error,
22 },
23 #[error("{0}")]
25 InvalidValue(String),
26}
27
28pub fn serialize_string<T: Into<String>>(value: T, buffer: &mut Vec<u8>) {
38 let mut value = value.into().into_bytes();
39 for b in value.len().to_le_bytes() {
40 buffer.push(b);
41 }
42 buffer.append(&mut value);
43}
44
45pub fn deserialize_string<T: TryFrom<String>>(
56 buffer: &mut Vec<u8>,
57) -> Result<T, DeserializationError>
58where
59 <T as TryFrom<String>>::Error: ToString,
60{
61 let value_size = deserialize_usize(buffer)?;
62 if value_size > buffer.len() {
63 return Err(DeserializationError::UnexpectedByteCount(
64 value_size,
65 buffer.len(),
66 ));
67 }
68 let tmp = buffer.split_off(value_size);
69 let result = String::from_utf8(buffer.to_owned()).map_err(|ex| ex.into());
70 *buffer = tmp;
71 result.and_then(|value| {
72 T::try_from(value).map_err(|ex| DeserializationError::InvalidValue(ex.to_string()))
73 })
74}
75
76pub fn serialize_vec<T: Into<String>>(value: Vec<T>, buffer: &mut Vec<u8>) {
88 for b in value.len().to_le_bytes() {
89 buffer.push(b);
90 }
91 for item in value {
92 serialize_string(item.into(), buffer);
93 }
94}
95
96pub fn deserialize_vec<T: TryFrom<String>>(
108 buffer: &mut Vec<u8>,
109) -> Result<Vec<T>, DeserializationError>
110where
111 <T as TryFrom<String>>::Error: ToString,
112{
113 let num_items = deserialize_usize(buffer)?;
114 let mut result = Vec::with_capacity(num_items);
115 for _ in 0..num_items {
116 result.push(deserialize_string(buffer)?);
117 }
118 Ok(result)
119}
120
121pub fn finalize_serialization(buffer: &mut Vec<u8>) {
136 let buffer_len = buffer.len();
137 for (index, b) in buffer_len.to_le_bytes().iter().enumerate() {
138 buffer.insert(index, *b);
139 }
140}
141
142blt_macros::add_num!(u64, "u8");
143blt_macros::add_num!(u64, "u16");
144blt_macros::add_num!(u64, "u32");
145blt_macros::add_num!(u64, "u64");
146blt_macros::add_num!(u64, "u128");
147blt_macros::add_num!(usize, "usize");
148
149blt_macros::add_num!(i64, "i8");
150blt_macros::add_num!(i64, "i16");
151blt_macros::add_num!(i64, "i32");
152blt_macros::add_num!(i64, "i64");
153blt_macros::add_num!(i64, "i128");
154blt_macros::add_num!(isize, "isize");
155
156blt_macros::add_num!(f32, "f32");
157blt_macros::add_num!(f64, "f64");
158
159blt_macros::remove_num!(u64, "u8");
160blt_macros::remove_num!(u64, "u16");
161blt_macros::remove_num!(u64, "u32");
162blt_macros::remove_num!(u64, "u64");
163blt_macros::remove_num!(u64, "u128");
164blt_macros::remove_num!(usize, "usize");
165
166blt_macros::remove_num!(i64, "i8");
167blt_macros::remove_num!(i64, "i16");
168blt_macros::remove_num!(i64, "i32");
169blt_macros::remove_num!(i64, "i64");
170blt_macros::remove_num!(i64, "i128");
171blt_macros::remove_num!(isize, "isize");
172
173blt_macros::remove_num!(f32, "f32");
174blt_macros::remove_num!(f64, "f64");
175
176#[macro_use]
177mod blt_macros {
178 macro_rules! add_num {
179 ($t: ty, $t_name: expr) => {
180 paste::paste! {
181 pub fn [<serialize_ $t_name>](value: $t, buffer: &mut Vec<u8>) {
183 for b in value.to_le_bytes() {
184 buffer.push(b);
185 }
186 }
187 }
188 };
189 }
190
191 macro_rules! remove_num {
192 ($t: ty, $t_name: expr) => {
193 paste::paste! {
194 pub fn [<deserialize_ $t_name>](buffer: &mut Vec<u8>) -> Result<$t, DeserializationError> {
197 let t_len = std::mem::size_of::<$t>();
198 if t_len > buffer.len() {
199 return Err(DeserializationError::UnexpectedByteCount(
200 t_len,
201 buffer.len(),
202 ));
203 }
204 let remaining_bytes = buffer.split_off(t_len);
205 let result = $t::from_le_bytes(buffer.as_slice().try_into().unwrap());
206 *buffer = remaining_bytes;
207 Ok(result)
208 }
209 }
210 };
211 }
212
213 pub(crate) use add_num;
214 pub(crate) use remove_num;
215}