use bytes::{Buf, BufMut};
use commonware_codec::{EncodeSize, Error as CodecError, Read, ReadRangeExt as _, Write};
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Event {
pub kind: String,
pub payload: Vec<u8>,
}
impl Event {
#[must_use]
pub fn new(kind: impl Into<String>, payload: Vec<u8>) -> Self {
Self {
kind: kind.into(),
payload,
}
}
}
#[derive(Debug, Clone, Copy)]
pub struct EventCfg {
pub max_kind_len: usize,
pub max_payload_len: usize,
}
impl EventCfg {
pub const DEFAULT: Self = Self {
max_kind_len: 256,
max_payload_len: 16 * 1024 * 1024,
};
}
impl Default for EventCfg {
fn default() -> Self {
Self::DEFAULT
}
}
impl Write for Event {
fn write(&self, buf: &mut impl BufMut) {
self.kind.as_bytes().to_vec().write(buf);
self.payload.write(buf);
}
}
impl EncodeSize for Event {
fn encode_size(&self) -> usize {
self.kind.as_bytes().to_vec().encode_size() + self.payload.encode_size()
}
}
impl Read for Event {
type Cfg = EventCfg;
fn read_cfg(buf: &mut impl Buf, cfg: &EventCfg) -> Result<Self, CodecError> {
let kind_bytes = <Vec<u8>>::read_range(buf, 0..=cfg.max_kind_len)?;
let kind = String::from_utf8(kind_bytes)
.map_err(|_| CodecError::Invalid("Event", "kind is not valid UTF-8"))?;
let payload = <Vec<u8>>::read_range(buf, 0..=cfg.max_payload_len)?;
Ok(Self { kind, payload })
}
}
#[cfg(test)]
mod tests {
use super::{Event, EventCfg};
use commonware_codec::{Decode as _, Encode as _};
#[test]
fn round_trips_through_codec() {
let event = Event::new("tool_call", vec![1, 2, 3, 0xff, 0]);
let bytes = event.encode();
let decoded = Event::decode_cfg(bytes, &EventCfg::DEFAULT).expect("decode");
assert_eq!(event, decoded);
}
#[test]
fn round_trips_empty_payload() {
let event = Event::new("user_msg", Vec::new());
let bytes = event.encode();
let decoded = Event::decode_cfg(bytes, &EventCfg::DEFAULT).expect("decode");
assert_eq!(event, decoded);
assert!(decoded.payload.is_empty());
}
#[test]
fn rejects_payload_over_cap() {
let event = Event::new("k", vec![0u8; 64]);
let bytes = event.encode();
let tight = EventCfg {
max_kind_len: 256,
max_payload_len: 8,
};
assert!(Event::decode_cfg(bytes, &tight).is_err());
}
}