1use super::{Result, Token};
2use crate::error::{NoValidTokenError, UnexpectedTokenError};
3use crate::event::{
4 EntryEvent, Event, EventType, GroupEndEvent, GroupStartEvent, Item, ValueContinuationEvent,
5};
6use logos::{Lexer, Logos, Span, SpannedIter};
7use std::borrow::Cow;
8
9pub struct Reader<'a> {
11 pub source: &'a str,
12 pub last_event: Option<EventType>,
13 lexer: SpannedIter<'a, Token>,
14}
15
16impl<'a> From<&'a str> for Reader<'a> {
17 fn from(content: &'a str) -> Self {
18 Reader {
19 source: content,
20 last_event: None,
21 lexer: Lexer::new(content).spanned(),
22 }
23 }
24}
25
26impl<'a> Reader<'a> {
27 fn token(&mut self) -> Option<(Result<Token, <Token as Logos>::Error>, Span)> {
28 self.lexer.next()
29 }
30
31 pub fn span(&self) -> Span {
32 self.lexer.span()
33 }
34
35 pub fn event(&mut self) -> Option<Result<Event<'a>>> {
37 let result = self.event_inner();
38 if let Some(Ok(event)) = &result {
39 self.last_event = Some(event.ty());
40 }
41 result
42 }
43
44 #[allow(dead_code)]
45 fn event_inner(&mut self) -> Option<Result<Event<'a>>> {
46 const VALID_KEY: &[Token] = &[
47 Token::Item,
48 Token::QuotedItem,
49 Token::GroupEnd,
50 Token::Statement,
51 Token::QuotedStatement,
52 ];
53
54 let whitespace_start = self.span().end;
55
56 let key = match self.token() {
57 None => {
58 return None;
59 }
60 Some((Err(_), span)) => {
61 return Some(Err(NoValidTokenError::new(
62 VALID_KEY,
63 span.into(),
64 self.source.into(),
65 )
66 .into()));
67 }
68 Some((Ok(Token::GroupEnd), span)) => {
69 return Some(Ok(Event::GroupEnd(GroupEndEvent { span })))
70 }
71
72 Some((Ok(Token::Item), span)) => Item::Item {
73 content: string(self.lexer.slice()),
74 span,
75 },
76
77 Some((Ok(Token::QuotedItem), span)) => Item::Item {
78 content: quoted_string(self.lexer.slice()),
79 span,
80 },
81
82 Some((Ok(Token::Statement), span)) => Item::Statement {
83 content: string(self.lexer.slice()),
84 span,
85 },
86
87 Some((Ok(Token::QuotedStatement), span)) => Item::Statement {
88 content: quoted_string(self.lexer.slice()),
89 span,
90 },
91
92 Some((Ok(token), span)) => {
93 return Some(Err(UnexpectedTokenError::new(
94 VALID_KEY,
95 Some(token),
96 span.into(),
97 self.source.into(),
98 )
99 .into()))
100 }
101 };
102
103 let whitespace_end = self.span().start;
104 let skipped_newline = self.source[whitespace_start..whitespace_end].contains('\n');
105 let last_event_has_value = matches!(
106 self.last_event,
107 Some(EventType::Entry | EventType::ValueContinuation)
108 );
109
110 if last_event_has_value && !skipped_newline {
112 return Some(Ok(Event::ValueContinuation(ValueContinuationEvent {
113 value: key,
114 span: self.span(),
115 })));
116 }
117
118 const VALID_VALUE: &[Token] = &[
119 Token::Item,
120 Token::QuotedItem,
121 Token::GroupStart,
122 Token::Statement,
123 Token::QuotedStatement,
124 ];
125
126 let value = match self.token() {
127 None => {
128 return Some(Err(UnexpectedTokenError::new(
129 VALID_VALUE,
130 None,
131 self.lexer.span().into(),
132 self.source.into(),
133 )
134 .into()));
135 }
136
137 Some((Err(_), span)) => {
138 return Some(Err(NoValidTokenError::new(
139 VALID_VALUE,
140 span.into(),
141 self.source.into(),
142 )
143 .into()));
144 }
145
146 Some((Ok(Token::GroupStart), span)) => {
147 return Some(Ok(Event::GroupStart(GroupStartEvent {
148 name: key.into_content(),
149 span,
150 })))
151 }
152
153 Some((Ok(Token::QuotedItem), span)) => Item::Item {
154 content: quoted_string(self.lexer.slice()),
155 span,
156 },
157
158 Some((Ok(Token::Item), span)) => Item::Item {
159 content: string(self.lexer.slice()),
160 span,
161 },
162
163 Some((Ok(Token::QuotedStatement), span)) => Item::Statement {
164 content: quoted_string(self.lexer.slice()),
165 span,
166 },
167
168 Some((Ok(Token::Statement), span)) => Item::Statement {
169 content: string(self.lexer.slice()),
170 span,
171 },
172
173 Some((Ok(token), span)) => {
174 return Some(Err(UnexpectedTokenError::new(
175 VALID_VALUE,
176 Some(token),
177 span.into(),
178 self.source.into(),
179 )
180 .into()))
181 }
182 };
183
184 let span = key.span().start..value.span().end;
185 Some(Ok(Event::Entry(EntryEvent { key, value, span })))
186 }
187}
188
189impl<'a> Iterator for Reader<'a> {
190 type Item = Result<Event<'a>>;
191
192 fn next(&mut self) -> Option<Self::Item> {
193 self.event()
194 }
195}
196
197pub(crate) fn quoted_string(source: &str) -> Cow<str> {
198 let source = &source[1..source.len() - 1];
199
200 if source.contains(r#"\""#) || source.contains(r#"\\"#) {
201 let mut buffer = source.bytes();
202 let mut string = Vec::with_capacity(buffer.len());
203
204 while let Some(byte) = buffer.next() {
205 if byte == b'\\' {
206 match buffer.next() {
207 Some(b'\\') => string.push(b'\\'),
208 Some(b'"') => string.push(b'"'),
209 Some(byte) => string.extend_from_slice(&[b'\\', byte]),
210 None => break,
211 }
212 } else {
213 string.push(byte);
214 }
215 }
216
217 String::from_utf8(string).unwrap().into()
218 } else {
219 source.into()
220 }
221}
222
223fn string(source: &str) -> Cow<str> {
224 source.into()
225}