Skip to main content

json_syntax/parse/
number.rs

1use super::{JsonParse, JsonParseError, JsonParsingContext, Parser};
2use crate::{JsonNumberBuf, number::JsonNumberRawBuffer};
3use decoded_char::DecodedChar;
4
5impl JsonParse for JsonNumberBuf {
6	fn parse_in<C, E>(
7		parser: &mut Parser<C, E>,
8		context: JsonParsingContext,
9	) -> Result<(Self, usize), JsonParseError<E>>
10	where
11		C: Iterator<Item = Result<DecodedChar, E>>,
12	{
13		let i = parser.begin_fragment();
14		let mut buffer = JsonNumberRawBuffer::new();
15
16		enum State {
17			Init,
18			FirstDigit,
19			Zero,
20			NonZero,
21			FractionalFirst,
22			FractionalRest,
23			ExponentSign,
24			ExponentFirst,
25			ExponentRest,
26		}
27
28		let mut state = State::Init;
29
30		while let Some(c) = parser.peek_char()? {
31			match state {
32				State::Init => match c {
33					'-' => state = State::FirstDigit,
34					'0' => state = State::Zero,
35					'1'..='9' => state = State::NonZero,
36					_ => return Err(JsonParseError::unexpected(parser.position, Some(c))),
37				},
38				State::FirstDigit => match c {
39					'0' => state = State::Zero,
40					'1'..='9' => state = State::NonZero,
41					_ => return Err(JsonParseError::unexpected(parser.position, Some(c))),
42				},
43				State::Zero => match c {
44					'.' => state = State::FractionalFirst,
45					'e' | 'E' => state = State::ExponentSign,
46					_ => {
47						if context.follows(c) {
48							break;
49						} else {
50							return Err(JsonParseError::unexpected(parser.position, Some(c)));
51						}
52					}
53				},
54				State::NonZero => match c {
55					'0'..='9' => state = State::NonZero,
56					'.' => state = State::FractionalFirst,
57					'e' | 'E' => state = State::ExponentSign,
58					_ => {
59						if context.follows(c) {
60							break;
61						} else {
62							return Err(JsonParseError::unexpected(parser.position, Some(c)));
63						}
64					}
65				},
66				State::FractionalFirst => match c {
67					'0'..='9' => state = State::FractionalRest,
68					_ => return Err(JsonParseError::unexpected(parser.position, Some(c))),
69				},
70				State::FractionalRest => match c {
71					'0'..='9' => state = State::FractionalRest,
72					'e' | 'E' => state = State::ExponentSign,
73					_ => {
74						if context.follows(c) {
75							break;
76						} else {
77							return Err(JsonParseError::unexpected(parser.position, Some(c)));
78						}
79					}
80				},
81				State::ExponentSign => match c {
82					'+' | '-' => state = State::ExponentFirst,
83					'0'..='9' => state = State::ExponentRest,
84					_ => return Err(JsonParseError::unexpected(parser.position, Some(c))),
85				},
86				State::ExponentFirst => match c {
87					'0'..='9' => state = State::ExponentRest,
88					_ => return Err(JsonParseError::unexpected(parser.position, Some(c))),
89				},
90				State::ExponentRest => match c {
91					'0'..='9' => state = State::ExponentRest,
92					_ => {
93						if context.follows(c) {
94							break;
95						} else {
96							return Err(JsonParseError::unexpected(parser.position, Some(c)));
97						}
98					}
99				},
100			}
101
102			// u8 conversion is safe since a number is composed of ASCII chars.
103			buffer.push(c as u8);
104			parser.next_char()?;
105		}
106
107		if matches!(
108			state,
109			State::Zero | State::NonZero | State::FractionalRest | State::ExponentRest
110		) {
111			parser.end_fragment(i);
112			Ok((unsafe { JsonNumberBuf::new_unchecked(buffer) }, i))
113		} else {
114			Err(JsonParseError::unexpected(parser.position, None))
115		}
116	}
117}