1use crate::Position;
4use std::fmt;
5
6#[derive(Debug, Clone, PartialEq, Eq)]
8pub struct Event {
9 pub event_type: EventType,
11 pub position: Position,
13}
14
15#[derive(Debug, Clone, PartialEq, Eq)]
17pub enum EventType {
18 StreamStart,
20 StreamEnd,
22
23 DocumentStart {
25 version: Option<(u8, u8)>,
27 tags: Vec<(String, String)>,
29 implicit: bool,
31 },
32
33 DocumentEnd {
35 implicit: bool,
37 },
38
39 Scalar {
41 anchor: Option<String>,
43 tag: Option<String>,
45 value: String,
47 plain_implicit: bool,
49 quoted_implicit: bool,
51 style: ScalarStyle,
53 },
54
55 SequenceStart {
57 anchor: Option<String>,
59 tag: Option<String>,
61 flow_style: bool,
63 },
64
65 SequenceEnd,
67
68 MappingStart {
70 anchor: Option<String>,
72 tag: Option<String>,
74 flow_style: bool,
76 },
77
78 MappingEnd,
80
81 Alias {
83 anchor: String,
85 },
86}
87
88#[derive(Debug, Clone, Copy, PartialEq, Eq)]
90pub enum ScalarStyle {
91 Plain,
93 SingleQuoted,
95 DoubleQuoted,
97 Literal,
99 Folded,
101}
102
103impl Event {
104 pub const fn new(event_type: EventType, position: Position) -> Self {
106 Self {
107 event_type,
108 position,
109 }
110 }
111
112 pub const fn stream_start(position: Position) -> Self {
114 Self::new(EventType::StreamStart, position)
115 }
116
117 pub const fn stream_end(position: Position) -> Self {
119 Self::new(EventType::StreamEnd, position)
120 }
121
122 pub const fn document_start(
124 position: Position,
125 version: Option<(u8, u8)>,
126 tags: Vec<(String, String)>,
127 implicit: bool,
128 ) -> Self {
129 Self::new(
130 EventType::DocumentStart {
131 version,
132 tags,
133 implicit,
134 },
135 position,
136 )
137 }
138
139 pub const fn document_end(position: Position, implicit: bool) -> Self {
141 Self::new(EventType::DocumentEnd { implicit }, position)
142 }
143
144 pub const fn scalar(
146 position: Position,
147 anchor: Option<String>,
148 tag: Option<String>,
149 value: String,
150 plain_implicit: bool,
151 quoted_implicit: bool,
152 style: ScalarStyle,
153 ) -> Self {
154 Self::new(
155 EventType::Scalar {
156 anchor,
157 tag,
158 value,
159 plain_implicit,
160 quoted_implicit,
161 style,
162 },
163 position,
164 )
165 }
166
167 pub const fn sequence_start(
169 position: Position,
170 anchor: Option<String>,
171 tag: Option<String>,
172 flow_style: bool,
173 ) -> Self {
174 Self::new(
175 EventType::SequenceStart {
176 anchor,
177 tag,
178 flow_style,
179 },
180 position,
181 )
182 }
183
184 pub const fn sequence_end(position: Position) -> Self {
186 Self::new(EventType::SequenceEnd, position)
187 }
188
189 pub const fn mapping_start(
191 position: Position,
192 anchor: Option<String>,
193 tag: Option<String>,
194 flow_style: bool,
195 ) -> Self {
196 Self::new(
197 EventType::MappingStart {
198 anchor,
199 tag,
200 flow_style,
201 },
202 position,
203 )
204 }
205
206 pub const fn mapping_end(position: Position) -> Self {
208 Self::new(EventType::MappingEnd, position)
209 }
210
211 pub const fn alias(position: Position, anchor: String) -> Self {
213 Self::new(EventType::Alias { anchor }, position)
214 }
215
216 pub const fn is_collection_start(&self) -> bool {
218 matches!(
219 self.event_type,
220 EventType::SequenceStart { .. } | EventType::MappingStart { .. }
221 )
222 }
223
224 pub const fn is_collection_end(&self) -> bool {
226 matches!(
227 self.event_type,
228 EventType::SequenceEnd | EventType::MappingEnd
229 )
230 }
231
232 pub const fn is_document_boundary(&self) -> bool {
234 matches!(
235 self.event_type,
236 EventType::DocumentStart { .. } | EventType::DocumentEnd { .. }
237 )
238 }
239}
240
241impl fmt::Display for Event {
242 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
243 match &self.event_type {
244 EventType::StreamStart => write!(f, "STREAM-START"),
245 EventType::StreamEnd => write!(f, "STREAM-END"),
246 EventType::DocumentStart { implicit, .. } => {
247 if *implicit {
248 write!(f, "DOCUMENT-START (implicit)")
249 } else {
250 write!(f, "DOCUMENT-START")
251 }
252 }
253 EventType::DocumentEnd { implicit } => {
254 if *implicit {
255 write!(f, "DOCUMENT-END (implicit)")
256 } else {
257 write!(f, "DOCUMENT-END")
258 }
259 }
260 EventType::Scalar { value, style, .. } => {
261 write!(f, "SCALAR({}, {:?})", value, style)
262 }
263 EventType::SequenceStart { flow_style, .. } => {
264 if *flow_style {
265 write!(f, "SEQUENCE-START (flow)")
266 } else {
267 write!(f, "SEQUENCE-START (block)")
268 }
269 }
270 EventType::SequenceEnd => write!(f, "SEQUENCE-END"),
271 EventType::MappingStart { flow_style, .. } => {
272 if *flow_style {
273 write!(f, "MAPPING-START (flow)")
274 } else {
275 write!(f, "MAPPING-START (block)")
276 }
277 }
278 EventType::MappingEnd => write!(f, "MAPPING-END"),
279 EventType::Alias { anchor } => write!(f, "ALIAS({})", anchor),
280 }
281 }
282}
283
284impl fmt::Display for ScalarStyle {
285 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
286 match self {
287 Self::Plain => write!(f, "plain"),
288 Self::SingleQuoted => write!(f, "single-quoted"),
289 Self::DoubleQuoted => write!(f, "double-quoted"),
290 Self::Literal => write!(f, "literal"),
291 Self::Folded => write!(f, "folded"),
292 }
293 }
294}
295
296#[cfg(test)]
297mod tests {
298 use super::*;
299
300 #[test]
301 fn test_event_creation() {
302 let pos = Position::at(1, 1, 0);
303
304 let stream_start = Event::stream_start(pos);
305 assert!(matches!(stream_start.event_type, EventType::StreamStart));
306 assert_eq!(stream_start.position, pos);
307
308 let scalar = Event::scalar(
309 pos,
310 None,
311 None,
312 "hello".to_string(),
313 true,
314 false,
315 ScalarStyle::Plain,
316 );
317
318 if let EventType::Scalar { value, style, .. } = &scalar.event_type {
319 assert_eq!(value, "hello");
320 assert_eq!(*style, ScalarStyle::Plain);
321 } else {
322 panic!("Expected scalar event");
323 }
324 }
325
326 #[test]
327 fn test_event_type_checks() {
328 let pos = Position::start();
329
330 let seq_start = Event::sequence_start(pos, None, None, false);
331 let seq_end = Event::sequence_end(pos);
332 let doc_start = Event::document_start(pos, None, vec![], true);
333
334 assert!(seq_start.is_collection_start());
335 assert!(!seq_start.is_collection_end());
336
337 assert!(!seq_end.is_collection_start());
338 assert!(seq_end.is_collection_end());
339
340 assert!(doc_start.is_document_boundary());
341 assert!(!doc_start.is_collection_start());
342 }
343
344 #[test]
345 fn test_event_display() {
346 let pos = Position::start();
347
348 let scalar = Event::scalar(
349 pos,
350 None,
351 None,
352 "test".to_string(),
353 true,
354 false,
355 ScalarStyle::DoubleQuoted,
356 );
357
358 let display = format!("{}", scalar);
359 assert!(display.contains("SCALAR"));
360 assert!(display.contains("test"));
361 }
362}