use crate::WireError;
use crate::codec::{WireDecode, WireEncode, read_u8, 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 UserResponse {
pub id: u32,
pub created_at: u64,
pub status: u8,
pub username: WireName,
pub options: WireOptions,
}
impl UserResponse {
const FIXED_SIZE: usize = 4 + 8 + 1; }
impl WireEncode for UserResponse {
fn encoded_size(&self) -> usize {
Self::FIXED_SIZE + self.username.encoded_size() + 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_u8(self.status);
self.username.encode(buf);
encode_options_prefixed(&self.options, buf);
}
}
impl WireDecode for UserResponse {
fn decode(buf: &[u8]) -> Result<(Self, usize), WireError> {
let id = read_u32_le(buf, 0)?;
let created_at = read_u64_le(buf, 4)?;
let status = read_u8(buf, 12)?;
let (username, name_consumed) = WireName::decode(&buf[13..])?;
let mut consumed = 13 + name_consumed;
let (options, options_consumed) = decode_options_prefixed(buf, consumed)?;
consumed += options_consumed;
Ok((
Self {
id,
created_at,
status,
username,
options,
},
consumed,
))
}
}
#[cfg(test)]
mod tests {
use super::*;
fn sample() -> UserResponse {
UserResponse {
id: 1,
created_at: 1_710_000_000_000,
status: 1,
username: WireName::new("admin").unwrap(),
options: WireOptions::empty(),
}
}
#[test]
fn roundtrip() {
let resp = sample();
let bytes = resp.to_bytes();
assert_eq!(bytes.len(), UserResponse::FIXED_SIZE + 1 + 5 + 4);
let (decoded, consumed) = UserResponse::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!(
UserResponse::decode(&bytes[..i]).is_err(),
"expected error for truncation at byte {i}"
);
}
}
#[test]
fn multiple_users_sequential() {
let u1 = UserResponse {
id: 1,
username: WireName::new("alice").unwrap(),
..sample()
};
let u2 = UserResponse {
id: 2,
username: WireName::new("bob").unwrap(),
..sample()
};
let mut buf = BytesMut::new();
u1.encode(&mut buf);
u2.encode(&mut buf);
let bytes = buf.freeze();
let (d1, pos1) = UserResponse::decode(&bytes).unwrap();
let (d2, pos2) = UserResponse::decode(&bytes[pos1..]).unwrap();
assert_eq!(d1, u1);
assert_eq!(d2, u2);
assert_eq!(pos1 + pos2, bytes.len());
}
}