use std::time::Duration;
use bytes::{BufMut, Bytes, BytesMut};
use bytestring::ByteString;
use crate::Data;
#[must_use]
#[derive(Debug, Clone)]
pub enum Event {
Data(Data),
Comment(ByteString),
}
impl Event {
pub(crate) fn line_split_with_prefix(
buf: &mut BytesMut,
prefix: &'static str,
data: ByteString,
) {
buf.reserve(data.len() + (10 * (prefix.len() + 1)) + 1);
for line in data.split('\n') {
buf.put_slice(prefix.as_bytes());
buf.put_slice(line.as_bytes());
buf.put_u8(b'\n');
}
}
pub(crate) fn into_bytes(self) -> Bytes {
let mut buf = BytesMut::new();
match self {
Event::Data(Data { id, event, data }) => {
if let Some(text) = id {
buf.put_slice(b"id: ");
buf.put_slice(text.as_bytes());
buf.put_u8(b'\n');
}
if let Some(text) = event {
buf.put_slice(b"event: ");
buf.put_slice(text.as_bytes());
buf.put_u8(b'\n');
}
Self::line_split_with_prefix(&mut buf, "data: ", data);
}
Event::Comment(text) => Self::line_split_with_prefix(&mut buf, ": ", text),
}
buf.put_u8(b'\n');
buf.freeze()
}
pub(crate) fn retry_to_bytes(retry: Duration) -> Bytes {
Bytes::from(format!("retry: {}\n\n", retry.as_millis()))
}
pub(crate) const fn keep_alive_bytes() -> Bytes {
Bytes::from_static(b": keep-alive\n\n")
}
}
impl From<Data> for Event {
fn from(data: Data) -> Self {
Self::Data(data)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn format_retry_message() {
assert_eq!(
Event::retry_to_bytes(Duration::from_millis(1)),
"retry: 1\n\n",
);
assert_eq!(
Event::retry_to_bytes(Duration::from_secs(10)),
"retry: 10000\n\n",
);
}
#[test]
fn line_split_format() {
let mut buf = BytesMut::new();
Event::line_split_with_prefix(&mut buf, "data: ", ByteString::from("foo"));
assert_eq!(buf, "data: foo\n");
let mut buf = BytesMut::new();
Event::line_split_with_prefix(&mut buf, "data: ", ByteString::from("foo\nbar"));
assert_eq!(buf, "data: foo\ndata: bar\n");
}
#[test]
fn into_bytes_format() {
assert_eq!(Event::Comment("foo".into()).into_bytes(), ": foo\n\n");
assert_eq!(
Event::Data(Data {
id: None,
event: None,
data: "foo".into()
})
.into_bytes(),
"data: foo\n\n"
);
assert_eq!(
Event::Data(Data {
id: None,
event: None,
data: "\n".into()
})
.into_bytes(),
"data: \ndata: \n\n"
);
assert_eq!(
Event::Data(Data {
id: Some("42".into()),
event: None,
data: "foo".into()
})
.into_bytes(),
"id: 42\ndata: foo\n\n"
);
assert_eq!(
Event::Data(Data {
id: None,
event: Some("bar".into()),
data: "foo".into()
})
.into_bytes(),
"event: bar\ndata: foo\n\n"
);
assert_eq!(
Event::Data(Data {
id: Some("42".into()),
event: Some("bar".into()),
data: "foo".into()
})
.into_bytes(),
"id: 42\nevent: bar\ndata: foo\n\n"
);
}
}