use serde::Serialize;
use crate::error::RayError;
const XLANG_HEADER_LEN: usize = 9;
pub fn serialize<T: Serialize>(value: &T) -> Result<Vec<u8>, RayError> {
let mut buf = Vec::new();
value.serialize(&mut rmp_serde::Serializer::new(&mut buf))?;
Ok(buf)
}
pub fn deserialize<T: serde::de::DeserializeOwned>(data: &[u8]) -> Result<T, RayError> {
let mut de = rmp_serde::Deserializer::from_read_ref(data);
T::deserialize(&mut de).map_err(RayError::from)
}
fn build_xlang_header(data_len: usize) -> [u8; XLANG_HEADER_LEN] {
let mut header = [0u8; XLANG_HEADER_LEN];
let mut buf = Vec::new();
if data_len <= 0x7f {
buf.push(data_len as u8); } else if data_len <= 0xff {
buf.push(0xcc); buf.push(data_len as u8);
} else if data_len <= 0xffff {
buf.push(0xcd); buf.extend_from_slice(&(data_len as u16).to_be_bytes());
} else {
buf.push(0xce); buf.extend_from_slice(&(data_len as u32).to_be_bytes());
}
let n = buf.len().min(XLANG_HEADER_LEN);
header[..n].copy_from_slice(&buf[..n]);
header
}
pub fn serialize_xlang<T: Serialize>(value: &T) -> Result<Vec<u8>, RayError> {
let payload = serialize(value)?;
let header = build_xlang_header(payload.len());
let mut buf = Vec::with_capacity(XLANG_HEADER_LEN + payload.len());
buf.extend_from_slice(&header);
buf.extend_from_slice(&payload);
Ok(buf)
}
fn has_xlang_header(data: &[u8]) -> bool {
if data.len() <= XLANG_HEADER_LEN {
return false;
}
let header = &data[..XLANG_HEADER_LEN];
let payload = &data[XLANG_HEADER_LEN..];
let payload_len = match header[0] {
v if v <= 0x7f => v as usize,
0xcc if header.len() >= 2 => header[1] as usize,
0xcd if header.len() >= 3 => {
u16::from_be_bytes([header[1], header[2]]) as usize
}
0xce if header.len() >= 5 => {
u32::from_be_bytes([header[1], header[2], header[3], header[4]]) as usize
}
_ => return false,
};
payload_len == payload.len()
}
pub fn deserialize_xlang<T: serde::de::DeserializeOwned>(data: &[u8]) -> Result<T, RayError> {
if has_xlang_header(data) {
let raw_data = &data[XLANG_HEADER_LEN..];
deserialize(raw_data)
} else {
deserialize(data)
}
}
pub fn deserialize_xlang_value(data: &[u8]) -> Result<rmpv::Value, RayError> {
if has_xlang_header(data) {
let mut reader = &data[XLANG_HEADER_LEN..];
rmpv::decode::read_value(&mut reader)
.map_err(|e| RayError::Serialization(format!("msgpack value decode error: {}", e)))
} else {
let mut reader = data;
rmpv::decode::read_value(&mut reader)
.map_err(|e| RayError::Serialization(format!("msgpack value decode error: {}", e)))
}
}
pub fn deserialize_value(data: &[u8]) -> Result<rmpv::Value, RayError> {
let mut reader = data;
rmpv::decode::read_value(&mut reader)
.map_err(|e| RayError::Serialization(format!("msgpack value decode error: {}", e)))
}
#[cfg(test)]
mod tests {
use super::*;
use std::collections::HashMap;
#[test]
fn test_serialize_deserialize_roundtrip() {
let val: i64 = 42;
let bytes = serialize(&val).unwrap();
let back: i64 = deserialize(&bytes).unwrap();
assert_eq!(val, back);
}
#[test]
fn test_serialize_xlang_header_format() {
let header = build_xlang_header(5);
assert_eq!(header[0], 5);
assert_eq!(header[1..], [0u8; 8]);
let header = build_xlang_header(200);
assert_eq!(header[0], 0xcc);
assert_eq!(header[1], 200);
assert_eq!(header[2..], [0u8; 7]);
let header = build_xlang_header(1000);
assert_eq!(header[0], 0xcd);
assert_eq!(header[1..3], [0x03, 0xe8]);
}
#[test]
fn test_has_xlang_header() {
let raw = serialize(&42i64).unwrap();
assert!(!has_xlang_header(&raw));
let xlang = serialize_xlang(&42i64).unwrap();
assert!(has_xlang_header(&xlang));
let big_data = vec![0u8; 200];
let xlang_big = serialize_xlang(&big_data).unwrap();
assert!(has_xlang_header(&xlang_big));
assert!(!has_xlang_header(&[]));
assert!(!has_xlang_header(&[0u8; 5]));
}
#[test]
fn test_has_xlang_header_non_zero_padding() {
let payload = serialize(&42i64).unwrap(); let mut data = vec![payload.len() as u8]; data.extend_from_slice(&[0x81, 0x04, 0x64, 0x28, 0x7f, 0x00, 0x00, 0x40]);
data.extend_from_slice(&payload);
assert_eq!(data.len(), 10);
assert!(has_xlang_header(&data));
let back: i64 = deserialize_xlang(&data).unwrap();
assert_eq!(back, 42);
}
#[test]
fn test_has_xlang_header_uint8_len() {
let payload_str = "x".repeat(200);
let payload = serialize(&payload_str).unwrap();
assert!(payload.len() > 127 && payload.len() <= 255,
"payload len = {}, expected 128-255", payload.len());
let xlang = serialize_xlang(&payload_str).unwrap();
assert!(has_xlang_header(&xlang));
let back: String = deserialize_xlang(&xlang).unwrap();
assert_eq!(back.len(), 200);
}
#[test]
fn test_has_xlang_header_uint16_len() {
let payload_str = "x".repeat(1000);
let payload = serialize(&payload_str).unwrap();
assert!(payload.len() > 255,
"payload len = {}, expected > 255", payload.len());
let xlang = serialize_xlang(&payload_str).unwrap();
assert!(has_xlang_header(&xlang));
let back: String = deserialize_xlang(&xlang).unwrap();
assert_eq!(back.len(), 1000);
}
#[test]
fn test_has_xlang_header_uint32_len() {
let big_string = "x".repeat(70000);
let payload = serialize(&big_string).unwrap();
assert!(payload.len() > 65535);
let xlang = serialize_xlang(&big_string).unwrap();
assert!(has_xlang_header(&xlang));
let back: String = deserialize_xlang(&xlang).unwrap();
assert_eq!(back.len(), 70000);
}
#[test]
fn test_serialize_xlang_roundtrip() {
let val = vec![1i64, 2, 3, 4, 5];
let xlang_bytes = serialize_xlang(&val).unwrap();
let payload_len = serialize(&val).unwrap().len();
assert_eq!(xlang_bytes.len(), XLANG_HEADER_LEN + payload_len);
let back: Vec<i64> = deserialize_xlang(&xlang_bytes).unwrap();
assert_eq!(val, back);
}
#[test]
fn test_serialize_xlang_string() {
let val = "hello".to_string();
let xlang_bytes = serialize_xlang(&val).unwrap();
let back: String = deserialize_xlang(&xlang_bytes).unwrap();
assert_eq!(val, back);
}
#[test]
fn test_serialize_xlang_bool() {
let xlang = serialize_xlang(&true).unwrap();
let back: bool = deserialize_xlang(&xlang).unwrap();
assert!(back);
let xlang = serialize_xlang(&false).unwrap();
let back: bool = deserialize_xlang(&xlang).unwrap();
assert!(!back);
}
#[test]
fn test_serialize_xlang_f64() {
let val: f64 = 3.141592653589793;
let xlang = serialize_xlang(&val).unwrap();
let back: f64 = deserialize_xlang(&xlang).unwrap();
assert_eq!(val, back);
}
#[test]
fn test_serialize_xlang_none() {
let val: Option<i64> = None;
let xlang = serialize_xlang(&val).unwrap();
let back: Option<i64> = deserialize_xlang(&xlang).unwrap();
assert_eq!(val, back);
}
#[test]
fn test_serialize_xlang_i32() {
let val: i32 = -12345;
let xlang = serialize_xlang(&val).unwrap();
let back: i32 = deserialize_xlang(&xlang).unwrap();
assert_eq!(val, back);
}
#[test]
fn test_serialize_xlang_empty_list() {
let val: Vec<i64> = vec![];
let xlang = serialize_xlang(&val).unwrap();
let back: Vec<i64> = deserialize_xlang(&xlang).unwrap();
assert_eq!(val, back);
assert!(back.is_empty());
}
#[test]
fn test_serialize_xlang_empty_map() {
let val: HashMap<String, i64> = HashMap::new();
let xlang = serialize_xlang(&val).unwrap();
let back: HashMap<String, i64> = deserialize_xlang(&xlang).unwrap();
assert_eq!(val, back);
assert!(back.is_empty());
}
#[test]
fn test_serialize_xlang_nested_vec() {
let val: Vec<Vec<i64>> = vec![vec![1, 2], vec![3, 4, 5], vec![]];
let xlang = serialize_xlang(&val).unwrap();
let back: Vec<Vec<i64>> = deserialize_xlang(&xlang).unwrap();
assert_eq!(val, back);
}
#[test]
fn test_serialize_xlang_tuple() {
let val = (42i64, "hello".to_string(), true);
let xlang = serialize_xlang(&val).unwrap();
let back: (i64, String, bool) = deserialize_xlang(&xlang).unwrap();
assert_eq!(val, back);
}
#[test]
fn test_serialize_xlang_large_list() {
let val: Vec<i64> = (0..10000).collect();
let xlang = serialize_xlang(&val).unwrap();
let back: Vec<i64> = deserialize_xlang(&xlang).unwrap();
assert_eq!(val, back);
}
#[test]
fn test_deserialize_xlang_auto_detect_no_header() {
let val = vec![1i64, 2, 3, 4, 5];
let raw_bytes = serialize(&val).unwrap();
let back: Vec<i64> = deserialize_xlang(&raw_bytes).unwrap();
assert_eq!(val, back);
}
#[test]
fn test_deserialize_xlang_auto_detect_with_header() {
let val = vec![1i64, 2, 3, 4, 5];
let xlang_bytes = serialize_xlang(&val).unwrap();
let back: Vec<i64> = deserialize_xlang(&xlang_bytes).unwrap();
assert_eq!(val, back);
}
#[test]
fn test_deserialize_xlang_auto_detect_non_zero_padding() {
let payload = serialize(&vec![1i64, 2, 3]).unwrap();
let mut data = vec![payload.len() as u8];
data.extend_from_slice(&[0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff]);
data.extend_from_slice(&payload);
let back: Vec<i64> = deserialize_xlang(&data).unwrap();
assert_eq!(back, vec![1, 2, 3]);
}
#[test]
fn test_deserialize_xlang_value_list() {
let val = vec![10i64, 20, 30];
let xlang_bytes = serialize_xlang(&val).unwrap();
let value = deserialize_xlang_value(&xlang_bytes).unwrap();
assert!(value.is_array());
let arr = value.as_array().unwrap();
assert_eq!(arr.len(), 3);
assert_eq!(arr[0].as_i64().unwrap(), 10);
assert_eq!(arr[1].as_i64().unwrap(), 20);
assert_eq!(arr[2].as_i64().unwrap(), 30);
}
#[test]
fn test_deserialize_xlang_value_dict() {
let map_value = rmpv::Value::Map(vec![
(rmpv::Value::String("name".into()), rmpv::Value::String("alice".into())),
(rmpv::Value::String("age".into()), rmpv::Value::Integer(30.into())),
]);
let xlang_bytes = serialize_xlang(&map_value).unwrap();
let value = deserialize_xlang_value(&xlang_bytes).unwrap();
assert!(value.is_map());
let entries = value.as_map().unwrap();
let name_val = entries.iter()
.find(|(k, _)| k.as_str() == Some("name"))
.map(|(_, v)| v)
.unwrap();
assert_eq!(name_val.as_str().unwrap(), "alice");
let age_val = entries.iter()
.find(|(k, _)| k.as_str() == Some("age"))
.map(|(_, v)| v)
.unwrap();
assert_eq!(age_val.as_i64().unwrap(), 30);
}
#[test]
fn test_deserialize_xlang_value_none() {
let val: Option<i64> = None;
let xlang_bytes = serialize_xlang(&val).unwrap();
let value = deserialize_xlang_value(&xlang_bytes).unwrap();
assert!(value.is_nil());
}
#[test]
fn test_deserialize_xlang_value_nested() {
let mut inner1 = HashMap::new();
inner1.insert("id".to_string(), 1i64);
let mut inner2 = HashMap::new();
inner2.insert("id".to_string(), 2i64);
let mut outer = HashMap::new();
outer.insert("items".to_string(), vec![inner1, inner2]);
let xlang_bytes = serialize_xlang(&outer).unwrap();
let value = deserialize_xlang_value(&xlang_bytes).unwrap();
assert!(value.is_map());
let entries = value.as_map().unwrap();
let items = entries.iter()
.find(|(k, _)| k.as_str() == Some("items"))
.map(|(_, v)| v)
.unwrap();
assert!(items.is_array());
assert_eq!(items.as_array().unwrap().len(), 2);
}
#[test]
fn test_deserialize_xlang_value_mixed_array() {
let mixed = rmpv::Value::Array(vec![
rmpv::Value::Integer(42.into()),
rmpv::Value::String("hello".into()),
rmpv::Value::Boolean(true),
rmpv::Value::Nil,
rmpv::Value::F32(3.14),
]);
let xlang = serialize_xlang(&mixed).unwrap();
let val = deserialize_xlang_value(&xlang).unwrap();
assert!(val.is_array());
let arr = val.as_array().unwrap();
assert_eq!(arr.len(), 5);
assert_eq!(arr[0].as_i64().unwrap(), 42);
assert_eq!(arr[1].as_str().unwrap(), "hello");
assert_eq!(arr[2].as_bool().unwrap(), true);
assert!(arr[3].is_nil());
}
#[test]
fn test_deserialize_xlang_value_empty_list() {
let val: Vec<i64> = vec![];
let xlang = serialize_xlang(&val).unwrap();
let value = deserialize_xlang_value(&xlang).unwrap();
assert!(value.is_array());
assert_eq!(value.as_array().unwrap().len(), 0);
}
#[test]
fn test_deserialize_value_string() {
let val = "hello world".to_string();
let bytes = serialize(&val).unwrap();
let value = deserialize_value(&bytes).unwrap();
assert_eq!(value.as_str().unwrap(), "hello world");
}
#[test]
fn test_deserialize_value_bool() {
let bytes = serialize(&true).unwrap();
let value = deserialize_value(&bytes).unwrap();
assert_eq!(value.as_bool().unwrap(), true);
}
#[test]
fn test_has_xlang_header_false_positive_guard() {
let raw = serialize(&0i64).unwrap();
assert!(!has_xlang_header(&raw));
let raw = serialize(&vec![1i64, 2, 3, 4, 5, 6, 7, 8, 9]).unwrap();
let back: Vec<i64> = deserialize_xlang(&raw).unwrap();
assert_eq!(back, vec![1, 2, 3, 4, 5, 6, 7, 8, 9]);
}
#[test]
fn test_serialize_xlang_then_serialize_again() {
let val = 42i64;
let xlang1 = serialize_xlang(&val).unwrap();
let xlang2 = serialize_xlang(&xlang1).unwrap();
assert!(has_xlang_header(&xlang2));
let inner: Vec<u8> = deserialize_xlang(&xlang2).unwrap();
assert!(has_xlang_header(&inner));
let val_back: i64 = deserialize_xlang(&inner).unwrap();
assert_eq!(val_back, 42);
}
}