server_sent_events/
event.rs1use alloc::{boxed::Box, vec::Vec};
2
3#[derive(Debug, Clone, Default, PartialEq, Eq)]
4pub struct Event {
5 pub comment: Option<Box<str>>,
7 pub retry: Option<usize>,
9 pub id: Option<Box<str>>,
11 pub r#type: Option<Box<str>>,
12 pub data: Option<EventData>,
13}
14
15#[derive(Debug, Clone, PartialEq, Eq)]
16pub enum EventData {
17 Line(Box<str>),
18 Lines(Vec<Box<str>>),
19}
20
21impl Event {
22 pub fn new<'a>(
23 data: &str,
24 r#type: impl Into<Option<&'a str>>,
25 id: impl Into<Option<&'a str>>,
26 ) -> Self {
27 Self {
28 id: id.into().map(Into::into),
29 r#type: r#type.into().map(Into::into),
30 data: Some(EventData::Line(data.into())),
31 ..Default::default()
32 }
33 }
34
35 pub fn with_multiline_data<'a>(
36 data: Vec<&str>,
37 r#type: impl Into<Option<&'a str>>,
38 id: impl Into<Option<&'a str>>,
39 ) -> Self {
40 Self {
41 id: id.into().map(Into::into),
42 r#type: r#type.into().map(Into::into),
43 data: Some(EventData::Lines(data.into_iter().map(Into::into).collect())),
44 ..Default::default()
45 }
46 }
47
48 pub fn with_comment(comment: &str) -> Self {
49 Self {
50 comment: Some(comment.into()),
51 ..Default::default()
52 }
53 }
54
55 pub fn with_retry(retry_ms: usize) -> Self {
56 Self {
57 retry: Some(retry_ms),
58 ..Default::default()
59 }
60 }
61}
62
63impl core::fmt::Display for Event {
64 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
65 if let Some(comment) = &self.comment {
66 writeln!(f, ": {comment}")?;
67 }
68
69 if let Some(retry) = &self.retry {
70 writeln!(f, "retry: {retry}")?;
71 }
72
73 if let Some(id) = &self.id {
74 writeln!(f, "id: {id}")?;
75 }
76
77 if let Some(r#type) = &self.r#type {
78 writeln!(f, "event: {type}")?;
79 }
80
81 if let Some(data) = &self.data {
82 match &data {
83 EventData::Line(s) => {
84 for x in s.lines() {
85 writeln!(f, "data: {x}")?;
86 }
87 }
88 &EventData::Lines(s_vec) => {
89 for s in s_vec {
90 for x in s.lines() {
91 writeln!(f, "data: {x}")?;
92 }
93 }
94 }
95 }
96 }
97
98 writeln!(f)?;
99
100 Ok(())
101 }
102}
103
104#[cfg(test)]
105mod tests {
106 use super::*;
107
108 use alloc::{string::ToString as _, vec};
109
110 #[test]
111 fn test_to_string() {
112 assert_eq!(
113 Event::with_comment("This is a comment")
114 .to_string()
115 .as_bytes(),
116 b": This is a comment\n\n"
117 );
118
119 assert_eq!(
120 Event::with_retry(10000).to_string().as_bytes(),
121 b"retry: 10000\n\n"
122 );
123
124 assert_eq!(
125 Event::new("message", None, None).to_string().as_bytes(),
126 b"data: message\n\n"
127 );
128 assert_eq!(
129 Event::new(r#"Message of type "foo""#, "foo", None)
130 .to_string()
131 .as_bytes(),
132 b"event: foo\ndata: Message of type \"foo\"\n\n"
133 );
134 assert_eq!(
135 Event::new(r#"Message of type "foo""#, "foo", "1")
136 .to_string()
137 .as_bytes(),
138 b"id: 1\nevent: foo\ndata: Message of type \"foo\"\n\n"
139 );
140
141 assert_eq!(
142 Event::with_multiline_data(
143 vec!["Multi-line message of", r#"type "bar" and id "42""#],
144 "bar",
145 "42"
146 )
147 .to_string()
148 .as_bytes(),
149 b"id: 42\nevent: bar\ndata: Multi-line message of\ndata: type \"bar\" and id \"42\"\n\n"
150 );
151
152 assert_eq!(
153 Event::with_multiline_data(vec!["another message", "with two lines "], None, None)
154 .to_string()
155 .as_bytes(),
156 b"data: another message\ndata: with two lines \n\n"
157 );
158 }
159}