use serde::{Deserialize, Serialize};
fn deserialize_raw_json_box<'de, D>(
deserializer: D,
) -> Result<Box<serde_json::value::RawValue>, D::Error>
where
D: serde::Deserializer<'de>,
{
let value = serde_json::Value::deserialize(deserializer)?;
serde_json::value::RawValue::from_string(value.to_string()).map_err(serde::de::Error::custom)
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
#[serde(tag = "status", rename_all = "snake_case")]
pub enum StreamReadStatus {
Event {
#[serde(deserialize_with = "deserialize_raw_json_box")]
#[cfg_attr(feature = "schema", schemars(with = "serde_json::Value"))]
event: Box<serde_json::value::RawValue>,
},
Timeout,
Closed,
}
#[cfg(test)]
#[allow(clippy::expect_used, clippy::panic)]
mod tests {
use super::*;
#[test]
fn event_status_roundtrip_carries_opaque_payload() {
let status = StreamReadStatus::Event {
event: serde_json::value::RawValue::from_string(
serde_json::json!({"kind": "delta", "text": "hi"}).to_string(),
)
.expect("raw value"),
};
let json = serde_json::to_value(&status).expect("serialize");
assert_eq!(json["status"], "event");
assert_eq!(json["event"]["kind"], "delta");
let parsed: StreamReadStatus = serde_json::from_value(json).expect("deserialize");
match parsed {
StreamReadStatus::Event { event } => {
let value: serde_json::Value =
serde_json::from_str(event.get()).expect("parse opaque event");
assert_eq!(value["text"], "hi");
}
other => panic!("expected Event, got {other:?}"),
}
}
#[test]
fn timeout_status_roundtrip() {
let status = StreamReadStatus::Timeout;
let json = serde_json::to_value(&status).expect("serialize");
assert_eq!(json, serde_json::json!({"status": "timeout"}));
let parsed: StreamReadStatus = serde_json::from_value(json).expect("deserialize");
assert!(matches!(parsed, StreamReadStatus::Timeout));
}
#[test]
fn closed_status_roundtrip() {
let status = StreamReadStatus::Closed;
let json = serde_json::to_value(&status).expect("serialize");
assert_eq!(json, serde_json::json!({"status": "closed"}));
let parsed: StreamReadStatus = serde_json::from_value(json).expect("deserialize");
assert!(matches!(parsed, StreamReadStatus::Closed));
}
#[test]
fn unknown_status_is_rejected() {
let json = serde_json::json!({"status": "drained"});
let err = serde_json::from_value::<StreamReadStatus>(json)
.expect_err("unknown status must fail closed");
assert!(err.to_string().contains("unknown variant"));
}
}