use std::borrow::Cow;
use crate::{Codec, Encoding, Status};
const PREFIX_LEN: usize = 5;
pub fn encode_frame<C, T>(value: &T, encoding: Encoding) -> Result<Vec<u8>, Status>
where
C: Codec<T>,
{
encode_payload(&C::encode(value)?, encoding)
}
pub fn encode_payload(payload: &[u8], encoding: Encoding) -> Result<Vec<u8>, Status> {
let (flag, payload): (u8, Cow<'_, [u8]>) = match encoding {
Encoding::Identity => (0, Cow::Borrowed(payload)),
#[cfg(any(feature = "gzip", feature = "deflate", feature = "zstd"))]
_ => (1, Cow::Owned(encoding.compress(payload)?)),
};
let mut out = Vec::with_capacity(PREFIX_LEN + payload.len());
out.push(flag);
out.extend_from_slice(&(payload.len() as u32).to_be_bytes());
out.extend_from_slice(&payload);
Ok(out)
}
#[cfg(test)]
mod tests {
use super::*;
use crate::codec::Prost;
fn frame(payload: &[u8]) -> Vec<u8> {
let mut out = Vec::with_capacity(PREFIX_LEN + payload.len());
out.push(0);
out.extend_from_slice(&(payload.len() as u32).to_be_bytes());
out.extend_from_slice(payload);
out
}
#[test]
fn encode_single_frame_identity() {
let buf = encode_frame::<Prost, Vec<u8>>(&b"hi".to_vec(), Encoding::Identity).unwrap();
assert_eq!(buf, frame(&[0x0A, 0x02, b'h', b'i']));
}
#[cfg(feature = "gzip")]
#[test]
fn encode_single_frame_gzip_sets_compressed_flag() {
let buf = encode_frame::<Prost, Vec<u8>>(&b"hi".to_vec(), Encoding::Gzip).unwrap();
assert_eq!(buf[0], 1, "compressed flag");
let len = u32::from_be_bytes([buf[1], buf[2], buf[3], buf[4]]) as usize;
let payload = &buf[PREFIX_LEN..PREFIX_LEN + len];
let decoded = Encoding::Gzip.decompress(payload, 1024).unwrap();
assert_eq!(decoded, [0x0A, 0x02, b'h', b'i']);
}
}