trillium_grpc/frame/
writer.rs1use std::borrow::Cow;
4
5use crate::{Codec, Encoding, Status};
6
7const PREFIX_LEN: usize = 5;
10
11pub fn encode_frame<C, T>(value: &T, encoding: Encoding) -> Result<Vec<u8>, Status>
18where
19 C: Codec<T>,
20{
21 encode_payload(&C::encode(value)?, encoding)
22}
23
24pub fn encode_payload(payload: &[u8], encoding: Encoding) -> Result<Vec<u8>, Status> {
28 let (flag, payload): (u8, Cow<'_, [u8]>) = match encoding {
29 Encoding::Identity => (0, Cow::Borrowed(payload)),
30 #[cfg(any(feature = "gzip", feature = "deflate", feature = "zstd"))]
31 _ => (1, Cow::Owned(encoding.compress(payload)?)),
32 };
33 let mut out = Vec::with_capacity(PREFIX_LEN + payload.len());
34 out.push(flag);
35 out.extend_from_slice(&(payload.len() as u32).to_be_bytes());
36 out.extend_from_slice(&payload);
37 Ok(out)
38}
39
40#[cfg(test)]
41mod tests {
42 use super::*;
43 use crate::codec::Prost;
44
45 fn frame(payload: &[u8]) -> Vec<u8> {
46 let mut out = Vec::with_capacity(PREFIX_LEN + payload.len());
47 out.push(0);
48 out.extend_from_slice(&(payload.len() as u32).to_be_bytes());
49 out.extend_from_slice(payload);
50 out
51 }
52
53 #[test]
54 fn encode_single_frame_identity() {
55 let buf = encode_frame::<Prost, Vec<u8>>(&b"hi".to_vec(), Encoding::Identity).unwrap();
56 assert_eq!(buf, frame(&[0x0A, 0x02, b'h', b'i']));
58 }
59
60 #[cfg(feature = "gzip")]
61 #[test]
62 fn encode_single_frame_gzip_sets_compressed_flag() {
63 let buf = encode_frame::<Prost, Vec<u8>>(&b"hi".to_vec(), Encoding::Gzip).unwrap();
64 assert_eq!(buf[0], 1, "compressed flag");
65 let len = u32::from_be_bytes([buf[1], buf[2], buf[3], buf[4]]) as usize;
67 let payload = &buf[PREFIX_LEN..PREFIX_LEN + len];
68 let decoded = Encoding::Gzip.decompress(payload, 1024).unwrap();
69 assert_eq!(decoded, [0x0A, 0x02, b'h', b'i']);
70 }
71}