use crate::id::EventId;
pub const TS_OFFSET: usize = 0;
pub const ID_OFFSET: usize = 8;
pub const FIELDS_OFFSET: usize = 16;
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub struct RecordView<'a> {
pub ts_nanos: u64,
pub event_id: EventId,
pub fields: &'a [u8],
}
impl<'a> RecordView<'a> {
pub fn parse(payload: &'a [u8]) -> Option<Self> {
if payload.len() < FIELDS_OFFSET {
return None;
}
let ts_nanos = u64::from_le_bytes(payload[TS_OFFSET..ID_OFFSET].try_into().unwrap());
let event_id = EventId(u64::from_le_bytes(
payload[ID_OFFSET..FIELDS_OFFSET].try_into().unwrap(),
));
Some(Self {
ts_nanos,
event_id,
fields: &payload[FIELDS_OFFSET..],
})
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn parses_prefix_and_fields() {
let mut payload = Vec::new();
payload.extend_from_slice(&123u64.to_le_bytes());
payload.extend_from_slice(&EventId::of("a::B").get().to_le_bytes());
payload.extend_from_slice(&[1, 2, 3, 4]);
let v = RecordView::parse(&payload).unwrap();
assert_eq!(v.ts_nanos, 123);
assert_eq!(v.event_id, EventId::of("a::B"));
assert_eq!(v.fields, &[1, 2, 3, 4]);
}
#[test]
fn rejects_short_payload() {
assert!(RecordView::parse(&[0u8; 8]).is_none());
assert!(RecordView::parse(&[0u8; 16]).is_some());
}
}