use core_types::{ErrorCode, ErrorDomain, RtError};
use data_model::{ControlEnvelope, DataEnvelope, PacketHeader, SchemaId, SchemaVersion};
const CONTROL_SEPARATOR: u8 = 0;
pub trait SerializationManager {
fn encode_control(&self, envelope: &ControlEnvelope) -> Result<Vec<u8>, RtError>;
fn decode_control(&self, bytes: &[u8]) -> Result<ControlEnvelope, RtError>;
fn encode_data(&self, envelope: &DataEnvelope) -> Result<Vec<u8>, RtError>;
}
#[derive(Default)]
pub struct SimpleSerializationManager;
impl SerializationManager for SimpleSerializationManager {
fn encode_control(&self, envelope: &ControlEnvelope) -> Result<Vec<u8>, RtError> {
let mut bytes = envelope.label.as_bytes().to_vec();
bytes.push(CONTROL_SEPARATOR);
bytes.extend_from_slice(&envelope.payload);
Ok(bytes)
}
fn decode_control(&self, bytes: &[u8]) -> Result<ControlEnvelope, RtError> {
let Some(separator) = bytes.iter().position(|b| *b == CONTROL_SEPARATOR) else {
return Err(RtError::new(
ErrorCode::CodecError,
ErrorDomain::DataModel,
false,
"invalid control payload: missing separator",
));
};
let label = String::from_utf8(bytes[..separator].to_vec()).map_err(|_| {
RtError::new(
ErrorCode::CodecError,
ErrorDomain::DataModel,
false,
"invalid control payload: label is not utf8",
)
})?;
let payload = bytes[separator + 1..].to_vec();
Ok(ControlEnvelope {
header: PacketHeader {
version: 1,
domain: core_types::TransportDomain::Local,
session_id: None,
stream_id: None,
sequence: 0,
ack: None,
timestamp: core_types::Timestamp::now(),
schema_id: SchemaId::new("decoded.control"),
schema_version: SchemaVersion(1),
},
label,
payload,
})
}
fn encode_data(&self, envelope: &DataEnvelope) -> Result<Vec<u8>, RtError> {
match &envelope.payload {
data_model::DataPayload::Inline(buf) => Ok(buf.clone()),
data_model::DataPayload::External(external) => {
let marker = format!(
"ext:{}:{}:{}",
external.buffer_id.0, external.offset, external.len
);
Ok(marker.into_bytes())
}
}
}
}