use super::error::{TransportError, TransportResult};
use super::types::PayloadFormat;
use serde::{Serialize, de::DeserializeOwned};
#[derive(Debug, Clone)]
pub enum PayloadValue {
Json(serde_json::Value),
MsgPack(serde_json::Value),
}
impl PayloadValue {
#[must_use]
pub fn as_json(&self) -> &serde_json::Value {
match self {
Self::Json(v) | Self::MsgPack(v) => v,
}
}
#[must_use]
pub fn into_json(self) -> serde_json::Value {
match self {
Self::Json(v) | Self::MsgPack(v) => v,
}
}
#[must_use]
pub fn is_json(&self) -> bool {
matches!(self, Self::Json(_))
}
#[must_use]
pub fn is_msgpack(&self) -> bool {
matches!(self, Self::MsgPack(_))
}
}
pub fn parse_payload(bytes: &[u8]) -> TransportResult<PayloadValue> {
let format = PayloadFormat::detect(bytes);
parse_payload_with_format(bytes, format)
}
pub fn parse_payload_with_format(
bytes: &[u8],
format: PayloadFormat,
) -> TransportResult<PayloadValue> {
match format {
PayloadFormat::Auto => parse_payload(bytes),
PayloadFormat::Json => {
let value: serde_json::Value = serde_json::from_slice(bytes)
.map_err(|e| TransportError::Internal(format!("JSON parse error: {e}")))?;
Ok(PayloadValue::Json(value))
}
PayloadFormat::MsgPack => {
let value: serde_json::Value = rmp_serde::from_slice(bytes)
.map_err(|e| TransportError::Internal(format!("MsgPack parse error: {e}")))?;
Ok(PayloadValue::MsgPack(value))
}
}
}
pub fn parse_payload_typed<T: DeserializeOwned>(bytes: &[u8]) -> TransportResult<T> {
let format = PayloadFormat::detect(bytes);
match format {
PayloadFormat::Json | PayloadFormat::Auto => serde_json::from_slice(bytes)
.map_err(|e| TransportError::Internal(format!("JSON deserialize error: {e}"))),
PayloadFormat::MsgPack => rmp_serde::from_slice(bytes)
.map_err(|e| TransportError::Internal(format!("MsgPack deserialize error: {e}"))),
}
}
pub fn serialize_json<T: Serialize>(value: &T) -> TransportResult<Vec<u8>> {
serde_json::to_vec(value)
.map_err(|e| TransportError::Internal(format!("JSON serialize error: {e}")))
}
pub fn serialize_msgpack<T: Serialize>(value: &T) -> TransportResult<Vec<u8>> {
rmp_serde::to_vec(value)
.map_err(|e| TransportError::Internal(format!("MsgPack serialize error: {e}")))
}
pub fn serialize_payload<T: Serialize>(
value: &T,
format: PayloadFormat,
) -> TransportResult<Vec<u8>> {
match format {
PayloadFormat::Json | PayloadFormat::Auto => serialize_json(value),
PayloadFormat::MsgPack => serialize_msgpack(value),
}
}
pub fn extract_field(bytes: &[u8], field: &str) -> TransportResult<Option<serde_json::Value>> {
let value: serde_json::Value = serde_json::from_slice(bytes)
.map_err(|e| TransportError::Internal(format!("JSON parse error: {e}")))?;
Ok(value.get(field).cloned())
}
pub fn extract_nested_field(
bytes: &[u8],
path: &str,
) -> TransportResult<Option<serde_json::Value>> {
let value: serde_json::Value = serde_json::from_slice(bytes)
.map_err(|e| TransportError::Internal(format!("JSON parse error: {e}")))?;
let mut current = &value;
for part in path.split('.') {
match current.get(part) {
Some(v) => current = v,
None => return Ok(None),
}
}
Ok(Some(current.clone()))
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn parse_json_object() {
let bytes = br#"{"foo": "bar", "num": 42}"#;
let value = parse_payload(bytes).unwrap();
assert!(value.is_json());
let json = value.as_json();
assert_eq!(json["foo"], "bar");
assert_eq!(json["num"], 42);
}
#[test]
fn parse_msgpack() {
let bytes = [
0x81, 0xa3, b'f', b'o', b'o', 0xa3, b'b', b'a', b'r', ];
let value = parse_payload(&bytes).unwrap();
assert!(value.is_msgpack());
let json = value.as_json();
assert_eq!(json["foo"], "bar");
}
#[test]
fn extract_simple_field() {
let bytes = br#"{"event": "login", "user_id": 123}"#;
let field = extract_field(bytes, "event").unwrap();
assert_eq!(field, Some(serde_json::json!("login")));
}
#[test]
fn extract_nested_field_path() {
let bytes = br#"{"tags": {"event": {"org_id": "acme"}}}"#;
let field = extract_nested_field(bytes, "tags.event.org_id").unwrap();
assert_eq!(field, Some(serde_json::json!("acme")));
}
#[test]
fn extract_missing_field() {
let bytes = br#"{"foo": "bar"}"#;
let field = extract_field(bytes, "missing").unwrap();
assert_eq!(field, None);
}
#[test]
fn serialize_roundtrip() {
#[derive(Debug, PartialEq, Serialize, serde::Deserialize)]
struct Event {
name: String,
value: i32,
}
let event = Event {
name: "test".to_string(),
value: 42,
};
let json_bytes = serialize_json(&event).unwrap();
let parsed: Event = parse_payload_typed(&json_bytes).unwrap();
assert_eq!(event, parsed);
let msgpack_bytes = serialize_msgpack(&event).unwrap();
let parsed: Event = parse_payload_typed(&msgpack_bytes).unwrap();
assert_eq!(event, parsed);
}
}