use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum StreamFrame<T> {
Item(T),
SenderError(String),
Dropped,
Detached,
Finalized,
Heartbeat,
TransportError(String),
}
#[derive(Debug, thiserror::Error)]
#[non_exhaustive]
pub enum StreamError {
#[error("sender error: {0}")]
SenderError(String),
#[error("sender dropped without explicit detach/finalize")]
SenderDropped,
#[error("transport error: {0}")]
TransportError(String),
#[error("deserialization error: {0}")]
DeserializationError(String),
}
#[derive(Debug, thiserror::Error)]
#[non_exhaustive]
pub enum SendError {
#[error("channel closed")]
ChannelClosed,
#[error("serialization error: {0}")]
SerializationError(String),
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_stream_frame_variants() {
let frames: Vec<StreamFrame<u32>> = vec![
StreamFrame::Item(42u32),
StreamFrame::SenderError("soft error".to_string()),
StreamFrame::Dropped,
StreamFrame::Detached,
StreamFrame::Finalized,
StreamFrame::Heartbeat,
StreamFrame::TransportError("connection reset".to_string()),
];
for frame in &frames {
let encoded = rmp_serde::to_vec(frame).expect("serialize StreamFrame");
let decoded: StreamFrame<u32> =
rmp_serde::from_slice(&encoded).expect("deserialize StreamFrame");
match (frame, &decoded) {
(StreamFrame::Item(a), StreamFrame::Item(b)) => assert_eq!(a, b),
(StreamFrame::SenderError(a), StreamFrame::SenderError(b)) => assert_eq!(a, b),
(StreamFrame::Dropped, StreamFrame::Dropped) => {}
(StreamFrame::Detached, StreamFrame::Detached) => {}
(StreamFrame::Finalized, StreamFrame::Finalized) => {}
(StreamFrame::Heartbeat, StreamFrame::Heartbeat) => {}
(StreamFrame::TransportError(a), StreamFrame::TransportError(b)) => {
assert_eq!(a, b)
}
_ => panic!("variant mismatch after round-trip"),
}
}
}
#[test]
fn test_stream_frame_item_direct_payload() {
let frame = StreamFrame::Item(42u32);
let encoded = rmp_serde::to_vec(&frame).expect("serialize");
let decoded: StreamFrame<u32> = rmp_serde::from_slice(&encoded).expect("deserialize");
match decoded {
StreamFrame::Item(val) => assert_eq!(val, 42u32),
other => panic!("expected Item(42), got {:?}", other),
}
}
#[test]
fn test_stream_frame_sender_error_round_trip() {
let frame = StreamFrame::<u32>::SenderError("msg".to_string());
let encoded = rmp_serde::to_vec(&frame).expect("serialize");
let decoded: StreamFrame<u32> = rmp_serde::from_slice(&encoded).expect("deserialize");
match decoded {
StreamFrame::SenderError(msg) => assert_eq!(msg, "msg"),
other => panic!("expected SenderError, got {:?}", other),
}
}
#[test]
fn test_stream_error_display() {
assert_eq!(
StreamError::SenderError("msg".to_string()).to_string(),
"sender error: msg"
);
assert_eq!(
StreamError::SenderDropped.to_string(),
"sender dropped without explicit detach/finalize"
);
assert_eq!(
StreamError::TransportError("msg".to_string()).to_string(),
"transport error: msg"
);
assert_eq!(
StreamError::DeserializationError("msg".to_string()).to_string(),
"deserialization error: msg"
);
}
#[test]
fn test_send_error_display() {
assert_eq!(SendError::ChannelClosed.to_string(), "channel closed");
assert_eq!(
SendError::SerializationError("msg".to_string()).to_string(),
"serialization error: msg"
);
}
}