use melin_wire_protocol::control_codec::{TAG_APP, TAG_LEN};
pub const MAX_RESPONSE_BODY: usize = 512;
const HEADER_LEN: usize = 4 + TAG_LEN;
pub(crate) const MAX_APP_FRAME: usize = HEADER_LEN + MAX_RESPONSE_BODY;
pub(crate) type EncodeBuf = [u8; MAX_APP_FRAME];
#[inline]
pub(crate) fn frame_app_response(
buf: &mut EncodeBuf,
encode: impl FnOnce(&mut [u8]) -> Result<usize, &'static str>,
) -> Result<usize, &'static str> {
let len = encode(&mut buf[HEADER_LEN..])?;
if len > MAX_RESPONSE_BODY {
return Err("encoder reported a body longer than its buffer");
}
let payload_len = (TAG_LEN + len) as u32;
buf[..4].copy_from_slice(&payload_len.to_le_bytes());
buf[4] = TAG_APP;
Ok(HEADER_LEN + len)
}
#[cfg(test)]
mod tests {
use super::*;
fn frame(
encode: impl FnOnce(&mut [u8]) -> Result<usize, &'static str>,
) -> (Result<usize, &'static str>, EncodeBuf) {
let mut buf = [0u8; MAX_APP_FRAME];
let result = frame_app_response(&mut buf, encode);
(result, buf)
}
#[test]
fn the_header_goes_in_front_of_the_body() {
let (n, buf) = frame(|body| {
body[..3].copy_from_slice(b"abc");
Ok(3)
});
assert_eq!(n, Ok(8));
assert_eq!(&buf[..8], &[4, 0, 0, 0, TAG_APP, b'a', b'b', b'c']);
}
#[test]
fn an_empty_body_is_a_tag_only_frame() {
let (n, buf) = frame(|_| Ok(0));
assert_eq!(n, Ok(5));
assert_eq!(&buf[..5], &[1, 0, 0, 0, TAG_APP]);
}
#[test]
fn a_body_may_start_with_any_byte() {
for first in [0x00, 0x01, 0x02, TAG_APP, 0xFF] {
let (n, buf) = frame(|body| {
body[0] = first;
Ok(1)
});
assert_eq!(n, Ok(6));
assert_eq!(&buf[..6], &[2, 0, 0, 0, TAG_APP, first]);
}
}
#[test]
fn the_encoder_is_given_the_whole_body_bound() {
let (n, _) = frame(|body| {
assert_eq!(body.len(), MAX_RESPONSE_BODY);
Ok(MAX_RESPONSE_BODY)
});
assert_eq!(n, Ok(MAX_APP_FRAME));
}
#[test]
fn a_length_past_the_body_is_refused() {
let (n, _) = frame(|_| Ok(MAX_RESPONSE_BODY + 1));
assert!(n.is_err());
}
#[test]
fn an_encode_error_passes_through() {
let (n, _) = frame(|_| Err("no"));
assert_eq!(n, Err("no"));
}
}