vexy_json_core/streaming/
ndjson.rs1use super::{StreamingEvent, StreamingParser};
9use crate::ast::Value;
10use crate::error::{Error, Result};
11use crate::parser::ParserOptions;
12
13pub struct NdJsonParser {
15 line_buffer: String,
17 #[allow(dead_code)]
19 options: ParserOptions,
20 finished: bool,
22 line_number: usize,
24}
25
26impl NdJsonParser {
27 pub fn new() -> Self {
29 Self::with_options(ParserOptions::default())
30 }
31
32 pub fn with_options(options: ParserOptions) -> Self {
34 Self {
35 line_buffer: String::new(),
36 options,
37 finished: false,
38 line_number: 1,
39 }
40 }
41
42 pub fn feed(&mut self, chunk: &str) -> Result<Vec<Value>> {
44 if self.finished {
45 return Err(Error::Custom("Parser already finished".to_string()));
46 }
47
48 let mut results = Vec::new();
49
50 for ch in chunk.chars() {
51 if ch == '\n' {
52 if !self.line_buffer.trim().is_empty() {
54 match self.parse_line(&self.line_buffer) {
55 Ok(value) => results.push(value),
56 Err(e) => {
57 return Err(Error::Custom(format!(
58 "Error on line {}: {}",
59 self.line_number, e
60 )));
61 }
62 }
63 }
64 self.line_buffer.clear();
65 self.line_number += 1;
66 } else {
67 self.line_buffer.push(ch);
68 }
69 }
70
71 Ok(results)
72 }
73
74 pub fn finish(&mut self) -> Result<Vec<Value>> {
76 if self.finished {
77 return Ok(Vec::new());
78 }
79
80 let mut results = Vec::new();
81
82 if !self.line_buffer.trim().is_empty() {
84 match self.parse_line(&self.line_buffer) {
85 Ok(value) => results.push(value),
86 Err(e) => {
87 return Err(Error::Custom(format!(
88 "Error on line {}: {}",
89 self.line_number, e
90 )));
91 }
92 }
93 }
94
95 self.finished = true;
96 Ok(results)
97 }
98
99 fn parse_line(&self, line: &str) -> Result<Value> {
101 let trimmed = line.trim();
102 if trimmed.is_empty() {
103 return Err(Error::Custom("Empty line".to_string()));
104 }
105
106 #[cfg(feature = "serde")]
108 {
109 crate::parse_with_options(trimmed, self.options.clone())
110 }
111 #[cfg(not(feature = "serde"))]
112 {
113 crate::parse(trimmed)
114 }
115 }
116
117
118 #[inline(always)]
120 pub fn is_finished(&self) -> bool {
121 self.finished
122 }
123
124 #[inline(always)]
126 pub fn line_number(&self) -> usize {
127 self.line_number
128 }
129}
130
131pub struct StreamingNdJsonParser {
133 line_buffer: String,
135 event_queue: Vec<StreamingEvent>,
137 options: ParserOptions,
139 finished: bool,
141 line_number: usize,
143}
144
145impl StreamingNdJsonParser {
146 pub fn new() -> Self {
148 Self::with_options(ParserOptions::default())
149 }
150
151 pub fn with_options(options: ParserOptions) -> Self {
153 Self {
154 line_buffer: String::new(),
155 event_queue: Vec::new(),
156 options,
157 finished: false,
158 line_number: 1,
159 }
160 }
161
162 pub fn feed(&mut self, chunk: &str) -> Result<()> {
164 if self.finished {
165 return Err(Error::Custom("Parser already finished".to_string()));
166 }
167
168 for ch in chunk.chars() {
169 if ch == '\n' {
170 if !self.line_buffer.trim().is_empty() {
172 self.start_line_parsing()?;
173 }
174 self.line_buffer.clear();
175 self.line_number += 1;
176 } else {
177 self.line_buffer.push(ch);
178 }
179 }
180
181 Ok(())
182 }
183
184 fn start_line_parsing(&mut self) -> Result<()> {
186 let mut parser = StreamingParser::with_options(self.options.clone());
187 parser.feed(&self.line_buffer)?;
188 let mut line_events = Vec::new();
192 while let Some(event) = parser.next_event()? {
193 if matches!(event, StreamingEvent::EndOfInput) {
194 break;
195 }
196 line_events.push(event);
197 }
198
199 line_events.push(StreamingEvent::EndOfInput);
201
202 self.event_queue.extend(line_events);
203 Ok(())
204 }
205
206 pub fn next_event(&mut self) -> Result<Option<StreamingEvent>> {
208 if !self.event_queue.is_empty() {
209 Ok(Some(self.event_queue.remove(0)))
210 } else {
211 Ok(None)
212 }
213 }
214
215 pub fn finish(&mut self) -> Result<()> {
217 if !self.line_buffer.trim().is_empty() {
218 self.start_line_parsing()?;
219 }
220 self.finished = true;
221 Ok(())
222 }
223
224 pub fn is_finished(&self) -> bool {
226 self.finished && self.event_queue.is_empty()
227 }
228
229 #[inline(always)]
231 pub fn line_number(&self) -> usize {
232 self.line_number
233 }
234}
235
236pub struct NdJsonIterator {
238 parser: NdJsonParser,
239 buffer: String,
240 input: Box<dyn Iterator<Item = std::result::Result<String, std::io::Error>>>,
241}
242
243impl NdJsonIterator {
244 pub fn new<I>(input: I) -> Self
246 where
247 I: Iterator<Item = std::result::Result<String, std::io::Error>> + 'static,
248 {
249 Self {
250 parser: NdJsonParser::new(),
251 buffer: String::new(),
252 input: Box::new(input),
253 }
254 }
255
256 pub fn with_options<I>(input: I, options: ParserOptions) -> Self
258 where
259 I: Iterator<Item = std::result::Result<String, std::io::Error>> + 'static,
260 {
261 Self {
262 parser: NdJsonParser::with_options(options),
263 buffer: String::new(),
264 input: Box::new(input),
265 }
266 }
267}
268
269impl Iterator for NdJsonIterator {
270 type Item = Result<Value>;
271
272 fn next(&mut self) -> Option<Self::Item> {
273 loop {
274 match self.input.next() {
275 Some(Ok(line)) => {
276 self.buffer = line;
277 self.buffer.push('\n');
278
279 match self.parser.feed(&self.buffer) {
280 Ok(values) => {
281 if !values.is_empty() {
282 return Some(Ok(values.into_iter().next().unwrap()));
283 }
284 }
285 Err(e) => return Some(Err(e)),
286 }
287 }
288 Some(Err(e)) => {
289 return Some(Err(Error::Custom(format!("IO error: {e}"))));
290 }
291 None => {
292 match self.parser.finish() {
294 Ok(values) => {
295 if !values.is_empty() {
296 return Some(Ok(values.into_iter().next().unwrap()));
297 }
298 return None;
299 }
300 Err(e) => return Some(Err(e)),
301 }
302 }
303 }
304 }
305 }
306}
307
308impl Default for NdJsonParser {
309 fn default() -> Self {
310 Self::new()
311 }
312}
313
314impl Default for StreamingNdJsonParser {
315 fn default() -> Self {
316 Self::new()
317 }
318}
319
320#[cfg(test)]
321mod tests {
322 use super::*;
323
324 #[test]
325 fn test_ndjson_parser() {
326 let mut parser = NdJsonParser::new();
327
328 let input = r#"{"name": "Alice", "age": 30}
329{"name": "Bob", "age": 25}
330{"name": "Charlie", "age": 35}"#;
331
332 let mut values = parser.feed(input).unwrap();
333 values.extend(parser.finish().unwrap());
334 assert_eq!(values.len(), 3);
335
336 if let Value::Object(obj) = &values[0] {
338 assert_eq!(
339 obj.get("name").unwrap(),
340 &Value::String("Alice".to_string())
341 );
342 } else {
343 panic!("Expected object");
344 }
345 }
346
347 #[test]
348 fn test_streaming_ndjson() {
349 let mut parser = StreamingNdJsonParser::new();
350
351 parser
352 .feed(
353 r#"{"key": "value1"}
354{"key": "value2"}"#,
355 )
356 .unwrap();
357 parser.finish().unwrap();
358
359 let mut events = Vec::new();
360 while let Some(event) = parser.next_event().unwrap() {
361 events.push(event);
362 }
363
364 assert!(!events.is_empty());
366 }
367
368 #[test]
369 fn test_empty_lines() {
370 let mut parser = NdJsonParser::new();
371
372 let input = r#"{"valid": true}
373
374{"also": "valid"}"#;
375
376 let mut values = parser.feed(input).unwrap();
377 values.extend(parser.finish().unwrap());
378 assert_eq!(values.len(), 2);
379 }
380}