jjpwrgem_parse/tokens/
stream.rs1use core::{iter::Peekable, range::Range};
2
3use crate::{
4 Error, ErrorKind, Result,
5 tokens::{
6 ByteWithContext, BytesWithContext, FALSE, NULL, TRUE, Token, TokenWithContext,
7 current_byte_pos,
8 lexical::JsonChar,
9 number::{parse_exponent, parse_mantissa},
10 string::parse_string,
11 },
12};
13
14fn skip_whitespace(bytes: &[u8]) -> usize {
15 use std::simd::{cmp::SimdPartialEq as _, u8x32};
16
17 let space = u8x32::splat(b' ');
18 let horizontal_tab = u8x32::splat(b'\t');
19 let line_feed = u8x32::splat(b'\n');
20 let carriage_return = u8x32::splat(b'\r');
21
22 let mut i = 0;
23 while i + 32 <= bytes.len() {
24 let chunk = u8x32::from_slice(&bytes[i..i + 32]);
25 let is_whitespace = chunk.simd_eq(space)
26 | chunk.simd_eq(horizontal_tab)
27 | chunk.simd_eq(line_feed)
28 | chunk.simd_eq(carriage_return);
29 let whitespace_count = is_whitespace.to_bitmask().trailing_ones() as usize;
30 i += whitespace_count;
31 if whitespace_count < 32 {
32 return i;
33 }
34 }
35
36 i + bytes[i..]
37 .iter()
38 .position(|&b| !matches!(b, b' ' | b'\t' | b'\n' | b'\r'))
39 .unwrap_or(bytes.len().saturating_sub(i))
40}
41
42#[derive(Debug, Clone)]
43struct TokenStreamInner<'a> {
44 input: &'a str,
45 pos: usize,
46}
47
48impl<'a> TokenStreamInner<'a> {
49 fn new_at_range(full_source: &'a str, range: Range<usize>) -> Self {
50 Self {
51 input: &full_source[..range.end],
52 pos: range.start,
53 }
54 }
55
56 fn peek_byte_with_context(&self) -> Option<ByteWithContext> {
57 self.input
58 .as_bytes()
59 .get(self.pos)
60 .copied()
61 .map(|byte| (self.pos, byte).into())
62 }
63
64 fn bytes_from_pos(&self) -> Peekable<BytesWithContext<'a>> {
65 BytesWithContext::new(self.input, self.pos).peekable()
66 }
67
68 fn parse_with_bytes<T>(
69 &mut self,
70 f: impl FnOnce(&'a str, &mut Peekable<BytesWithContext<'a>>) -> Result<T>,
71 ) -> Result<T> {
72 let mut bytes = self.bytes_from_pos();
73 let result = f(self.input, &mut bytes);
74 if result.is_ok() {
75 self.update_pos_from_bytes(&mut bytes);
76 }
77 result
78 }
79
80 fn update_pos_from_bytes(&mut self, bytes: &mut Peekable<BytesWithContext<'a>>) {
81 self.pos = current_byte_pos(bytes, self.input);
82 }
83
84 fn unexpected_character(&self) -> Result<TokenWithContext> {
85 let unexpected = self.input[self.pos..]
86 .chars()
87 .next()
88 .expect("pos must be in bounds");
89 Err(Error::new(
90 ErrorKind::UnexpectedCharacter(JsonChar(unexpected)),
91 self.pos..self.pos + unexpected.len_utf8(),
92 self.input,
93 ))
94 }
95
96 fn consume_whitespace(&mut self) {
97 let Some(ByteWithContext(_, byte)) = self.peek_byte_with_context() else {
98 return;
99 };
100 if !byte.is_whitespace() {
101 return;
102 }
103
104 self.pos += skip_whitespace(&self.input.as_bytes()[self.pos..]);
105 }
106}
107
108impl Iterator for TokenStreamInner<'_> {
109 type Item = Result<TokenWithContext>;
110
111 fn next(&mut self) -> Option<Self::Item> {
112 loop {
113 self.consume_whitespace();
114 let ctx = self.peek_byte_with_context()?;
115
116 if let Some(tok) = ctx.as_token_with_context() {
117 self.pos = ctx.range().end;
118 return Some(Ok(tok));
119 }
120
121 let token = match ctx.as_byte() {
122 b'"' => {
123 let result = parse_string(self.input, self.pos);
124 if let Ok(token) = &result {
125 self.pos = token.range.end;
126 }
127 result
128 }
129 b'0'..=b'9' | b'-' => self.parse_with_bytes(parse_mantissa),
130 b'e' | b'E' => {
131 match self.parse_with_bytes(|input, bytes| {
132 bytes.next();
133 parse_exponent(input, ctx.range(), bytes)
134 }) {
135 Ok(Some(tok)) => Ok(tok),
136 Ok(None) => continue,
137 Err(err) => Err(err),
138 }
139 }
140 b'n' | b't' | b'f' => {
141 let (expected, token) = match ctx.as_byte() {
142 b'n' => (NULL, Token::Null),
143 b't' => (TRUE, Token::True),
144 b'f' => (FALSE, Token::False),
145 _ => unreachable!("matched above"),
146 };
147 let end = self.pos + expected.len();
148 if self.input.as_bytes().get(self.pos..end) == Some(expected.as_bytes()) {
149 self.pos = end;
150 Ok(TokenWithContext::new(token, ctx.0..end))
151 } else {
152 self.unexpected_character()
153 }
154 }
155 _ => self.unexpected_character(),
156 };
157
158 return Some(token);
159 }
160 }
161}
162
163#[derive(Debug, Clone)]
164pub struct TokenStream<'a> {
165 inner: TokenStreamInner<'a>,
166 cached: Option<TokenWithContext>,
167}
168
169impl<'a> TokenStream<'a> {
170 pub(crate) fn new_at_range(full_source: &'a str, range: Range<usize>) -> Self {
171 Self {
172 inner: TokenStreamInner::new_at_range(full_source, range),
173 cached: None,
174 }
175 }
176
177 pub fn new(s: &'a str) -> Self {
178 Self::new_at_range(s, 0..s.len())
179 }
180
181 pub(crate) fn pos(&self) -> usize {
182 self.inner.pos
183 }
184
185 pub fn peek_token(&mut self) -> Result<Option<&TokenWithContext>> {
186 if self.cached.is_none() {
187 match self.inner.next() {
188 Some(Ok(token)) => self.cached = Some(token),
189 Some(Err(err)) => return Err(err),
190 None => return Ok(None),
191 }
192 }
193
194 Ok(self.cached.as_ref())
195 }
196
197 pub fn next_token(&mut self) -> Result<Option<TokenWithContext>> {
198 if let Some(token) = self.cached.take() {
199 Ok(Some(token))
200 } else {
201 self.next().transpose()
202 }
203 }
204}
205
206impl Iterator for TokenStream<'_> {
207 type Item = Result<TokenWithContext>;
208
209 fn next(&mut self) -> Option<Self::Item> {
210 self.inner.next()
211 }
212}