use crate::WireError;
use crate::codec::{WireDecode, WireEncode, read_u32_le, read_u64_le};
use crate::primitives::identifier::WireName;
use crate::primitives::options::{
WireOptions, decode_options_prefixed, encode_options_prefixed, options_prefixed_size,
};
use bytes::{BufMut, BytesMut};
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct StreamResponse {
pub id: u32,
pub created_at: u64,
pub topics_count: u32,
pub size_bytes: u64,
pub messages_count: u64,
pub name: WireName,
pub options: WireOptions,
}
impl StreamResponse {
const FIXED_SIZE: usize = 4 + 8 + 4 + 8 + 8 + 1; }
impl WireEncode for StreamResponse {
fn encoded_size(&self) -> usize {
Self::FIXED_SIZE + self.name.len() + options_prefixed_size(&self.options)
}
fn encode(&self, buf: &mut BytesMut) {
buf.put_u32_le(self.id);
buf.put_u64_le(self.created_at);
buf.put_u32_le(self.topics_count);
buf.put_u64_le(self.size_bytes);
buf.put_u64_le(self.messages_count);
self.name.encode(buf);
encode_options_prefixed(&self.options, buf);
}
}
impl WireDecode for StreamResponse {
fn decode(buf: &[u8]) -> Result<(Self, usize), WireError> {
let id = read_u32_le(buf, 0)?;
let created_at = read_u64_le(buf, 4)?;
let topics_count = read_u32_le(buf, 12)?;
let size_bytes = read_u64_le(buf, 16)?;
let messages_count = read_u64_le(buf, 24)?;
let (name, name_consumed) = WireName::decode(&buf[32..])?;
let mut consumed = 32 + name_consumed;
let (options, options_consumed) = decode_options_prefixed(buf, consumed)?;
consumed += options_consumed;
Ok((
Self {
id,
created_at,
topics_count,
size_bytes,
messages_count,
name,
options,
},
consumed,
))
}
}
#[cfg(test)]
mod tests {
use super::*;
fn sample() -> StreamResponse {
StreamResponse {
id: 1,
created_at: 1_710_000_000_000,
topics_count: 3,
size_bytes: 1024,
messages_count: 100,
name: WireName::new("test-stream").unwrap(),
options: WireOptions::empty(),
}
}
#[test]
fn roundtrip() {
let resp = sample();
let bytes = resp.to_bytes();
assert_eq!(bytes.len(), StreamResponse::FIXED_SIZE + 11 + 4);
let (decoded, consumed) = StreamResponse::decode(&bytes).unwrap();
assert_eq!(consumed, bytes.len());
assert_eq!(decoded, resp);
}
#[test]
fn truncated_returns_error() {
let resp = sample();
let bytes = resp.to_bytes();
for i in 0..bytes.len() {
assert!(
StreamResponse::decode(&bytes[..i]).is_err(),
"expected error for truncation at byte {i}"
);
}
}
#[test]
fn multiple_streams_sequential() {
let s1 = StreamResponse {
id: 1,
name: WireName::new("a").unwrap(),
..sample()
};
let s2 = StreamResponse {
id: 2,
name: WireName::new("bb").unwrap(),
..sample()
};
let mut buf = BytesMut::new();
s1.encode(&mut buf);
s2.encode(&mut buf);
let bytes = buf.freeze();
let (d1, pos1) = StreamResponse::decode(&bytes).unwrap();
let (d2, pos2) = StreamResponse::decode(&bytes[pos1..]).unwrap();
assert_eq!(d1, s1);
assert_eq!(d2, s2);
assert_eq!(pos1 + pos2, bytes.len());
}
}