#![doc = include_str!("../README.md")]
mod compression_strategies;
mod error;
use std::{fmt::Debug, sync::Arc};
pub use compression_strategies::*;
#[cfg(feature = "json")]
use serde::de::DeserializeOwned;
pub use crate::error::{CompressionError, DataParserError, SerdeError};
#[derive(Debug, Clone, strum::EnumIter, strum_macros::Display)]
pub enum SerializationType {
#[cfg(feature = "bincode")]
#[strum(serialize = "bincode")]
Bincode,
#[cfg(feature = "json")]
#[strum(serialize = "json")]
Json,
#[cfg(feature = "postcard")]
#[strum(serialize = "postcard")]
Postcard,
}
#[async_trait::async_trait]
pub trait DataEncoder:
serde::Serialize
+ serde::de::DeserializeOwned
+ Clone
+ Send
+ Sync
+ Debug
+ std::marker::Sized
{
type Err: std::error::Error + From<DataParserError>;
fn data_parser() -> DataParser {
DataParser::default()
}
async fn encode(&self) -> Result<Vec<u8>, Self::Err> {
Self::data_parser().encode(self).await.map_err(Into::into)
}
#[cfg(feature = "json")]
fn encode_json(&self) -> Result<Vec<u8>, Self::Err> {
Self::data_parser().encode_json(self).map_err(Into::into)
}
async fn decode(encoded: &[u8]) -> Result<Self, Self::Err> {
Self::data_parser()
.decode(encoded)
.await
.map_err(Into::into)
}
#[cfg(feature = "json")]
fn decode_json(encoded: &[u8]) -> Result<Self, Self::Err> {
Self::data_parser().decode_json(encoded).map_err(Into::into)
}
#[cfg(feature = "json")]
fn to_json_value(&self) -> Result<serde_json::Value, Self::Err> {
Self::data_parser().to_json_value(self).map_err(Into::into)
}
}
#[derive(Clone)]
pub struct DataParser {
compression_strategy: Option<Arc<dyn CompressionStrategy>>,
pub serialization_type: SerializationType,
}
impl Default for DataParser {
fn default() -> Self {
Self {
compression_strategy: None,
serialization_type: SerializationType::Json,
}
}
}
impl DataParser {
pub fn with_compression_strategy(
mut self,
compression_strategy: &Arc<dyn CompressionStrategy>,
) -> Self {
self.compression_strategy = Some(compression_strategy.clone());
self
}
pub fn with_serialization_type(
mut self,
serialization_type: SerializationType,
) -> Self {
self.serialization_type = serialization_type;
self
}
pub async fn encode<T: DataEncoder>(
&self,
data: &T,
) -> Result<Vec<u8>, DataParserError> {
let serialized_data = self.serialize(data).await?;
Ok(match &self.compression_strategy {
Some(strategy) => strategy.compress(&serialized_data[..]).await?,
None => serialized_data,
})
}
#[cfg(feature = "json")]
pub fn encode_json<T: DataEncoder>(
&self,
data: &T,
) -> Result<Vec<u8>, DataParserError> {
self.serialize_json(data)
}
#[cfg(feature = "json")]
pub fn to_json_value<T: serde::Serialize>(
&self,
data: &T,
) -> Result<serde_json::Value, DataParserError> {
self.serialize_json_value(data)
}
pub async fn serialize<T: DataEncoder>(
&self,
raw_data: &T,
) -> Result<Vec<u8>, DataParserError> {
match self.serialization_type {
#[cfg(feature = "bincode")]
SerializationType::Bincode => bincode::serialize(&raw_data)
.map_err(|e| DataParserError::Encode(SerdeError::Bincode(*e))),
#[cfg(feature = "json")]
SerializationType::Json => serde_json::to_vec(&raw_data)
.map_err(|e| DataParserError::EncodeJson(SerdeError::Json(e))),
#[cfg(feature = "postcard")]
SerializationType::Postcard => postcard::to_allocvec(&raw_data)
.map_err(|e| DataParserError::Encode(SerdeError::Postcard(e))),
}
}
#[cfg(feature = "json")]
fn serialize_json<T: DataEncoder>(
&self,
raw_data: &T,
) -> Result<Vec<u8>, DataParserError> {
serde_json::to_vec(&raw_data)
.map_err(|e| DataParserError::EncodeJson(SerdeError::Json(e)))
}
#[cfg(feature = "json")]
fn serialize_json_value<T: serde::Serialize>(
&self,
raw_data: &T,
) -> Result<serde_json::Value, DataParserError> {
serde_json::to_value(raw_data)
.map_err(|e| DataParserError::EncodeJson(SerdeError::Json(e)))
}
pub async fn decode<T: DataEncoder>(
&self,
data: &[u8],
) -> Result<T, DataParserError> {
let data = match &self.compression_strategy {
Some(strategy) => strategy.decompress(data).await?,
None => data.to_vec(),
};
let decoded_data = self.deserialize(&data[..])?;
Ok(decoded_data)
}
#[cfg(feature = "json")]
pub fn decode_json<T: DataEncoder>(
&self,
data: &[u8],
) -> Result<T, DataParserError> {
self.deserialize_json(data)
}
pub fn deserialize<T: DeserializeOwned>(
&self,
raw_data: &[u8],
) -> Result<T, DataParserError> {
match self.serialization_type {
#[cfg(feature = "bincode")]
SerializationType::Bincode => bincode::deserialize(raw_data)
.map_err(|e| DataParserError::Decode(SerdeError::Bincode(*e))),
#[cfg(feature = "json")]
SerializationType::Json => self.deserialize_json(raw_data),
#[cfg(feature = "postcard")]
SerializationType::Postcard => postcard::from_bytes(raw_data)
.map_err(|e| DataParserError::Decode(SerdeError::Postcard(e))),
}
}
#[cfg(feature = "json")]
fn deserialize_json<T: DeserializeOwned>(
&self,
raw_data: &[u8],
) -> Result<T, DataParserError> {
serde_json::from_slice(raw_data)
.map_err(|e| DataParserError::DecodeJson(SerdeError::Json(e)))
}
}
#[cfg(test)]
mod tests {
use pretty_assertions::assert_eq;
use super::*;
#[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq)]
struct TestData {
field: String,
}
impl DataEncoder for TestData {
type Err = DataParserError;
}
#[tokio::test]
async fn test_encode_decode() {
let parser = DataParser::default();
let original_data = TestData {
field: "test".to_string(),
};
let encoded = parser.encode(&original_data).await.unwrap();
let decoded: TestData = parser.decode(&encoded).await.unwrap();
assert_eq!(original_data, decoded);
}
#[tokio::test]
async fn test_serialization_types() {
let data = TestData {
field: "test".to_string(),
};
for serialization_type in [
#[cfg(feature = "bincode")]
SerializationType::Bincode,
#[cfg(feature = "postcard")]
SerializationType::Postcard,
#[cfg(feature = "json")]
SerializationType::Json,
] {
let parser = DataParser::default()
.with_serialization_type(serialization_type);
let encoded = parser.encode(&data).await.unwrap();
let decoded: TestData = parser.decode(&encoded).await.unwrap();
assert_eq!(data, decoded);
}
}
#[tokio::test]
async fn test_compression_strategies() {
let data = TestData {
field: "test".to_string(),
};
for strategy in ALL_COMPRESSION_STRATEGIES.iter() {
let parser =
DataParser::default().with_compression_strategy(strategy);
let encoded = parser.encode(&data).await.unwrap();
let decoded: TestData = parser.decode(&encoded).await.unwrap();
assert_eq!(data, decoded);
}
}
}