use serde::{Deserialize, Serialize};
use super::TransportError;
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct Frame<M> {
pub from: String,
pub msg: M,
}
impl<M> Frame<M> {
pub fn is_self(&self, my_tag: &str) -> bool {
self.from == my_tag
}
}
pub fn encode_line<T: Serialize>(value: &T) -> Result<String, TransportError> {
serde_json::to_string(value).map_err(|e| TransportError::SerializationError(e.to_string()))
}
pub fn decode_line<T: serde::de::DeserializeOwned>(line: &str) -> Result<T, TransportError> {
serde_json::from_str(line).map_err(|e| TransportError::SerializationError(e.to_string()))
}
#[cfg(test)]
mod tests {
use super::*;
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
#[serde(tag = "kind", rename_all = "snake_case")]
enum TestMessage {
Hello { version: u8 },
HelloAck { version: u8 },
RequestBattle,
}
fn hello() -> TestMessage {
TestMessage::Hello { version: 2 }
}
fn hello_ack() -> TestMessage {
TestMessage::HelloAck { version: 2 }
}
#[test]
fn bare_message_roundtrips_through_codec() {
let json = encode_line(&hello()).unwrap();
assert!(!json.contains('\n'));
assert_eq!(decode_line::<TestMessage>(&json).unwrap(), hello());
}
#[test]
fn frame_roundtrips_through_codec_and_self_filter() {
let frame = Frame {
from: "abc123".to_string(),
msg: hello_ack(),
};
let json = encode_line(&frame).unwrap();
assert!(json.contains("\"from\":\"abc123\""));
assert!(json.contains("\"msg\":"));
let decoded = decode_line::<Frame<TestMessage>>(&json).unwrap();
assert_eq!(decoded, frame);
assert!(frame.is_self("abc123"));
assert!(!frame.is_self("peer-tag"));
}
#[test]
fn peer_frame_with_different_tag_is_kept() {
let frame = Frame {
from: "peer-tag".to_string(),
msg: TestMessage::RequestBattle,
};
assert!(!frame.is_self("my-tag"));
let json = encode_line(&frame).unwrap();
assert_eq!(
decode_line::<Frame<TestMessage>>(&json).unwrap().msg,
TestMessage::RequestBattle
);
}
#[test]
fn malformed_line_is_a_serialization_error() {
match decode_line::<Frame<TestMessage>>("not json at all") {
Err(TransportError::SerializationError(_)) => {}
other => panic!("expected SerializationError, got {:?}", other),
}
let bare = encode_line(&hello()).unwrap();
assert!(matches!(
decode_line::<Frame<TestMessage>>(&bare),
Err(TransportError::SerializationError(_))
));
}
}