use std::sync::Arc;
use bytes::Bytes;
use crabka_schema_serde::format::{SchemaDeserializer, SchemaSerializer};
use crate::error::ConnectError;
pub trait Converter<T>: Send + Sync + 'static {
fn serialize(&self, topic: &str, value: &T) -> Result<Bytes, ConnectError>;
fn deserialize(&self, topic: &str, bytes: &[u8]) -> Result<T, ConnectError>;
}
#[derive(Debug, Clone, Copy, Default)]
pub struct ByteIdentity;
impl Converter<Bytes> for ByteIdentity {
fn serialize(&self, _topic: &str, value: &Bytes) -> Result<Bytes, ConnectError> {
Ok(value.clone())
}
fn deserialize(&self, _topic: &str, bytes: &[u8]) -> Result<Bytes, ConnectError> {
Ok(Bytes::copy_from_slice(bytes))
}
}
pub struct SchemaConverter<T> {
serializer: Arc<dyn SchemaSerializer<T>>,
deserializer: Arc<dyn SchemaDeserializer<T>>,
}
impl<T> SchemaConverter<T> {
pub fn new(
serializer: Arc<dyn SchemaSerializer<T>>,
deserializer: Arc<dyn SchemaDeserializer<T>>,
) -> Self {
Self {
serializer,
deserializer,
}
}
}
impl<T: Send + Sync + 'static> Converter<T> for SchemaConverter<T> {
fn serialize(&self, topic: &str, value: &T) -> Result<Bytes, ConnectError> {
self.serializer
.serialize(topic, value)
.map_err(|e| ConnectError::Convert(e.to_string()))
}
fn deserialize(&self, topic: &str, bytes: &[u8]) -> Result<T, ConnectError> {
self.deserializer
.deserialize(topic, bytes)
.map_err(|e| ConnectError::Convert(e.to_string()))
}
}
#[cfg(test)]
mod tests {
use super::*;
use assert2::check;
use crabka_schema_serde::SchemaSerdeError;
struct FakeSerde;
impl SchemaSerializer<String> for FakeSerde {
fn serialize(&self, topic: &str, value: &String) -> Result<Bytes, SchemaSerdeError> {
Ok(Bytes::from(format!("{topic}:{value}")))
}
}
impl SchemaDeserializer<String> for FakeSerde {
fn deserialize(&self, _topic: &str, bytes: &[u8]) -> Result<String, SchemaSerdeError> {
String::from_utf8(bytes.to_vec()).map_err(|e| SchemaSerdeError::Wire(e.to_string()))
}
}
#[test]
fn schema_converter_serialize_forwards_to_inner_serde() {
let conv = SchemaConverter::new(Arc::new(FakeSerde), Arc::new(FakeSerde));
let out = conv.serialize("topic", &"hello".to_owned()).unwrap();
check!(out == Bytes::from_static(b"topic:hello"));
}
#[test]
fn schema_converter_deserialize_forwards_to_inner_serde() {
let conv = SchemaConverter::new(Arc::new(FakeSerde), Arc::new(FakeSerde));
let value = conv.deserialize("topic", b"world").unwrap();
check!(value == "world");
}
#[test]
fn byte_identity_serialize_preserves_bytes() {
let c = ByteIdentity;
let v = Bytes::from_static(b"\x00\x01\xff payload");
let out = c.serialize("t", &v).unwrap();
check!(out == v);
}
#[test]
fn byte_identity_round_trips() {
let c = ByteIdentity;
let original = b"\xde\xad\xbe\xef";
let decoded = c.deserialize("t", original).unwrap();
let encoded = c.serialize("t", &decoded).unwrap();
check!(encoded.as_ref() == original);
}
}