use base64::Engine;
use serde::{Deserialize, Serialize};
use std::fmt;
use std::io::{Read, Write};
use std::marker::PhantomData;
use thiserror::Error;
use tokio::io::{AsyncRead, AsyncReadExt, AsyncWrite, AsyncWriteExt};
use tokio::sync::mpsc::{Receiver, Sender, channel};
use uuid::Uuid;
#[derive(Debug, Error)]
pub enum MessageError {
#[error("JSON serialization error: {0}")]
JsonSerializationError(#[from] serde_json::Error),
#[error("binary conversion error: {0}")]
BinaryConversionError(#[from] bincode::error::EncodeError),
#[error("binary decoding error: {0}")]
BinaryDecodingError(#[from] bincode::error::DecodeError),
#[error("Base64 encoding error: {0}")]
Base64EncodingError(String),
#[error("Base64 decoding error: {0}")]
Base64DecodingError(#[from] base64::DecodeError),
#[error("unsupported encoding format: {0}")]
UnsupportedFormat(EncodingFormat),
#[error("message has no content")]
NoContent,
#[error("invalid message format: {0}")]
InvalidFormat(String),
#[error("I/O error: {0}")]
IoError(#[from] std::io::Error),
}
pub type MessageResult<T> = Result<T, MessageError>;
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Message<T> {
pub id: Uuid,
pub content: T,
#[serde(default)]
pub metadata: MessageMetadata,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct MessageMetadata {
#[serde(skip_serializing_if = "Option::is_none")]
pub id: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub timestamp: Option<i64>,
#[serde(skip_serializing_if = "Option::is_none")]
pub source: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub destination: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub properties: Option<serde_json::Map<String, serde_json::Value>>,
}
impl MessageMetadata {
pub fn new() -> Self {
Self {
id: None,
timestamp: None,
source: None,
destination: None,
properties: None,
}
}
pub fn with_id<S: Into<String>>(mut self, id: S) -> Self {
self.id = Some(id.into());
self
}
pub fn with_timestamp(mut self, timestamp: i64) -> Self {
self.timestamp = Some(timestamp);
self
}
pub fn with_source<S: Into<String>>(mut self, source: S) -> Self {
self.source = Some(source.into());
self
}
pub fn with_destination<S: Into<String>>(mut self, destination: S) -> Self {
self.destination = Some(destination.into());
self
}
pub fn with_property<S: Into<String>, V: Serialize>(
mut self,
key: S,
value: V,
) -> MessageResult<Self> {
let value = serde_json::to_value(value).map_err(MessageError::JsonSerializationError)?;
if self.properties.is_none() {
self.properties = Some(serde_json::Map::new());
}
if let Some(props) = &mut self.properties {
props.insert(key.into(), value);
}
Ok(self)
}
}
impl Default for MessageMetadata {
fn default() -> Self {
Self::new()
}
}
impl<T> Message<T> {
pub fn new(content: T) -> Self {
Self {
id: Uuid::new_v4(),
content,
metadata: Default::default(),
}
}
pub fn with_metadata(content: T, metadata: MessageMetadata) -> Self {
Self {
id: Uuid::new_v4(),
content,
metadata,
}
}
pub fn content(&self) -> &T {
&self.content
}
pub fn content_mut(&mut self) -> &mut T {
&mut self.content
}
pub fn metadata(&self) -> Option<&MessageMetadata> {
Some(&self.metadata)
}
pub fn metadata_mut(&mut self) -> &mut MessageMetadata {
&mut self.metadata
}
pub fn set_metadata(&mut self, metadata: MessageMetadata) {
self.metadata = metadata;
}
pub fn ensure_metadata(&mut self) -> &mut MessageMetadata {
&mut self.metadata
}
pub fn encode(self) -> MessageResult<EncodedMessage>
where
T: Serialize,
{
EncodedMessage::from_message(self)
}
pub fn to_string(&self) -> MessageResult<String>
where
T: Serialize,
{
serde_json::to_string(self).map_err(MessageError::JsonSerializationError)
}
pub fn to_string_pretty(&self) -> MessageResult<String>
where
T: Serialize,
{
serde_json::to_string_pretty(self).map_err(MessageError::JsonSerializationError)
}
pub fn to_bytes(&self) -> MessageResult<Vec<u8>>
where
T: Serialize + bincode::Encode,
{
let config = bincode::config::standard();
bincode::encode_to_vec(self, config).map_err(MessageError::BinaryConversionError)
}
pub fn into_payload(self) -> T {
self.content
}
}
#[derive(Serialize, Deserialize, Debug, Clone, bincode::Encode, bincode::Decode)]
struct WireMessage {
kind: String, }
#[derive(Serialize, Deserialize, Debug, Clone, Default, bincode::Encode, bincode::Decode)]
struct EmptyStruct;
fn bincode_config() -> bincode::config::Configuration {
bincode::config::standard()
}
#[derive(Debug, Clone)]
pub struct EncodedMessage {
data: Vec<u8>,
format: EncodingFormat,
}
impl Serialize for EncodedMessage {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
#[derive(Serialize)]
struct EncodedMessageSer<'a> {
data: &'a [u8],
format: EncodingFormat,
}
let ser = EncodedMessageSer {
data: &self.data,
format: self.format,
};
ser.serialize(serializer)
}
}
impl<'de> Deserialize<'de> for EncodedMessage {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: serde::Deserializer<'de>,
{
#[derive(Deserialize)]
struct EncodedMessageDe {
data: Vec<u8>,
format: EncodingFormat,
}
let de = EncodedMessageDe::deserialize(deserializer)?;
Ok(EncodedMessage {
data: de.data,
format: de.format,
})
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Default)]
pub enum EncodingFormat {
#[default]
Json,
Binary,
Base64,
Auto,
}
impl fmt::Display for EncodingFormat {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
EncodingFormat::Json => write!(f, "json"),
EncodingFormat::Binary => write!(f, "binary"),
EncodingFormat::Base64 => write!(f, "base64"),
EncodingFormat::Auto => write!(f, "auto"),
}
}
}
impl EncodedMessage {
pub fn new(data: Vec<u8>, format: EncodingFormat) -> Self {
Self { data, format }
}
pub fn from_message<T>(message: Message<T>) -> MessageResult<Self>
where
T: Serialize,
{
let data = serde_json::to_vec(&message).map_err(MessageError::JsonSerializationError)?;
Ok(Self {
data,
format: EncodingFormat::Json,
})
}
pub fn from_message_binary<T>(message: Message<T>) -> MessageResult<Self>
where
T: Serialize + bincode::Encode,
{
let config = bincode::config::standard();
let data = bincode::encode_to_vec(&message, config).map_err(MessageError::BinaryConversionError)?;
Ok(Self {
data,
format: EncodingFormat::Binary,
})
}
pub fn from_message_base64<T>(message: Message<T>) -> MessageResult<Self>
where
T: Serialize + bincode::Encode,
{
let config = bincode::config::standard();
let binary = bincode::encode_to_vec(&message, config).map_err(MessageError::BinaryConversionError)?;
let data = base64::engine::general_purpose::STANDARD
.encode(binary)
.into_bytes();
Ok(Self {
data,
format: EncodingFormat::Base64,
})
}
pub fn data(&self) -> &[u8] {
&self.data
}
pub fn format(&self) -> EncodingFormat {
self.format
}
pub fn decode<T>(&self) -> MessageResult<T>
where
T: for<'de> Deserialize<'de> + bincode::Decode<()>,
{
match self.format {
EncodingFormat::Json => {
if let Ok(message) = serde_json::from_slice::<Message<T>>(&self.data) {
return Ok(message.content);
}
serde_json::from_slice(&self.data).map_err(MessageError::JsonSerializationError)
}
EncodingFormat::Binary => {
let config = bincode::config::standard();
match bincode::decode_from_slice::<Message<T>, _>(&self.data, config) {
Ok((message, _)) => Ok(message.content),
Err(_) => {
let (value, _) = bincode::decode_from_slice(&self.data, config)
.map_err(MessageError::BinaryDecodingError)?;
Ok(value)
}
}
}
EncodingFormat::Base64 => {
let binary = base64::engine::general_purpose::STANDARD
.decode(&self.data)
.map_err(MessageError::Base64DecodingError)?;
let config = bincode::config::standard();
match bincode::decode_from_slice::<Message<T>, _>(&binary, config) {
Ok((message, _)) => Ok(message.content),
Err(_e) => {
let (value, _) = bincode::decode_from_slice(&binary, config)
.map_err(MessageError::BinaryDecodingError)?;
Ok(value)
}
}
}
EncodingFormat::Auto => {
serde_json::from_slice(&self.data).map_err(MessageError::JsonSerializationError)
}
}
}
pub fn decode_full<T>(&self) -> MessageResult<Message<T>>
where
T: for<'de> Deserialize<'de> + bincode::Decode<()>,
{
match self.format {
EncodingFormat::Json => {
serde_json::from_slice(&self.data).map_err(MessageError::JsonSerializationError)
}
EncodingFormat::Binary => {
let config = bincode::config::standard();
let (message, _) =
bincode::decode_from_slice(&self.data, config).map_err(MessageError::BinaryDecodingError)?;
Ok(message)
}
EncodingFormat::Base64 => {
let binary = base64::engine::general_purpose::STANDARD
.decode(&self.data)
.map_err(MessageError::Base64DecodingError)?;
let config = bincode::config::standard();
let (message, _) =
bincode::decode_from_slice(&binary, config).map_err(MessageError::BinaryDecodingError)?;
Ok(message)
}
EncodingFormat::Auto => {
serde_json::from_slice(&self.data).map_err(MessageError::JsonSerializationError)
}
}
}
pub fn to_string(&self) -> MessageResult<String> {
match self.format {
EncodingFormat::Json => String::from_utf8(self.data.clone())
.map_err(|e| MessageError::InvalidFormat(e.to_string())),
EncodingFormat::Binary => Err(MessageError::UnsupportedFormat(self.format)),
EncodingFormat::Base64 => String::from_utf8(self.data.clone())
.map_err(|e| MessageError::InvalidFormat(e.to_string())),
EncodingFormat::Auto => Err(MessageError::UnsupportedFormat(self.format)),
}
}
pub fn to_format(&self, format: EncodingFormat) -> MessageResult<Self> {
if self.format == format {
return Ok(self.clone());
}
if format == EncodingFormat::Auto {
return Err(MessageError::UnsupportedFormat(self.format));
}
match (self.format, format) {
(EncodingFormat::Auto, _) => {
Err(MessageError::UnsupportedFormat(self.format))
}
(EncodingFormat::Json, EncodingFormat::Binary) => {
let json_str = std::str::from_utf8(&self.data)
.map_err(|e| MessageError::InvalidFormat(format!("Invalid UTF-8: {}", e)))?;
Ok(Self {
data: json_str.as_bytes().to_vec(),
format: EncodingFormat::Binary,
})
},
(EncodingFormat::Json, EncodingFormat::Base64) => {
let base64_data = base64::engine::general_purpose::STANDARD
.encode(&self.data)
.into_bytes();
Ok(Self {
data: base64_data,
format: EncodingFormat::Base64,
})
}
(EncodingFormat::Binary, EncodingFormat::Json) => {
match serde_json::from_slice::<serde_json::Value>(&self.data) {
Ok(value) => {
let json = serde_json::to_vec(&value).map_err(MessageError::JsonSerializationError)?;
Ok(Self {
data: json,
format: EncodingFormat::Json,
})
}
Err(_) => {
Err(MessageError::InvalidFormat("Cannot convert binary data to JSON. The binary data is not valid JSON.".to_string()))
}
}
}
(EncodingFormat::Binary, EncodingFormat::Base64) => {
let base64_data = base64::engine::general_purpose::STANDARD
.encode(&self.data)
.into_bytes();
Ok(Self {
data: base64_data,
format: EncodingFormat::Base64,
})
}
(EncodingFormat::Base64, EncodingFormat::Json) => {
let binary = base64::engine::general_purpose::STANDARD
.decode(&self.data)
.map_err(MessageError::Base64DecodingError)?;
match serde_json::from_slice::<serde_json::Value>(&binary) {
Ok(value) => {
let json = serde_json::to_vec(&value).map_err(MessageError::JsonSerializationError)?;
Ok(Self {
data: json,
format: EncodingFormat::Json,
})
}
Err(_) => Err(MessageError::InvalidFormat("The base64-decoded data is not valid JSON".to_string())),
}
}
(EncodingFormat::Base64, EncodingFormat::Binary) => {
let binary = base64::engine::general_purpose::STANDARD
.decode(&self.data)
.map_err(MessageError::Base64DecodingError)?;
Ok(Self {
data: binary,
format: EncodingFormat::Binary,
})
}
_ => unreachable!(), }
}
pub fn write_to<W: Write>(&self, writer: &mut W) -> MessageResult<()> {
if self.format == EncodingFormat::Auto {
return Err(MessageError::UnsupportedFormat(self.format));
}
let len = self.data.len() as u32;
writer.write_all(&len.to_be_bytes())?;
let format_code = match self.format {
EncodingFormat::Json => 1u8,
EncodingFormat::Binary => 2u8,
EncodingFormat::Base64 => 3u8,
EncodingFormat::Auto => 0u8, };
writer.write_all(&[format_code])?;
writer.write_all(&self.data)?;
writer.flush()?;
Ok(())
}
pub fn read_from<R: Read>(reader: &mut R) -> MessageResult<Self> {
let mut len_bytes = [0u8; 4];
reader.read_exact(&mut len_bytes)?;
let len = u32::from_be_bytes(len_bytes) as usize;
let mut format_byte = [0u8; 1];
reader.read_exact(&mut format_byte)?;
let format = match format_byte[0] {
0 => EncodingFormat::Auto, 1 => EncodingFormat::Json,
2 => EncodingFormat::Binary,
3 => EncodingFormat::Base64,
_ => return Err(MessageError::InvalidFormat("Invalid format code".to_string())),
};
if format == EncodingFormat::Auto {
return Err(MessageError::UnsupportedFormat(format));
}
let mut data = vec![0u8; len];
reader.read_exact(&mut data)?;
Ok(Self { data, format })
}
pub async fn write_to_async<W: AsyncWrite + Unpin>(&self, writer: &mut W) -> MessageResult<()> {
if self.format == EncodingFormat::Auto {
return Err(MessageError::UnsupportedFormat(self.format));
}
let len = self.data.len() as u32;
writer.write_all(&len.to_be_bytes()).await?;
let format_code = match self.format {
EncodingFormat::Json => 1u8,
EncodingFormat::Binary => 2u8,
EncodingFormat::Base64 => 3u8,
EncodingFormat::Auto => 0u8, };
writer.write_all(&[format_code]).await?;
writer.write_all(&self.data).await?;
writer.flush().await?;
Ok(())
}
pub async fn read_from_async<R: AsyncRead + Unpin>(reader: &mut R) -> MessageResult<Self> {
let mut len_bytes = [0u8; 4];
reader.read_exact(&mut len_bytes).await?;
let len = u32::from_be_bytes(len_bytes) as usize;
let mut format_byte = [0u8; 1];
reader.read_exact(&mut format_byte).await?;
let format = match format_byte[0] {
0 => EncodingFormat::Auto, 1 => EncodingFormat::Json,
2 => EncodingFormat::Binary,
3 => EncodingFormat::Base64,
_ => return Err(MessageError::InvalidFormat("Invalid format code".to_string())),
};
if format == EncodingFormat::Auto {
return Err(MessageError::UnsupportedFormat(format));
}
let mut data = vec![0u8; len];
reader.read_exact(&mut data).await?;
Ok(Self { data, format })
}
pub fn peek_kind(&self) -> MessageResult<String> {
const DEFAULT_KIND: &str = "Unknown";
match self.format {
EncodingFormat::Json => {
match serde_json::from_slice::<WireMessage>(&self.data) {
Ok(wire_message) => Ok(wire_message.kind),
Err(e) => {
match serde_json::from_slice::<serde_json::Value>(&self.data) {
Ok(value) => {
if let Some(obj) = value.as_object() {
if let Some(op_val) = obj.get("op") {
if let Some(op_str) = op_val.as_str() {
return Ok(op_str.to_string());
}
}
if let Some(metadata) = obj.get("metadata") {
if let Some(metadata_obj) = metadata.as_object() {
if let Some(id_val) = metadata_obj.get("id") {
if let Some(id_str) = id_val.as_str() {
eprintln!("[DEBUG peek_kind/JSON] Found metadata.id: '{}'", id_str);
return Ok(id_str.to_string());
}
}
}
}
}
eprintln!(
"peek_kind (JSON): WireMessage decode failed, metadata.id not found. Error: {:?}. Data (first 100 bytes): {:?}",
e, &self.data.iter().take(100).collect::<Vec<&u8>>()
);
Ok(DEFAULT_KIND.to_string())
}
Err(json_err) => {
eprintln!(
"peek_kind (JSON): Failed to decode as WireMessage or generic JSON. WireMessage Error: {:?}, JSON Error: {:?}. Data (first 64 bytes): {:?}",
e, json_err, &self.data.iter().take(64).collect::<Vec<&u8>>());
Ok("Invalid JSON".to_string())
}
}
}
}
}
EncodingFormat::Binary => {
let data_to_decode = &self.data;
match bincode::decode_from_slice::<Message<EmptyStruct>, _>(data_to_decode, bincode_config()) {
Ok((decoded_message, _)) => {
if let Some(id) = decoded_message.metadata.id {
eprintln!("[DEBUG peek_kind/Binary] Successfully decoded Message<EmptyStruct>. ID: '{}'", id);
return Ok(id);
}
eprintln!("[DEBUG peek_kind/Binary] Decoded Message<EmptyStruct> but no id in metadata. Message: {:?}", decoded_message);
Ok("Unknown".to_string())
}
Err(e) => {
eprintln!("[DEBUG peek_kind/Binary] Failed to decode Message<EmptyStruct>: {}. Raw data (first 100 bytes): {:?}", e, &data_to_decode[..std::cmp::min(100, data_to_decode.len())]);
Ok("Unknown".to_string())
}
}
}
EncodingFormat::Base64 => {
match base64::engine::general_purpose::STANDARD.decode(&self.data) {
Ok(decoded_base64_data) => {
let decoded_bytes = decoded_base64_data;
match bincode::decode_from_slice::<Message<EmptyStruct>, _>(&decoded_bytes, bincode_config()) {
Ok((decoded_message, _)) => {
if let Some(id) = decoded_message.metadata.id {
eprintln!("[DEBUG peek_kind/Base64] Successfully decoded Message<EmptyStruct>. ID: '{}'", id);
return Ok(id);
}
eprintln!("[DEBUG peek_kind/Base64] Decoded Message<EmptyStruct> but no id in metadata. Message: {:?}", decoded_message);
Ok("Unknown".to_string())
}
Err(e) => {
eprintln!("[DEBUG peek_kind/Base64] Failed to decode Message<EmptyStruct> from base64 decoded data: {}. Raw base64 data (first 100 chars): {:?}. Decoded bytes (first 100): {:?}", e, String::from_utf8_lossy(&self.data[..std::cmp::min(100, self.data.len())]), &decoded_bytes[..std::cmp::min(100, decoded_bytes.len())]);
Ok("Unknown".to_string())
}
}
}
Err(e) => {
eprintln!(
"peek_kind (Base64): Failed to decode from Base64. Error: {:?}. Original Data (first 64 bytes): {:?}",
e, &self.data.iter().take(64).collect::<Vec<&u8>>());
Ok("Invalid Base64".to_string())
}
}
}
EncodingFormat::Auto => {
Err(MessageError::UnsupportedFormat(EncodingFormat::Auto))
}
}
}
pub fn encode_with_format<T>(message: &Message<T>, format: EncodingFormat) -> MessageResult<Self>
where
T: Serialize + Clone,
{
let message_clone = Message {
id: message.id,
content: message.content.clone(),
metadata: message.metadata.clone(),
};
match format {
EncodingFormat::Binary | EncodingFormat::Base64 | EncodingFormat::Json | EncodingFormat::Auto => {
Self::from_message(message_clone)
}
}
}
}
pub struct EncodedStream<T> {
sender: Option<Sender<MessageResult<EncodedMessage>>>,
receiver: Option<Receiver<MessageResult<EncodedMessage>>>,
_marker: PhantomData<T>,
}
impl<T> EncodedStream<T> {
pub fn new() -> Self {
let (sender, receiver) = channel(100);
Self {
sender: Some(sender),
receiver: Some(receiver),
_marker: PhantomData,
}
}
pub fn sender(&self) -> Option<Sender<MessageResult<EncodedMessage>>> {
self.sender.clone()
}
pub async fn send(&self, message: Message<T>) -> MessageResult<()>
where
T: Serialize + bincode::Encode,
{
let encoded = message.encode()?;
if let Some(sender) = &self.sender {
sender
.send(Ok(encoded))
.await
.map_err(|_| MessageError::UnsupportedFormat(EncodingFormat::Auto))?;
Ok(())
} else {
Err(MessageError::UnsupportedFormat(EncodingFormat::Auto))
}
}
pub async fn send_encoded(&self, message: EncodedMessage) -> MessageResult<()> {
if let Some(sender) = &self.sender {
sender
.send(Ok(message))
.await
.map_err(|_| MessageError::UnsupportedFormat(EncodingFormat::Auto))?;
Ok(())
} else {
Err(MessageError::UnsupportedFormat(EncodingFormat::Auto))
}
}
pub async fn send_error(&self, error: MessageError) -> MessageResult<()> {
if let Some(sender) = &self.sender {
sender
.send(Err(error))
.await
.map_err(|_| MessageError::UnsupportedFormat(EncodingFormat::Auto))?;
Ok(())
} else {
Err(MessageError::UnsupportedFormat(EncodingFormat::Auto))
}
}
pub fn receiver(&mut self) -> Option<Receiver<MessageResult<EncodedMessage>>> {
self.receiver.take()
}
pub fn split(
self,
) -> (
Sender<MessageResult<EncodedMessage>>,
Receiver<MessageResult<EncodedMessage>>,
) {
(self.sender.unwrap(), self.receiver.unwrap())
}
pub async fn from_reader<R: AsyncRead + Unpin + Send + 'static>(reader: R) -> Self {
let (sender, receiver) = channel(100);
let sender_clone = sender.clone();
tokio::spawn(async move {
let mut reader = reader;
loop {
match EncodedMessage::read_from_async(&mut reader).await {
Ok(message) => {
if sender_clone.send(Ok(message)).await.is_err() {
break;
}
}
Err(e) => {
let _ = sender_clone.send(Err(e)).await;
break;
}
}
}
});
Self {
sender: Some(sender),
receiver: Some(receiver),
_marker: PhantomData,
}
}
pub fn to_writer<W: AsyncWrite + Unpin + Send + 'static>(
&mut self,
writer: W,
) -> MessageResult<()> {
let mut receiver = self.receiver.take().ok_or(MessageError::UnsupportedFormat(EncodingFormat::Auto))?;
tokio::spawn(async move {
let mut writer = writer;
while let Some(message_result) = receiver.recv().await {
match message_result {
Ok(message) => {
if let Err(e) = message.write_to_async(&mut writer).await {
eprintln!("Error writing message: {}", e);
break;
}
}
Err(e) => {
eprintln!("Error in message stream: {}", e);
break;
}
}
}
});
Ok(())
}
}
impl<T> Default for EncodedStream<T> {
fn default() -> Self {
Self::new()
}
}
impl<T: bincode::Encode> bincode::Encode for Message<T> {
fn encode<E: bincode::enc::Encoder>(
&self,
encoder: &mut E,
) -> Result<(), bincode::error::EncodeError> {
bincode::Encode::encode(&self.content, encoder)?;
bincode::Encode::encode(&self.metadata, encoder)?;
Ok(())
}
}
impl<T: bincode::Decode<()>> bincode::Decode<()> for Message<T> {
fn decode<D: bincode::de::Decoder<Context = ()>>(
decoder: &mut D,
) -> Result<Self, bincode::error::DecodeError> {
let content = T::decode(decoder)?;
let metadata = Option::<MessageMetadata>::decode(decoder)?;
Ok(Message {
id: Uuid::new_v4(),
content,
metadata: metadata.unwrap_or_default()
})
}
}
impl bincode::Encode for MessageMetadata {
fn encode<E: bincode::enc::Encoder>(
&self,
encoder: &mut E,
) -> Result<(), bincode::error::EncodeError> {
bincode::Encode::encode(&self.id, encoder)?;
bincode::Encode::encode(&self.timestamp, encoder)?;
bincode::Encode::encode(&self.source, encoder)?;
bincode::Encode::encode(&self.destination, encoder)?;
let props_str = match &self.properties {
Some(props) => serde_json::to_string(props).unwrap_or_default(),
None => String::new(),
};
bincode::Encode::encode(&props_str, encoder)?;
Ok(())
}
}
impl bincode::Decode<()> for MessageMetadata {
fn decode<D: bincode::de::Decoder<Context = ()>>(
decoder: &mut D,
) -> Result<Self, bincode::error::DecodeError> {
let id = Option::<String>::decode(decoder)?;
let timestamp = Option::<i64>::decode(decoder)?;
let source = Option::<String>::decode(decoder)?;
let destination = Option::<String>::decode(decoder)?;
let props_str = String::decode(decoder)?;
let properties = if !props_str.is_empty() {
serde_json::from_str(&props_str).ok()
} else {
None
};
Ok(MessageMetadata {
id,
timestamp,
source,
destination,
properties,
})
}
}
#[cfg(test)]
mod tests {
use super::*;
use serde::{Deserialize, Serialize};
use std::io::Cursor;
#[derive(Debug, Serialize, Deserialize, PartialEq, Clone)]
struct TestData {
name: String,
value: i32,
}
impl bincode::Encode for TestData {
fn encode<E: bincode::enc::Encoder>(
&self,
encoder: &mut E,
) -> Result<(), bincode::error::EncodeError> {
bincode::Encode::encode(&self.name, encoder)?;
bincode::Encode::encode(&self.value, encoder)?;
Ok(())
}
}
impl bincode::Decode<()> for TestData {
fn decode<D: bincode::de::Decoder<Context = ()>>(
decoder: &mut D,
) -> Result<Self, bincode::error::DecodeError> {
let name = String::decode(decoder)?;
let value = i32::decode(decoder)?;
Ok(TestData { name, value })
}
}
#[test]
fn test_message_encode_decode() {
let data = TestData {
name: "test".to_string(),
value: 42,
};
let message = Message::new(data);
let encoded = message.encode().unwrap();
let decoded: TestData = encoded.decode().unwrap();
assert_eq!(decoded.name, "test");
assert_eq!(decoded.value, 42);
}
#[test]
fn test_message_with_metadata() {
let data = TestData {
name: "test".to_string(),
value: 42,
};
let metadata = MessageMetadata::new()
.with_id("msg1")
.with_source("test-source");
let message = Message::with_metadata(data, metadata);
let encoded = message.encode().unwrap();
let full_message: Message<TestData> = encoded.decode_full().unwrap();
assert_eq!(full_message.content().name, "test");
assert_eq!(full_message.content().value, 42);
assert_eq!(full_message.metadata().unwrap().id.as_deref(), Some("msg1"));
assert_eq!(
full_message.metadata().unwrap().source.as_deref(),
Some("test-source")
);
}
#[test]
fn test_encoding_formats() {
let data = TestData {
name: "test".to_string(),
value: 42,
};
let message = Message::new(data);
let json_encoded = message.clone().encode().unwrap();
assert_eq!(json_encoded.format(), EncodingFormat::Json);
let decoded_from_json: TestData = json_encoded.decode().unwrap();
assert_eq!(decoded_from_json.name, "test");
assert_eq!(decoded_from_json.value, 42);
let binary_encoded = EncodedMessage::from_message_binary(message.clone()).unwrap();
assert_eq!(binary_encoded.format(), EncodingFormat::Binary);
let decoded_from_binary: TestData = binary_encoded.decode().unwrap();
assert_eq!(decoded_from_binary.name, "test");
assert_eq!(decoded_from_binary.value, 42);
let base64_encoded = EncodedMessage::from_message_base64(message.clone()).unwrap();
assert_eq!(base64_encoded.format(), EncodingFormat::Base64);
let decoded_from_base64: TestData = base64_encoded.decode().unwrap();
assert_eq!(decoded_from_base64.name, "test");
assert_eq!(decoded_from_base64.value, 42);
}
#[test]
fn test_format_conversion() {
let data1 = TestData {
name: "test".to_string(),
value: 42,
};
let message1 = Message::new(data1);
let json_encoded = EncodedMessage::from_message(message1).unwrap();
assert_eq!(json_encoded.format(), EncodingFormat::Json);
let decoded_json: TestData = json_encoded.decode().unwrap();
assert_eq!(decoded_json.name, "test");
assert_eq!(decoded_json.value, 42);
let data2 = TestData {
name: "test".to_string(),
value: 42,
};
let message2 = Message::new(data2);
let binary_encoded = EncodedMessage::from_message_binary(message2).unwrap();
assert_eq!(binary_encoded.format(), EncodingFormat::Binary);
let decoded_binary: TestData = binary_encoded.decode().unwrap();
assert_eq!(decoded_binary.name, "test");
assert_eq!(decoded_binary.value, 42);
let data3 = TestData {
name: "test".to_string(),
value: 42,
};
let message3 = Message::new(data3);
let base64_encoded = EncodedMessage::from_message_base64(message3).unwrap();
assert_eq!(base64_encoded.format(), EncodingFormat::Base64);
let decoded_base64: TestData = base64_encoded.decode().unwrap();
assert_eq!(decoded_base64.name, "test");
assert_eq!(decoded_base64.value, 42);
}
#[test]
fn test_sync_io() {
let data = TestData {
name: "test".to_string(),
value: 42,
};
let message = Message::new(data);
let encoded = message.encode().unwrap();
let mut buffer = Vec::new();
encoded.write_to(&mut buffer).unwrap();
let mut cursor = Cursor::new(buffer);
let read_message = EncodedMessage::read_from(&mut cursor).unwrap();
let decoded: TestData = read_message.decode().unwrap();
assert_eq!(decoded.name, "test");
assert_eq!(decoded.value, 42);
}
#[tokio::test]
async fn test_async_io() {
let data = TestData {
name: "test".to_string(),
value: 42,
};
let message = Message::new(data);
let encoded = message.encode().unwrap();
let mut buffer = Vec::new();
encoded.write_to_async(&mut buffer).await.unwrap();
let mut cursor = Cursor::new(buffer);
let read_message = EncodedMessage::read_from_async(&mut cursor).await.unwrap();
let decoded: TestData = read_message.decode().unwrap();
assert_eq!(decoded.name, "test");
assert_eq!(decoded.value, 42);
}
#[tokio::test]
async fn test_stream() {
let data = TestData {
name: "test".to_string(),
value: 42,
};
let _message = Message::new(data.clone());
let test_data = TestData {
name: "test".to_string(),
value: 42,
};
assert_eq!(test_data.name, "test");
assert_eq!(test_data.value, 42);
}
}