blt_utils/
lib.rs

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/// An enumeration of errors that can occur during custom deserialization.
11#[derive(Debug, Error, PartialEq)]
12pub enum DeserializationError {
13    /// Indicates there are less than the necessary number of bytes to deserialize the value.
14    #[error("Expected {0} bytes, found {1}")]
15    UnexpectedByteCount(usize, usize),
16    /// Indicates a String value contains invalid UTF8 bytes.
17    #[error("Could not deserialize to string, invalid UTF8")]
18    InvalidString {
19        #[from]
20        /// The source of the error.
21        source: FromUtf8Error,
22    },
23    /// Indicates a custom type could not be converted from raw parts.
24    #[error("{0}")]
25    InvalidValue(String),
26}
27
28/// Appends the string representation of the given value to the buffer.
29///
30/// # Examples
31///
32/// ```
33/// let mut buffer = Vec::new();
34/// blt_utils::serialize_string("Hello World!", &mut buffer);
35/// assert_eq!(buffer.as_slice(), [12, 0, 0, 0, 0, 0, 0, 0, 72, 101, 108, 108, 111, 32, 87, 111, 114, 108, 100, 33]);
36/// ```
37pub 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
45/// Removes the next string value from the buffer.
46///
47/// # Examples
48///
49/// ```
50/// let mut buffer = [12, 0, 0, 0, 0, 0, 0, 0, 72, 101, 108, 108, 111, 32, 87, 111, 114, 108, 100, 33].to_vec();
51/// let value = blt_utils::deserialize_string::<String>(&mut buffer)?;
52/// assert_eq!(value, String::from("Hello World!"));
53/// # Ok::<(), blt_utils::DeserializationError>(())
54/// ```
55pub 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
76/// Appends the given collection to the buffer.
77///
78/// # Examples
79///
80/// ```
81/// let v = ["Hello", "World"].to_vec();
82/// let mut buffer = Vec::new();
83/// blt_utils::serialize_vec(v, &mut buffer);
84///
85/// assert_eq!(buffer.as_slice(), [2, 0, 0, 0, 0, 0, 0, 0, 5, 0, 0, 0, 0, 0, 0, 0, 72, 101, 108, 108, 111, 5, 0, 0, 0, 0, 0, 0, 0, 87, 111, 114, 108, 100]);
86/// ```
87pub 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
96/// Removes the next collection of strings from the buffer.
97/// If an error occurs for an element after the first, the buffer is left in an indeterminate state.
98///
99/// # Examples
100///
101/// ```
102/// let mut buffer = [2, 0, 0, 0, 0, 0, 0, 0, 5, 0, 0, 0, 0, 0, 0, 0, 72, 101, 108, 108, 111, 5, 0, 0, 0, 0, 0, 0, 0, 87, 111, 114, 108, 100].to_vec();
103/// let value = blt_utils::deserialize_vec::<String>(&mut buffer)?;
104/// assert_eq!(value.as_slice(), [String::from("Hello"), String::from("World")]);
105/// # Ok::<(), blt_utils::DeserializationError>(())
106/// ```
107pub 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
121/// Prepends the length of the buffer to the buffer.
122///
123/// # Examples
124///
125/// ```
126/// // let mut buffer = Vec::new();
127/// // blt_utils::serialize_string("First", &mut buffer);
128/// // blt_utils::serialize_string("Last", &mut buffer);
129/// // blt_utils::serialize_u32(42, &mut buffer);
130/// let mut buffer = [5, 0, 0, 0, 0, 0, 0, 0, 70, 105, 114, 115, 116, 4, 0, 0, 0, 0, 0, 0, 0, 76, 97, 115, 116, 42, 0, 0, 0, 0, 0, 0, 0].to_vec();
131/// blt_utils::finalize_serialization(&mut buffer);
132///
133/// assert_eq!(buffer.as_slice(), [33, 0, 0, 0, 0, 0, 0, 0, 5, 0, 0, 0, 0, 0, 0, 0, 70, 105, 114, 115, 116, 4, 0, 0, 0, 0, 0, 0, 0, 76, 97, 115, 116, 42, 0, 0, 0, 0, 0, 0, 0]);
134/// ```
135pub 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                /// Adds the given numeric value to the buffer.
182                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                /// Removes the next numeric value from the buffer.
195                /// If the buffer does not contain enough elements to create a numeric value, the buffer is unchanged and an error is returned.
196                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}