use crate::error::{Error, Result};
use crate::protocol::message::Message;
use bytes::Bytes;
pub struct JsonCodec;
impl JsonCodec {
pub fn encode(message: &Message) -> Result<Bytes> {
let json = serde_json::to_vec(message)?;
Ok(Bytes::from(json))
}
pub fn decode(data: &[u8]) -> Result<Message> {
let message: Message = serde_json::from_slice(data)?;
Ok(message)
}
pub fn encode_pretty(message: &Message) -> Result<Bytes> {
let json = serde_json::to_vec_pretty(message)?;
Ok(Bytes::from(json))
}
pub fn validate(data: &[u8]) -> Result<()> {
serde_json::from_slice::<serde_json::Value>(data)?;
Ok(())
}
}
pub struct JsonMessage {
data: Bytes,
}
impl JsonMessage {
pub fn new(data: Bytes) -> Self {
Self { data }
}
pub fn from_string(s: String) -> Self {
Self {
data: Bytes::from(s.into_bytes()),
}
}
pub fn data(&self) -> &Bytes {
&self.data
}
pub fn to_message(&self) -> Result<Message> {
JsonCodec::decode(&self.data)
}
pub fn as_string(&self) -> Result<String> {
String::from_utf8(self.data.to_vec())
.map_err(|e| Error::Protocol(format!("Invalid UTF-8: {}", e)))
}
pub fn validate(&self) -> Result<()> {
JsonCodec::validate(&self.data)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_json_codec_ping() -> Result<()> {
let msg = Message::ping();
let encoded = JsonCodec::encode(&msg)?;
let decoded = JsonCodec::decode(&encoded)?;
assert_eq!(msg.msg_type, decoded.msg_type);
assert_eq!(msg.id, decoded.id);
Ok(())
}
#[test]
fn test_json_codec_pretty() -> Result<()> {
let msg = Message::ping();
let encoded = JsonCodec::encode_pretty(&msg)?;
let decoded = JsonCodec::decode(&encoded)?;
assert_eq!(msg.msg_type, decoded.msg_type);
let s = String::from_utf8(encoded.to_vec()).ok();
assert!(s.is_some());
assert!(s.as_ref().is_some_and(|s| s.contains('\n')));
Ok(())
}
#[test]
fn test_json_message() -> Result<()> {
let msg = Message::ping();
let encoded = JsonCodec::encode(&msg)?;
let json_msg = JsonMessage::new(encoded);
let decoded = json_msg.to_message()?;
assert_eq!(msg.msg_type, decoded.msg_type);
json_msg.validate()?;
Ok(())
}
#[test]
fn test_json_validate_invalid() {
let invalid = b"not valid json";
let result = JsonCodec::validate(invalid);
assert!(result.is_err());
}
}