1use std::fs::File;
8use std::io::{self, BufRead, BufReader, Read};
9use std::path::Path;
10use std::str::FromStr;
11
12use crate::node::is_space;
13use crate::text::push_code_point;
14use crate::{Node, ParseError, Position, Text, Value};
15
16type Result<T> = std::result::Result<T, ParseError>;
17
18impl Node {
19 pub fn from_reader<R: Read>(reader: R) -> Result<Node> {
23 parse(BufReader::new(reader))
24 }
25}
26
27impl TryFrom<&str> for Node {
28 type Error = ParseError;
29
30 fn try_from(text: &str) -> Result<Node> {
31 parse(text.as_bytes())
32 }
33}
34
35impl TryFrom<&[u8]> for Node {
36 type Error = ParseError;
37
38 fn try_from(bytes: &[u8]) -> Result<Node> {
39 parse(bytes)
40 }
41}
42
43impl TryFrom<&Path> for Node {
44 type Error = ParseError;
45
46 fn try_from(path: &Path) -> Result<Node> {
47 let file = File::open(path).map_err(|source| ParseError::Open {
48 path: path.to_owned(),
49 source,
50 })?;
51 Node::from_reader(file)
52 }
53}
54
55impl FromStr for Node {
56 type Err = ParseError;
57
58 fn from_str(text: &str) -> Result<Node> {
59 parse(text.as_bytes())
60 }
61}
62
63fn parse<R: BufRead>(reader: R) -> Result<Node> {
64 let mut parser = Parser::new(reader);
65 parser.input.skip_bom()?;
66 parser.input.skip_ws()?;
67 if parser.input.peek()?.is_none() {
68 return Err(ParseError::EmptyInput);
69 }
70 let node = parser.value()?;
71 parser.input.skip_ws()?;
72 let at = parser.input.pos;
73 match parser.input.peek()? {
74 None => Ok(node),
75 Some(b'}') => Err(ParseError::UnmatchedClose { at }),
76 Some(_) => Err(ParseError::TrailingData { at }),
77 }
78}
79
80pub struct Values<R> {
101 parser: Parser<BufReader<R>>,
102 state: State,
103}
104
105#[derive(Clone, Copy, PartialEq, Eq)]
106enum State {
107 Fresh,
109 BeforeValue,
110 AfterValue,
111 Done,
112}
113
114impl<R: Read> Values<R> {
115 pub fn new(reader: R) -> Self {
116 Values {
117 parser: Parser::new(BufReader::new(reader)),
118 state: State::Fresh,
119 }
120 }
121
122 pub fn read_line(&mut self) -> Result<Option<String>> {
126 self.start()?;
127 let input = &mut self.parser.input;
128 let at = input.pos;
129 if input.peek()?.is_none() {
130 return Ok(None);
131 }
132 let mut bytes = Vec::new();
133 if input.scan(|b| b == b'\n', Some(&mut bytes))?.is_some() {
134 input.bump()?;
135 }
136 if bytes.last() == Some(&b'\r') {
137 bytes.pop();
138 }
139 String::from_utf8(bytes)
140 .map(Some)
141 .map_err(|_| ParseError::InvalidUtf8 {
142 context: "line",
143 at,
144 })
145 }
146
147 pub fn position(&self) -> Position {
149 self.parser.input.pos
150 }
151
152 fn start(&mut self) -> Result<()> {
153 if self.state == State::Fresh {
154 self.parser.input.skip_bom()?;
155 self.state = State::BeforeValue;
156 }
157 Ok(())
158 }
159
160 fn read_value(&mut self) -> Result<Option<Node>> {
161 self.start()?;
162 let input = &mut self.parser.input;
163 input.skip_ws()?;
164 if self.state == State::AfterValue {
165 let at = input.pos;
166 match input.peek()? {
167 None => return Ok(None),
168 Some(b',') => {
169 input.bump()?;
170 input.skip_ws()?;
171 }
172 Some(b'}') => return Err(ParseError::UnmatchedClose { at }),
173 Some(_) => {
174 return Err(ParseError::UnexpectedChar {
175 found: self.parser.char_at_cursor()?,
176 at,
177 });
178 }
179 }
180 }
181 if self.parser.input.peek()?.is_none() {
182 return Ok(None);
183 }
184 let node = self.parser.value()?;
185 self.state = State::AfterValue;
186 Ok(Some(node))
187 }
188}
189
190impl<R: Read> Iterator for Values<R> {
191 type Item = Result<Node>;
192
193 fn next(&mut self) -> Option<Result<Node>> {
194 if self.state == State::Done {
195 return None;
196 }
197 let result = self.read_value();
198 if !matches!(result, Ok(Some(_))) {
199 self.state = State::Done;
200 }
201 result.transpose()
202 }
203}
204
205impl<R: Read> std::iter::FusedIterator for Values<R> {}
206
207fn fill<R: BufRead>(reader: &mut R) -> io::Result<&[u8]> {
209 loop {
210 match reader.fill_buf() {
211 Ok(_) => break,
213 Err(e) if e.kind() == io::ErrorKind::Interrupted => {}
214 Err(e) => return Err(e),
215 }
216 }
217 reader.fill_buf()
218}
219
220struct Input<R> {
222 inner: R,
223 pending: Vec<u8>,
225 pos: Position,
226}
227
228impl<R: BufRead> Input<R> {
229 fn new(inner: R) -> Self {
230 Self {
231 inner,
232 pending: Vec::new(),
233 pos: Position::START,
234 }
235 }
236
237 fn skip_bom(&mut self) -> Result<()> {
238 const BOM: [u8; 3] = [0xEF, 0xBB, 0xBF];
239 for (i, expected) in BOM.into_iter().enumerate() {
240 if self.peek_ahead(i)? != Some(expected) {
241 return Ok(());
242 }
243 }
244 self.pending.clear();
245 self.pos.offset = BOM.len() as u64;
246 Ok(())
247 }
248
249 fn peek_inner(&mut self) -> Result<Option<u8>> {
250 Ok(fill(&mut self.inner)?.first().copied())
251 }
252
253 fn peek(&mut self) -> Result<Option<u8>> {
254 match self.pending.first() {
255 Some(&b) => Ok(Some(b)),
256 None => self.peek_inner(),
257 }
258 }
259
260 fn peek_ahead(&mut self, n: usize) -> Result<Option<u8>> {
262 while self.pending.len() <= n {
263 let Some(b) = self.peek_inner()? else {
264 return Ok(None);
265 };
266 self.inner.consume(1);
267 self.pending.push(b);
268 }
269 Ok(Some(self.pending[n]))
270 }
271
272 fn bump(&mut self) -> Result<Option<u8>> {
273 let byte = if self.pending.is_empty() {
274 let byte = self.peek_inner()?;
275 if byte.is_some() {
276 self.inner.consume(1);
277 }
278 byte
279 } else {
280 Some(self.pending.remove(0))
281 };
282 if let Some(b) = byte {
283 advance_byte(&mut self.pos, b);
284 }
285 Ok(byte)
286 }
287
288 fn skip_ws(&mut self) -> Result<()> {
290 loop {
291 match self.space_len()? {
292 0 => return Ok(()),
293 1 => {
294 self.scan(|b| !is_ascii_space(b), None)?;
295 }
296 len => {
297 for _ in 0..len {
298 self.bump()?;
299 }
300 }
301 }
302 }
303 }
304
305 fn space_len(&mut self) -> Result<usize> {
307 let Some(first) = self.peek()? else {
308 return Ok(0);
309 };
310 let len = match first {
311 b if is_ascii_space(b) => 1,
312 0xC2 => match self.peek_ahead(1)? {
314 Some(0x85 | 0xA0) => 2,
315 _ => 0,
316 },
317 0xE1..=0xE3 => {
319 let (Some(b1), Some(b2)) = (self.peek_ahead(1)?, self.peek_ahead(2)?) else {
320 return Ok(0);
321 };
322 let c = u32::from(first & 0x0F) << 12
323 | u32::from(b1 & 0x3F) << 6
324 | u32::from(b2 & 0x3F);
325 let valid = b1 & 0xC0 == 0x80 && b2 & 0xC0 == 0x80;
326 if valid && char::from_u32(c).is_some_and(is_space) {
327 3
328 } else {
329 0
330 }
331 }
332 _ => 0,
333 };
334 Ok(len)
335 }
336
337 fn scan(
341 &mut self,
342 stop: impl Fn(u8) -> bool,
343 mut out: Option<&mut Vec<u8>>,
344 ) -> Result<Option<u8>> {
345 while let Some(&b) = self.pending.first() {
347 if stop(b) {
348 return Ok(Some(b));
349 }
350 self.bump()?;
351 if let Some(out) = out.as_deref_mut() {
352 out.push(b);
353 }
354 }
355 loop {
356 let buf = fill(&mut self.inner)?;
357 if buf.is_empty() {
358 return Ok(None);
359 }
360 let (len, found) = match buf.iter().position(|&b| stop(b)) {
361 Some(i) => (i, Some(buf[i])),
362 None => (buf.len(), None),
363 };
364 let chunk = &buf[..len];
365 if let Some(out) = out.as_deref_mut() {
366 out.extend_from_slice(chunk);
367 }
368 advance(&mut self.pos, chunk);
369 self.inner.consume(len);
370 if found.is_some() {
371 return Ok(found);
372 }
373 }
374 }
375
376 fn next_code_point(&mut self) -> Result<Option<u32>> {
378 let Some(first) = self.bump()? else {
379 return Ok(None);
380 };
381 let (len, mut c) = match first {
382 0..=0x7F => return Ok(Some(u32::from(first))),
383 0xC0..=0xDF => (2, u32::from(first & 0x1F)),
384 0xE0..=0xEF => (3, u32::from(first & 0x0F)),
385 0xF0..=0xF7 => (4, u32::from(first & 0x07)),
386 _ => return Ok(Some(u32::from(char::REPLACEMENT_CHARACTER))),
387 };
388 for _ in 1..len {
389 match self.peek()? {
390 Some(b) if b & 0xC0 == 0x80 => {
391 self.bump()?;
392 c = c << 6 | u32::from(b & 0x3F);
393 }
394 _ => return Ok(Some(u32::from(char::REPLACEMENT_CHARACTER))),
395 }
396 }
397 Ok(Some(c))
398 }
399}
400
401fn is_ascii_space(b: u8) -> bool {
402 matches!(b, b'\t'..=b'\r' | 0x1C..=b' ')
403}
404
405struct Parser<R> {
406 input: Input<R>,
407 items: Vec<Node>,
412}
413
414impl<R: BufRead> Parser<R> {
415 fn new(inner: R) -> Self {
416 Self {
417 input: Input::new(inner),
418 items: Vec::new(),
419 }
420 }
421
422 fn value(&mut self) -> Result<Node> {
423 match self.input.peek()? {
424 Some(b'{') => self.list(),
425 _ => self.scalar(),
426 }
427 }
428
429 fn list(&mut self) -> Result<Node> {
431 let mut stack: Vec<(Position, usize)> = Vec::new();
433 self.items.clear();
435 loop {
436 let opened = self.input.pos;
438 self.input.bump()?;
439 self.input.skip_ws()?;
440 stack.push((opened, self.items.len()));
441 match self.input.peek()? {
442 Some(b'}') => {}
444 Some(b'{') => continue,
445 _ => {
446 let item = self.scalar()?;
447 self.items.push(item);
448 }
449 }
450 loop {
452 self.input.skip_ws()?;
453 let at = self.input.pos;
454 match self.input.peek()? {
455 Some(b',') => {
456 self.input.bump()?;
457 self.input.skip_ws()?;
458 if self.input.peek()? == Some(b'{') {
459 break;
460 }
461 let item = self.scalar()?;
464 self.items.push(item);
465 }
466 Some(b'}') => {
467 self.input.bump()?;
468 let (opened, first) = stack.pop().expect("list stack is not empty");
469 let items = self.items.drain(first..).collect();
470 let done = Node::parsed(Value::List(items), opened);
471 if stack.is_empty() {
472 return Ok(done);
473 }
474 self.items.push(done);
475 }
476 Some(_) => {
478 return Err(ParseError::UnexpectedChar {
479 found: self.char_at_cursor()?,
480 at,
481 });
482 }
483 None => {
484 let (opened, _) = stack.last().expect("list stack is not empty");
485 return Err(ParseError::UnclosedList {
486 opened: *opened,
487 at,
488 });
489 }
490 }
491 }
492 }
493 }
494
495 fn scalar(&mut self) -> Result<Node> {
496 if self.input.peek()? == Some(b'"') {
497 self.string()
498 } else {
499 self.atom()
500 }
501 }
502
503 fn string(&mut self) -> Result<Node> {
507 let start = self.input.pos;
508 self.input.bump()?;
509 let mut bytes = Vec::new();
510 loop {
511 let part = bytes.len();
512 if self.input.scan(|b| b == b'"', Some(&mut bytes))?.is_none() {
513 return Err(ParseError::UnclosedString { start });
514 }
515 if std::str::from_utf8(&bytes[part..]).is_err() {
516 return Err(ParseError::InvalidUtf8 {
517 context: "quoted string",
518 at: start,
519 });
520 }
521 self.input.bump()?;
522 match self.input.peek()? {
523 Some(b'"') => {
524 self.input.bump()?;
525 bytes.push(b'"');
526 }
527 Some(b'\\') => {
528 let at = self.input.pos;
529 self.input.bump()?;
530 let mut unit = 0;
531 for _ in 0..4 {
532 let digit = self.input.next_code_point()?.and_then(hex_digit);
533 let Some(digit) = digit else {
534 return Err(ParseError::InvalidEscape { at });
535 };
536 unit = unit << 4 | digit;
537 }
538 push_code_point(&mut bytes, unit);
539 }
540 _ => break,
541 }
542 }
543 Ok(Node::parsed(Value::Str(Text::from_wtf8(bytes)), start))
544 }
545
546 fn atom(&mut self) -> Result<Node> {
548 let start = self.input.pos;
549 let mut bytes = Vec::new();
550 self.input
551 .scan(|b| matches!(b, b',' | b'}'), Some(&mut bytes))?;
552 if std::str::from_utf8(&bytes).is_err() {
553 return Err(ParseError::InvalidUtf8 {
554 context: "value",
555 at: start,
556 });
557 }
558 Ok(Node::parsed(Value::Atom(Text::from_wtf8(bytes)), start))
559 }
560
561 fn char_at_cursor(&mut self) -> Result<char> {
563 let c = self.input.next_code_point()?;
564 Ok(c.and_then(char::from_u32)
565 .unwrap_or(char::REPLACEMENT_CHARACTER))
566 }
567}
568
569fn hex_digit(c: u32) -> Option<u32> {
572 match c {
573 0x30..=0x39 => Some(c - 0x30),
574 0x41..=0x46 => Some(c - 0x41 + 10),
575 0x61..=0x66 => Some(c - 0x61 + 10),
576 0xFF21..=0xFF26 => Some(c - 0xFF21 + 10),
577 0xFF41..=0xFF46 => Some(c - 0xFF41 + 10),
578 _ => DIGIT_ZEROS
579 .iter()
580 .find(|&&zero| (zero..zero + 10).contains(&c))
581 .map(|zero| c - zero),
582 }
583}
584
585const DIGIT_ZEROS: [u32; 34] = [
588 0x0660, 0x06F0, 0x07C0, 0x0966, 0x09E6, 0x0A66, 0x0AE6, 0x0B66, 0x0BE6, 0x0C66, 0x0CE6, 0x0D66,
589 0x0E50, 0x0ED0, 0x0F20, 0x1040, 0x1090, 0x17E0, 0x1810, 0x1946, 0x19D0, 0x1A80, 0x1A90, 0x1B50,
590 0x1BB0, 0x1C40, 0x1C50, 0xA620, 0xA8D0, 0xA900, 0xA9D0, 0xAA50, 0xABF0, 0xFF10,
591];
592
593fn advance_byte(pos: &mut Position, byte: u8) {
595 pos.offset += 1;
596 if byte == b'\n' {
597 pos.line += 1;
598 pos.column = 1;
599 } else if byte & 0xC0 != 0x80 {
600 pos.column += 1;
602 }
603}
604
605fn advance(pos: &mut Position, bytes: &[u8]) {
607 let chars = |bytes: &[u8]| bytes.iter().filter(|&&b| b & 0xC0 != 0x80).count() as u64;
609 pos.offset += bytes.len() as u64;
610 match bytes.iter().rposition(|&b| b == b'\n') {
611 Some(last) => {
612 pos.line += bytes.iter().filter(|&&b| b == b'\n').count() as u64;
613 pos.column = 1 + chars(&bytes[last + 1..]);
614 }
615 None => pos.column += chars(bytes),
616 }
617}
618#[cfg(test)]
619mod tests {
620 use super::*;
621
622 fn atom(s: &str) -> Node {
623 Node::atom(s)
624 }
625
626 struct ByteByByte<'a>(&'a [u8]);
628
629 impl Read for ByteByByte<'_> {
630 fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
631 match (self.0.split_first(), buf.first_mut()) {
632 (Some((&b, rest)), Some(slot)) => {
633 *slot = b;
634 self.0 = rest;
635 Ok(1)
636 }
637 _ => Ok(0),
638 }
639 }
640 }
641
642 #[test]
643 fn parses_values() {
644 let node: Node = "\u{feff}{1,{\"a \"\"b\"\"\",x},{},}".parse().unwrap();
645 assert_eq!(
646 node,
647 Node::list([
648 atom("1"),
649 Node::list([Node::string("a \"b\""), atom("x")]),
650 Node::list([]),
651 atom(""),
652 ])
653 );
654 }
655
656 #[test]
657 fn keeps_base64_with_line_breaks() {
658 let node = Node::try_from("{1,\r\n{#base64:QUJD\r\r\nREVG\r\r\n},2}").unwrap();
659 assert_eq!(
660 node.get_path(&[1, 0]).and_then(Node::as_str),
661 Some("#base64:QUJD\r\r\nREVG\r\r\n")
662 );
663 assert_eq!(node[2].as_i64(), Some(2));
664 }
665
666 #[test]
667 fn atoms_run_to_comma_or_brace() {
668 let node = Node::try_from("{1 , 2\r\n}").unwrap();
669 assert_eq!(node, Node::list([atom("1 "), atom("2\r\n")]));
670 assert_eq!(node[1].as_atom_trimmed(), Some("2"));
671 assert_eq!(node[1].as_i64(), Some(2));
672 assert_eq!(node.to_string(), "{1 ,2\r\n}");
673
674 let node = Node::try_from("{a{b,{x\"y\",1}}").unwrap();
675 assert_eq!(
676 node,
677 Node::list([atom("a{b"), Node::list([atom("x\"y\""), atom("1")])])
678 );
679 let node = Node::try_from("{\u{3000}\"a\"\u{a0},\u{2028}{}\u{85}, b}").unwrap();
681 assert_eq!(
682 node,
683 Node::list([Node::string("a"), Node::list([]), atom("b")])
684 );
685 assert_eq!(
686 Node::from_reader(ByteByByte("{\u{2003}x\u{2003}}".as_bytes())).unwrap(),
687 Node::list([atom("x\u{2003}")])
688 );
689 }
690
691 #[test]
692 fn empty_items() {
693 let items = |text: &str| Node::try_from(text).unwrap().into_list().unwrap();
694 assert_eq!(items("{}"), []);
695 assert_eq!(items("{ \r\n}"), []);
696 assert_eq!(items("{,}"), [atom(""), atom("")]);
698 assert_eq!(items("{a,}"), [atom("a"), atom("")]);
699 assert_eq!(items("{,a}"), [atom(""), atom("a")]);
700 assert_eq!(items("{,,}").len(), 3);
701 }
702
703 #[test]
704 fn unescapes_utf16_code_units() {
705 let node = Node::try_from(r#"{"a"\d83d"\de00b",""""\D800"""}"#).unwrap();
706 assert_eq!(node[0].as_quoted(), Some("a😀b"));
707 assert_eq!(node[0].to_string(), r#""a"\d83d"\de00b""#);
708 let lone = node[1].as_text().unwrap();
710 let units = [u16::from(b'"'), 0xD800, u16::from(b'"')];
711 assert_eq!(lone.encode_utf16().collect::<Vec<_>>(), units);
712 assert_eq!(node[1].as_str(), None);
713 assert_eq!(node[1].to_string(), r#"""""\d800""""#);
714 assert_eq!(
716 Node::try_from(r#""""\d800""#).unwrap().as_quoted(),
717 Some(r#""\d800"#)
718 );
719 let node = Node::string(Text::from_utf16(&units[1..]));
720 assert_eq!(node.to_string(), r#"""\d800""""#);
721 assert_eq!(Node::try_from(node.to_string().as_str()).unwrap(), node);
722
723 let node = Node::try_from(r#"""\004f"\٠٠٤١""#).unwrap();
725 assert_eq!(node.as_quoted(), Some("OA"));
726 }
727
728 #[test]
729 fn reads_only_utf8() {
730 let err = Node::try_from(&[0xFF, 0xFE, b'{', 0, b'}', 0][..]).unwrap_err();
732 assert!(matches!(err, ParseError::InvalidUtf8 { .. }), "{err}");
733 let err = Node::try_from(&b"{\"\xED\xA0\x80\"}"[..]).unwrap_err();
735 assert!(matches!(err, ParseError::InvalidUtf8 { .. }), "{err}");
736 }
737
738 #[test]
739 fn deep_nesting_without_recursion() {
740 let depth = 5_000;
741 let text = format!("{}{}", "{".repeat(depth), "}".repeat(depth));
742 assert!(Node::try_from(text.as_str()).is_ok());
743 }
744
745 #[test]
746 fn reads_byte_by_byte() {
747 let text = "\u{feff}{1,\r\n{\"ру\"\"с\",#base64:AB\r\r\nC},Ж,\"\"}";
748 let expected = Node::try_from(text).unwrap();
749 let node = Node::from_reader(ByteByByte(text.as_bytes())).unwrap();
750 assert_eq!(node, expected);
751 }
752
753 #[test]
754 fn partial_bom_is_part_of_value() {
755 let node = Node::try_from("\u{f000}").unwrap();
757 assert_eq!(node, atom("\u{f000}"));
758 }
759
760 #[test]
761 fn propagates_io_errors() {
762 struct Failing;
763 impl Read for Failing {
764 fn read(&mut self, _: &mut [u8]) -> io::Result<usize> {
765 Err(io::Error::other("disk is on fire"))
766 }
767 }
768 let err = Node::from_reader(Failing).unwrap_err();
769 assert!(matches!(err, ParseError::Io(_)));
770 insta::assert_snapshot!(err, @"I/O error while reading input: disk is on fire");
771 }
772
773 #[test]
774 fn rejects_broken_input() {
775 assert!(Node::try_from("{1,2").is_err());
776 assert!(Node::try_from("{\"abc}").is_err());
777 assert!(Node::try_from("{1}}").is_err());
778 }
779
780 #[test]
781 fn reads_value_sequences() {
782 let text = "\u{feff}HEAD\r\n\r\n{1},\r\n{2,\"x\"},\r\nz,\r\n";
783 let mut values = Values::new(ByteByByte(text.as_bytes()));
784 assert_eq!(values.read_line().unwrap().as_deref(), Some("HEAD"));
785 assert_eq!(values.read_line().unwrap().as_deref(), Some(""));
786 let nodes: Vec<Node> = values.map(Result::unwrap).collect();
787 assert_eq!(
788 nodes,
789 [
790 Node::list([atom("1")]),
791 Node::list([atom("2"), Node::string("x")]),
792 atom("z")
793 ]
794 );
795 assert_eq!(nodes[1].position().unwrap().line, 4);
796
797 assert_eq!(Values::new("".as_bytes()).count(), 0);
798 let mut values = Values::new("{1}\r\n{2}".as_bytes());
799 assert!(values.next().unwrap().is_ok());
800 insta::assert_snapshot!(values.next().unwrap().unwrap_err(), @"unexpected character '{' at line 2, column 1: expected ',' or '}'");
801 assert!(values.next().is_none());
802 let err = Values::new("{1},{2".as_bytes())
803 .nth(1)
804 .unwrap()
805 .unwrap_err();
806 insta::assert_snapshot!(err, @"unexpected end of input at line 1, column 7: list opened at line 1, column 5 is not closed");
807 }
808
809 #[test]
810 fn reports_positions() {
811 let err = Node::try_from("{1,\r\n{2,\r\n 3").unwrap_err();
812 insta::assert_snapshot!(err, @"unexpected end of input at line 3, column 4: list opened at line 2, column 1 is not closed");
813 let err = Node::try_from("{\"ёж\" x}").unwrap_err();
814 insta::assert_snapshot!(err, @"unexpected character 'x' at line 1, column 7: expected ',' or '}'");
815 assert_eq!(err.position().map(|p| p.offset), Some(8));
816 }
817}