use super::{Envelope, EnvelopeError};
pub trait EnvelopeCodec: Send + Sync {
fn encode(&self, envelope: &Envelope) -> Result<Vec<u8>, EnvelopeError>;
fn decode(&self, data: &[u8]) -> Result<Envelope, EnvelopeError>;
}
#[derive(Debug, Clone, Default)]
pub struct JsonCodec;
impl EnvelopeCodec for JsonCodec {
fn encode(&self, envelope: &Envelope) -> Result<Vec<u8>, EnvelopeError> {
serde_json::to_vec(envelope).map_err(EnvelopeError::Serialization)
}
fn decode(&self, data: &[u8]) -> Result<Envelope, EnvelopeError> {
serde_json::from_slice(data).map_err(EnvelopeError::Deserialization)
}
}
#[cfg(test)]
mod tests {
use super::*;
use serde_json::json;
#[test]
fn test_json_codec_encode_decode_roundtrip() {
let codec = JsonCodec;
let envelope = Envelope::new("chat", "message", json!({"text": "hello world"}));
let encoded = codec.encode(&envelope).expect("encode");
let decoded = codec.decode(&encoded).expect("decode");
assert_eq!(decoded.namespace, "chat");
assert_eq!(decoded.msg_type, "message");
assert_eq!(decoded.payload["text"], "hello world");
}
#[test]
fn test_json_codec_preserves_all_fields() {
let codec = JsonCodec;
let envelope = Envelope {
namespace: "ft".into(),
msg_type: "offer".into(),
payload: json!({"file": "data.bin"}),
timestamp: Some(1711234567890),
from: Some("peer-abc".into()),
};
let encoded = codec.encode(&envelope).expect("encode");
let decoded = codec.decode(&encoded).expect("decode");
assert_eq!(decoded.namespace, "ft");
assert_eq!(decoded.msg_type, "offer");
assert_eq!(decoded.payload["file"], "data.bin");
assert_eq!(decoded.timestamp, Some(1711234567890));
assert_eq!(decoded.from.as_deref(), Some("peer-abc"));
}
#[test]
fn test_json_codec_unknown_fields_forward_compat() {
let codec = JsonCodec;
let json_bytes = br#"{
"namespace": "v2",
"msg_type": "new_feature",
"payload": {},
"priority": "high",
"trace_id": "abc-123"
}"#;
let decoded = codec.decode(json_bytes).expect("should decode with unknown fields");
assert_eq!(decoded.namespace, "v2");
assert_eq!(decoded.msg_type, "new_feature");
}
#[test]
fn test_json_codec_decode_error() {
let codec = JsonCodec;
let result = codec.decode(b"{{invalid");
assert!(result.is_err());
}
#[test]
fn test_json_codec_empty_payload() {
let codec = JsonCodec;
let envelope = Envelope::new("ping", "request", json!(null));
let encoded = codec.encode(&envelope).expect("encode");
let decoded = codec.decode(&encoded).expect("decode");
assert!(decoded.payload.is_null());
}
#[test]
fn test_json_codec_is_send_sync() {
fn assert_send_sync<T: Send + Sync>() {}
assert_send_sync::<JsonCodec>();
}
#[test]
fn test_json_codec_trait_object() {
let codec: std::sync::Arc<dyn EnvelopeCodec> = std::sync::Arc::new(JsonCodec);
let envelope = Envelope::new("test", "msg", json!("data"));
let encoded = codec.encode(&envelope).expect("encode");
let decoded = codec.decode(&encoded).expect("decode");
assert_eq!(decoded.namespace, "test");
}
}