pedronauck_data_parser/lib.rs
1#![doc = include_str!("../README.md")]
2
3mod compression_strategies;
4mod error;
5
6use std::{fmt::Debug, sync::Arc};
7
8pub use compression_strategies::*;
9#[cfg(feature = "json")]
10use serde::de::DeserializeOwned;
11
12pub use crate::error::{CompressionError, DataParserError, SerdeError};
13
14/// Serialization types supported for data parsing
15#[derive(Debug, Clone, strum::EnumIter, strum_macros::Display)]
16pub enum SerializationType {
17 /// Bincode serialization
18 #[cfg(feature = "bincode")]
19 #[strum(serialize = "bincode")]
20 Bincode,
21 /// json serialization
22 #[cfg(feature = "json")]
23 #[strum(serialize = "json")]
24 Json,
25 /// Postcard serialization
26 #[cfg(feature = "postcard")]
27 #[strum(serialize = "postcard")]
28 Postcard,
29}
30
31#[async_trait::async_trait]
32pub trait DataEncoder:
33 serde::Serialize
34 + serde::de::DeserializeOwned
35 + Clone
36 + Send
37 + Sync
38 + Debug
39 + std::marker::Sized
40{
41 type Err: std::error::Error + From<DataParserError>;
42
43 fn data_parser() -> DataParser {
44 DataParser::default()
45 }
46
47 async fn encode(&self) -> Result<Vec<u8>, Self::Err> {
48 Self::data_parser().encode(self).await.map_err(Into::into)
49 }
50
51 #[cfg(feature = "json")]
52 fn encode_json(&self) -> Result<Vec<u8>, Self::Err> {
53 Self::data_parser().encode_json(self).map_err(Into::into)
54 }
55
56 async fn decode(encoded: &[u8]) -> Result<Self, Self::Err> {
57 Self::data_parser()
58 .decode(encoded)
59 .await
60 .map_err(Into::into)
61 }
62
63 #[cfg(feature = "json")]
64 fn decode_json(encoded: &[u8]) -> Result<Self, Self::Err> {
65 Self::data_parser().decode_json(encoded).map_err(Into::into)
66 }
67
68 #[cfg(feature = "json")]
69 fn to_json_value(&self) -> Result<serde_json::Value, Self::Err> {
70 Self::data_parser().to_json_value(self).map_err(Into::into)
71 }
72}
73
74/// `DataParser` is a utility struct for encoding (serializing and optionally compressing)
75/// and decoding (deserializing and optionally decompressing) data. It is useful for
76/// optimizing memory usage and I/O bandwidth by applying different
77/// serialization formats and optional compression strategies.
78///
79/// # Fields
80///
81/// * `compression_strategy` - An `Option<Arc<dyn CompressionStrategy>>` that defines
82/// the method of data compression. If `None`, no compression is applied.
83/// * `serialization_type` - An enum that specifies the serialization format
84/// (e.g., Bincode, Postcard, JSON).
85///
86/// # Examples
87///
88/// ```
89/// use pedronauck_data_parser::*;
90/// use std::sync::Arc;
91///
92/// #[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq)]
93/// struct TestData {
94/// field: String,
95/// }
96///
97/// impl DataEncoder for TestData {
98/// type Err = DataParserError;
99/// }
100///
101/// #[tokio::main]
102/// async fn main() -> Result<(), Box<dyn std::error::Error>> {
103/// let parser = DataParser::default();
104///
105/// let original_data = TestData { field: "test".to_string() };
106/// let encoded = parser.encode(&original_data).await?;
107/// let decoded: TestData = parser.decode(&encoded).await?;
108///
109/// assert_eq!(original_data, decoded);
110/// Ok(())
111/// }
112/// ```
113#[derive(Clone)]
114pub struct DataParser {
115 compression_strategy: Option<Arc<dyn CompressionStrategy>>,
116 pub serialization_type: SerializationType,
117}
118
119impl Default for DataParser {
120 /// Provides a default instance of `DataParser` with no compression strategy
121 /// and `SerializationType::Json`.
122 ///
123 /// # Examples
124 ///
125 /// ```
126 /// use pedronauck_data_parser::{DataParser, SerializationType};
127 ///
128 /// let parser = DataParser::default();
129 /// assert!(matches!(parser.serialization_type, SerializationType::Json));
130 /// ```
131 fn default() -> Self {
132 Self {
133 compression_strategy: None,
134 serialization_type: SerializationType::Json,
135 }
136 }
137}
138
139impl DataParser {
140 /// Sets the compression strategy for the `DataParser`.
141 ///
142 /// # Arguments
143 ///
144 /// * `compression_strategy` - A reference to an `Arc` of a `CompressionStrategy` trait object.
145 ///
146 /// # Returns
147 ///
148 /// A new instance of `DataParser` with the updated compression strategy.
149 ///
150 /// # Examples
151 ///
152 /// ```
153 /// use pedronauck_data_parser::*;
154 /// use std::sync::Arc;
155 ///
156 /// let parser = DataParser::default()
157 /// .with_compression_strategy(&DEFAULT_COMPRESSION_STRATEGY);
158 /// ```
159 pub fn with_compression_strategy(
160 mut self,
161 compression_strategy: &Arc<dyn CompressionStrategy>,
162 ) -> Self {
163 self.compression_strategy = Some(compression_strategy.clone());
164 self
165 }
166
167 /// Sets the serialization type for the `DataParser`.
168 ///
169 /// # Arguments
170 ///
171 /// * `serialization_type` - A `SerializationType` enum specifying the desired serialization format.
172 ///
173 /// # Returns
174 ///
175 /// A new instance of `DataParser` with the updated serialization type.
176 ///
177 /// # Examples
178 ///
179 /// ```
180 /// use pedronauck_data_parser::*;
181 ///
182 /// let parser = DataParser::default()
183 /// .with_serialization_type(SerializationType::Postcard);
184 /// ```
185 pub fn with_serialization_type(
186 mut self,
187 serialization_type: SerializationType,
188 ) -> Self {
189 self.serialization_type = serialization_type;
190 self
191 }
192
193 /// Encodes the provided data by serializing and optionally compressing it.
194 ///
195 /// # Arguments
196 ///
197 /// * `data` - A reference to a data structure implementing the `DataParseable` trait.
198 ///
199 /// # Returns
200 ///
201 /// A `Result` containing either a `Vec<u8>` of the serialized (and optionally compressed) data,
202 /// or an `Error` if encoding fails.
203 ///
204 /// # Examples
205 ///
206 /// ```
207 /// use pedronauck_data_parser::*;
208 ///
209 /// #[derive(serde::Serialize, serde::Deserialize, Debug, Clone)]
210 /// struct TestData {
211 /// field: String,
212 /// }
213 ///
214 /// impl DataEncoder for TestData {
215 /// type Err = DataParserError;
216 /// }
217 ///
218 /// #[tokio::main]
219 /// async fn main() -> Result<(), Box<dyn std::error::Error>> {
220 /// let parser = DataParser::default();
221 /// let data = TestData { field: "test".to_string() };
222 /// let encoded = parser.encode(&data).await?;
223 /// assert!(!encoded.is_empty());
224 /// Ok(())
225 /// }
226 /// ```
227 pub async fn encode<T: DataEncoder>(
228 &self,
229 data: &T,
230 ) -> Result<Vec<u8>, DataParserError> {
231 let serialized_data = self.serialize(data).await?;
232 Ok(match &self.compression_strategy {
233 Some(strategy) => strategy.compress(&serialized_data[..]).await?,
234 None => serialized_data,
235 })
236 }
237
238 #[cfg(feature = "json")]
239 pub fn encode_json<T: DataEncoder>(
240 &self,
241 data: &T,
242 ) -> Result<Vec<u8>, DataParserError> {
243 self.serialize_json(data)
244 }
245
246 #[cfg(feature = "json")]
247 pub fn to_json_value<T: serde::Serialize>(
248 &self,
249 data: &T,
250 ) -> Result<serde_json::Value, DataParserError> {
251 self.serialize_json_value(data)
252 }
253
254 /// Serializes the provided data according to the selected `SerializationType`.
255 ///
256 /// # Arguments
257 ///
258 /// * `raw_data` - A reference to a data structure implementing the `DataParseable` trait.
259 ///
260 /// # Returns
261 ///
262 /// A `Result` containing either a `Vec<u8>` of the serialized data,
263 /// or an `Error` if serialization fails.
264 pub async fn serialize<T: DataEncoder>(
265 &self,
266 raw_data: &T,
267 ) -> Result<Vec<u8>, DataParserError> {
268 match self.serialization_type {
269 #[cfg(feature = "bincode")]
270 SerializationType::Bincode => bincode::serialize(&raw_data)
271 .map_err(|e| DataParserError::Encode(SerdeError::Bincode(*e))),
272 #[cfg(feature = "json")]
273 SerializationType::Json => serde_json::to_vec(&raw_data)
274 .map_err(|e| DataParserError::EncodeJson(SerdeError::Json(e))),
275 #[cfg(feature = "postcard")]
276 SerializationType::Postcard => postcard::to_allocvec(&raw_data)
277 .map_err(|e| DataParserError::Encode(SerdeError::Postcard(e))),
278 }
279 }
280
281 #[cfg(feature = "json")]
282 fn serialize_json<T: DataEncoder>(
283 &self,
284 raw_data: &T,
285 ) -> Result<Vec<u8>, DataParserError> {
286 serde_json::to_vec(&raw_data)
287 .map_err(|e| DataParserError::EncodeJson(SerdeError::Json(e)))
288 }
289
290 #[cfg(feature = "json")]
291 fn serialize_json_value<T: serde::Serialize>(
292 &self,
293 raw_data: &T,
294 ) -> Result<serde_json::Value, DataParserError> {
295 serde_json::to_value(raw_data)
296 .map_err(|e| DataParserError::EncodeJson(SerdeError::Json(e)))
297 }
298
299 /// Decodes the provided data by deserializing and optionally decompressing it.
300 ///
301 /// # Arguments
302 ///
303 /// * `data` - A byte slice (`&[u8]`) representing the serialized (and optionally compressed) data.
304 ///
305 /// # Returns
306 ///
307 /// A `Result` containing either the deserialized data structure,
308 /// or an `Error` if decoding fails.
309 ///
310 /// # Examples
311 ///
312 /// ```
313 /// use pedronauck_data_parser::*;
314 ///
315 /// #[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq)]
316 /// struct TestData {
317 /// field: String,
318 /// }
319 ///
320 /// impl DataEncoder for TestData {
321 /// type Err = DataParserError;
322 /// }
323 ///
324 /// #[tokio::main]
325 /// async fn main() -> Result<(), Box<dyn std::error::Error>> {
326 /// let parser = DataParser::default();
327 /// let original_data = TestData { field: "test".to_string() };
328 /// let encoded = parser.encode(&original_data).await?;
329 /// let decoded: TestData = parser.decode(&encoded).await?;
330 /// assert_eq!(original_data, decoded);
331 /// Ok(())
332 /// }
333 /// ```
334 pub async fn decode<T: DataEncoder>(
335 &self,
336 data: &[u8],
337 ) -> Result<T, DataParserError> {
338 let data = match &self.compression_strategy {
339 Some(strategy) => strategy.decompress(data).await?,
340 None => data.to_vec(),
341 };
342 let decoded_data = self.deserialize(&data[..])?;
343 Ok(decoded_data)
344 }
345
346 #[cfg(feature = "json")]
347 pub fn decode_json<T: DataEncoder>(
348 &self,
349 data: &[u8],
350 ) -> Result<T, DataParserError> {
351 self.deserialize_json(data)
352 }
353
354 /// Deserializes the provided data according to the selected `SerializationType`.
355 ///
356 /// # Arguments
357 ///
358 /// * `raw_data` - A byte slice (`&[u8]`) representing the serialized data.
359 ///
360 /// # Returns
361 ///
362 /// A `Result` containing either the deserialized data structure,
363 /// or an `Error` if deserialization fails.
364 pub fn deserialize<T: DeserializeOwned>(
365 &self,
366 raw_data: &[u8],
367 ) -> Result<T, DataParserError> {
368 match self.serialization_type {
369 #[cfg(feature = "bincode")]
370 SerializationType::Bincode => bincode::deserialize(raw_data)
371 .map_err(|e| DataParserError::Decode(SerdeError::Bincode(*e))),
372 #[cfg(feature = "json")]
373 SerializationType::Json => self.deserialize_json(raw_data),
374 #[cfg(feature = "postcard")]
375 SerializationType::Postcard => postcard::from_bytes(raw_data)
376 .map_err(|e| DataParserError::Decode(SerdeError::Postcard(e))),
377 }
378 }
379
380 #[cfg(feature = "json")]
381 fn deserialize_json<T: DeserializeOwned>(
382 &self,
383 raw_data: &[u8],
384 ) -> Result<T, DataParserError> {
385 serde_json::from_slice(raw_data)
386 .map_err(|e| DataParserError::DecodeJson(SerdeError::Json(e)))
387 }
388}
389
390#[cfg(test)]
391mod tests {
392 use pretty_assertions::assert_eq;
393
394 use super::*;
395
396 #[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq)]
397 struct TestData {
398 field: String,
399 }
400
401 impl DataEncoder for TestData {
402 type Err = DataParserError;
403 }
404
405 #[tokio::test]
406 async fn test_encode_decode() {
407 let parser = DataParser::default();
408 let original_data = TestData {
409 field: "test".to_string(),
410 };
411 let encoded = parser.encode(&original_data).await.unwrap();
412 let decoded: TestData = parser.decode(&encoded).await.unwrap();
413 assert_eq!(original_data, decoded);
414 }
415
416 #[tokio::test]
417 async fn test_serialization_types() {
418 let data = TestData {
419 field: "test".to_string(),
420 };
421
422 for serialization_type in [
423 #[cfg(feature = "bincode")]
424 SerializationType::Bincode,
425 #[cfg(feature = "postcard")]
426 SerializationType::Postcard,
427 #[cfg(feature = "json")]
428 SerializationType::Json,
429 ] {
430 let parser = DataParser::default()
431 .with_serialization_type(serialization_type);
432 let encoded = parser.encode(&data).await.unwrap();
433 let decoded: TestData = parser.decode(&encoded).await.unwrap();
434 assert_eq!(data, decoded);
435 }
436 }
437
438 #[tokio::test]
439 async fn test_compression_strategies() {
440 let data = TestData {
441 field: "test".to_string(),
442 };
443
444 for strategy in ALL_COMPRESSION_STRATEGIES.iter() {
445 let parser =
446 DataParser::default().with_compression_strategy(strategy);
447 let encoded = parser.encode(&data).await.unwrap();
448 let decoded: TestData = parser.decode(&encoded).await.unwrap();
449 assert_eq!(data, decoded);
450 }
451 }
452}