use bytes::{Buf, BufMut, Bytes, BytesMut};
use crate::primitives::varint::{get_uvarint, put_uvarint, uvarint_len};
pub const FRAME_VERSION: u32 = 1;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct ValueHeader {
pub api_key: u32,
pub api_version: u32,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, thiserror::Error)]
pub enum EnvelopeError {
#[error("truncated metadata record value envelope")]
Truncated,
#[error(
"Could not deserialize metadata record due to unknown frame version {0}(only frame version 1 is supported)"
)]
UnknownFrameVersion(u32),
}
#[must_use]
pub fn encode_value(api_key: u32, api_version: u32, body: &[u8]) -> Bytes {
let mut out = BytesMut::with_capacity(
uvarint_len(FRAME_VERSION) + uvarint_len(api_key) + uvarint_len(api_version) + body.len(),
);
put_uvarint(&mut out, FRAME_VERSION);
put_uvarint(&mut out, api_key);
put_uvarint(&mut out, api_version);
out.put_slice(body);
out.freeze()
}
pub fn decode_value_header<B: Buf>(buf: &mut B) -> Result<ValueHeader, EnvelopeError> {
let frame_version = get_uvarint(buf).map_err(|_| EnvelopeError::Truncated)?;
if frame_version != FRAME_VERSION {
return Err(EnvelopeError::UnknownFrameVersion(frame_version));
}
let api_key = get_uvarint(buf).map_err(|_| EnvelopeError::Truncated)?;
let api_version = get_uvarint(buf).map_err(|_| EnvelopeError::Truncated)?;
Ok(ValueHeader {
api_key,
api_version,
})
}
#[cfg(test)]
mod tests {
use super::*;
const GOLDEN_VALUE: [u8; 5] = [0x01, 0x0C, 0x00, 0x01, 0x02];
#[test]
fn encode_matches_the_golden_bytes() {
assert2::assert!(encode_value(12, 0, &[0x01, 0x02])[..] == GOLDEN_VALUE);
}
#[test]
fn golden_bytes_decode_to_the_header_and_body() {
let mut cur: &[u8] = &GOLDEN_VALUE;
let hdr = decode_value_header(&mut cur);
assert2::assert!(
hdr == Ok(ValueHeader {
api_key: 12,
api_version: 0,
})
);
assert2::assert!(cur == [0x01, 0x02]);
}
#[test]
fn rejects_a_bad_envelope() {
for (label, value, want) in [
("empty", vec![], EnvelopeError::Truncated),
("frame version only", vec![0x01], EnvelopeError::Truncated),
(
"frame version 0",
vec![0x00, 0x0C, 0x00],
EnvelopeError::UnknownFrameVersion(0),
),
(
"frame version 2",
vec![0x02, 0x0C, 0x00],
EnvelopeError::UnknownFrameVersion(2),
),
(
"frame version 300 (two-byte varint)",
vec![0xAC, 0x02, 0x0C, 0x00],
EnvelopeError::UnknownFrameVersion(300),
),
] {
let mut cur: &[u8] = &value;
assert2::assert!(decode_value_header(&mut cur) == Err(want), "{label}");
}
}
#[test]
fn unknown_frame_version_reads_as_kafkas_message() {
assert2::assert!(
EnvelopeError::UnknownFrameVersion(2).to_string()
== "Could not deserialize metadata record due to unknown frame version 2(only frame version 1 is supported)"
);
}
}