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}