rust_yaml/parser/
events.rs

1//! YAML event definitions
2
3use crate::Position;
4use std::fmt;
5
6/// Represents a YAML parsing event
7#[derive(Debug, Clone, PartialEq, Eq)]
8pub struct Event {
9    /// The type of event
10    pub event_type: EventType,
11    /// Position where the event occurred
12    pub position: Position,
13}
14
15/// Types of YAML parsing events
16#[derive(Debug, Clone, PartialEq, Eq)]
17pub enum EventType {
18    /// Start of stream
19    StreamStart,
20    /// End of stream
21    StreamEnd,
22
23    /// Document start
24    DocumentStart {
25        /// YAML version
26        version: Option<(u8, u8)>,
27        /// Tag directives
28        tags: Vec<(String, String)>,
29        /// Implicit document start
30        implicit: bool,
31    },
32
33    /// Document end
34    DocumentEnd {
35        /// Implicit document end
36        implicit: bool,
37    },
38
39    /// Scalar value
40    Scalar {
41        /// Anchor name
42        anchor: Option<String>,
43        /// Tag
44        tag: Option<String>,
45        /// Value
46        value: String,
47        /// Plain style (unquoted)
48        plain_implicit: bool,
49        /// Quoted style implicit
50        quoted_implicit: bool,
51        /// Style
52        style: ScalarStyle,
53    },
54
55    /// Sequence start
56    SequenceStart {
57        /// Anchor name
58        anchor: Option<String>,
59        /// Tag
60        tag: Option<String>,
61        /// Flow style
62        flow_style: bool,
63    },
64
65    /// Sequence end
66    SequenceEnd,
67
68    /// Mapping start
69    MappingStart {
70        /// Anchor name
71        anchor: Option<String>,
72        /// Tag
73        tag: Option<String>,
74        /// Flow style
75        flow_style: bool,
76    },
77
78    /// Mapping end
79    MappingEnd,
80
81    /// Alias reference
82    Alias {
83        /// Anchor name being referenced
84        anchor: String,
85    },
86}
87
88/// Scalar representation styles
89#[derive(Debug, Clone, Copy, PartialEq, Eq)]
90pub enum ScalarStyle {
91    /// Plain style (no quotes)
92    Plain,
93    /// Single quoted
94    SingleQuoted,
95    /// Double quoted
96    DoubleQuoted,
97    /// Literal style (|)
98    Literal,
99    /// Folded style (>)
100    Folded,
101}
102
103impl Event {
104    /// Create a new event
105    pub const fn new(event_type: EventType, position: Position) -> Self {
106        Self {
107            event_type,
108            position,
109        }
110    }
111
112    /// Create a stream start event
113    pub const fn stream_start(position: Position) -> Self {
114        Self::new(EventType::StreamStart, position)
115    }
116
117    /// Create a stream end event
118    pub const fn stream_end(position: Position) -> Self {
119        Self::new(EventType::StreamEnd, position)
120    }
121
122    /// Create a document start event
123    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    /// Create a document end event
140    pub const fn document_end(position: Position, implicit: bool) -> Self {
141        Self::new(EventType::DocumentEnd { implicit }, position)
142    }
143
144    /// Create a scalar event
145    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    /// Create a sequence start event
168    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    /// Create a sequence end event
185    pub const fn sequence_end(position: Position) -> Self {
186        Self::new(EventType::SequenceEnd, position)
187    }
188
189    /// Create a mapping start event
190    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    /// Create a mapping end event
207    pub const fn mapping_end(position: Position) -> Self {
208        Self::new(EventType::MappingEnd, position)
209    }
210
211    /// Create an alias event
212    pub const fn alias(position: Position, anchor: String) -> Self {
213        Self::new(EventType::Alias { anchor }, position)
214    }
215
216    /// Check if this is a collection start event
217    pub const fn is_collection_start(&self) -> bool {
218        matches!(
219            self.event_type,
220            EventType::SequenceStart { .. } | EventType::MappingStart { .. }
221        )
222    }
223
224    /// Check if this is a collection end event
225    pub const fn is_collection_end(&self) -> bool {
226        matches!(
227            self.event_type,
228            EventType::SequenceEnd | EventType::MappingEnd
229        )
230    }
231
232    /// Check if this is a document boundary event
233    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}