df_hyperliquid_core/utils/json/
parse.rs1use crate::utils::json::Json;
5
6#[derive(Debug, Clone, PartialEq, Eq, thiserror::Error)]
8#[error("line {line}, column {column}: {message}")]
9pub struct BadJson {
10 pub line: usize,
11 pub column: usize,
12 pub message: String,
13}
14
15impl Json {
16 pub fn parse(text: &str) -> Result<Json, BadJson> {
17 let mut reader = Reader { text: text.as_bytes(), at: 0, source: text };
18 reader.space();
19 let value = reader.value(0)?;
20 reader.space();
21 if reader.at < reader.text.len() {
22 return Err(reader.fail("more after the value ends"));
23 }
24 Ok(value)
25 }
26}
27
28const DEEPEST: usize = 128;
30
31struct Reader<'a> {
32 text: &'a [u8],
33 at: usize,
34 source: &'a str,
35}
36
37impl Reader<'_> {
38 fn fail(&self, message: &str) -> BadJson {
39 let before = self.source.get(..self.at).unwrap_or(self.source);
40 let line = before.matches('\n').count() + 1;
41 let column = before.rsplit('\n').next().map_or(0, |tail| tail.chars().count()) + 1;
42 BadJson { line, column, message: message.to_owned() }
43 }
44
45 fn peek(&self) -> Option<u8> {
46 self.text.get(self.at).copied()
47 }
48
49 fn space(&mut self) {
50 while matches!(self.peek(), Some(b' ' | b'\n' | b'\r' | b'\t')) {
51 self.at += 1;
52 }
53 }
54
55 fn expect(&mut self, word: &str) -> Result<(), BadJson> {
56 match self.text[self.at..].starts_with(word.as_bytes()) {
57 true => {
58 self.at += word.len();
59 Ok(())
60 }
61 false => Err(self.fail(&format!("expected {word}"))),
62 }
63 }
64
65 fn value(&mut self, depth: usize) -> Result<Json, BadJson> {
66 if depth > DEEPEST {
67 return Err(self.fail("nested too deep"));
68 }
69 match self.peek() {
70 None => Err(self.fail("the text ends where a value should be")),
71 Some(b'n') => self.expect("null").map(|()| Json::Null),
72 Some(b't') => self.expect("true").map(|()| Json::Bool(true)),
73 Some(b'f') => self.expect("false").map(|()| Json::Bool(false)),
74 Some(b'"') => self.string().map(Json::String),
75 Some(b'[') => self.array(depth),
76 Some(b'{') => self.object(depth),
77 Some(b'-' | b'0'..=b'9') => self.number(),
78 Some(_) => Err(self.fail("not the start of a value")),
79 }
80 }
81
82 fn array(&mut self, depth: usize) -> Result<Json, BadJson> {
83 self.at += 1;
84 let mut items = Vec::new();
85 self.space();
86 if self.peek() == Some(b']') {
87 self.at += 1;
88 return Ok(Json::Array(items));
89 }
90 loop {
91 self.space();
92 items.push(self.value(depth + 1)?);
93 self.space();
94 match self.peek() {
95 Some(b',') => self.at += 1,
96 Some(b']') => {
97 self.at += 1;
98 return Ok(Json::Array(items));
99 }
100 _ => return Err(self.fail("expected , or ] in an array")),
101 }
102 }
103 }
104
105 fn object(&mut self, depth: usize) -> Result<Json, BadJson> {
106 self.at += 1;
107 let mut entries: Vec<(String, Json)> = Vec::new();
108 self.space();
109 if self.peek() == Some(b'}') {
110 self.at += 1;
111 return Ok(Json::Object(entries));
112 }
113 loop {
114 self.space();
115 if self.peek() != Some(b'"') {
116 return Err(self.fail("expected a key in quotes"));
117 }
118 let key = self.string()?;
119 if entries.iter().any(|(seen, _)| *seen == key) {
120 return Err(self.fail(&format!("the key {key:?} is written twice")));
121 }
122 self.space();
123 if self.peek() != Some(b':') {
124 return Err(self.fail("expected : after a key"));
125 }
126 self.at += 1;
127 self.space();
128 let value = self.value(depth + 1)?;
129 entries.push((key, value));
130 self.space();
131 match self.peek() {
132 Some(b',') => self.at += 1,
133 Some(b'}') => {
134 self.at += 1;
135 return Ok(Json::Object(entries));
136 }
137 _ => return Err(self.fail("expected , or } in an object")),
138 }
139 }
140 }
141
142 fn number(&mut self) -> Result<Json, BadJson> {
143 let start = self.at;
144 if self.peek() == Some(b'-') {
145 self.at += 1;
146 }
147 let digits = |reader: &mut Self| {
148 let from = reader.at;
149 while matches!(reader.peek(), Some(b'0'..=b'9')) {
150 reader.at += 1;
151 }
152 reader.at - from
153 };
154 let whole = self.at;
155 if digits(self) == 0 {
156 return Err(self.fail("a number needs digits"));
157 }
158 if self.text[whole] == b'0' && self.at - whole > 1 {
159 return Err(self.fail("a number does not start with 0"));
160 }
161 if self.peek() == Some(b'.') {
162 self.at += 1;
163 if digits(self) == 0 {
164 return Err(self.fail("digits must follow the point"));
165 }
166 }
167 if matches!(self.peek(), Some(b'e' | b'E')) {
168 self.at += 1;
169 if matches!(self.peek(), Some(b'+' | b'-')) {
170 self.at += 1;
171 }
172 if digits(self) == 0 {
173 return Err(self.fail("digits must follow the exponent"));
174 }
175 }
176 Ok(Json::Number(self.source[start..self.at].to_owned()))
177 }
178
179 fn string(&mut self) -> Result<String, BadJson> {
180 self.at += 1;
181 let mut out = String::new();
182 loop {
183 let start = self.at;
184 while !matches!(self.peek(), None | Some(b'"' | b'\\')) {
185 if self.text[self.at] < 0x20 {
186 return Err(self.fail("a raw control character inside a string"));
187 }
188 self.at += 1;
189 }
190 out.push_str(&self.source[start..self.at]);
191 match self.peek() {
192 None => return Err(self.fail("a string that never closes")),
193 Some(b'"') => {
194 self.at += 1;
195 return Ok(out);
196 }
197 _ => {
198 self.at += 1;
199 let escaped = self.peek().ok_or_else(|| self.fail("a string that never closes"))?;
200 self.at += 1;
201 match escaped {
202 b'"' => out.push('"'),
203 b'\\' => out.push('\\'),
204 b'/' => out.push('/'),
205 b'b' => out.push('\u{08}'),
206 b'f' => out.push('\u{0c}'),
207 b'n' => out.push('\n'),
208 b'r' => out.push('\r'),
209 b't' => out.push('\t'),
210 b'u' => out.push(self.unicode()?),
211 _ => return Err(self.fail("not an escape JSON knows")),
212 }
213 }
214 }
215 }
216 }
217
218 fn unicode(&mut self) -> Result<char, BadJson> {
219 let first = self.four()?;
220 if (0xd800..0xdc00).contains(&first) {
221 if !self.text[self.at..].starts_with(b"\\u") {
222 return Err(self.fail("half of a surrogate pair"));
223 }
224 self.at += 2;
225 let second = self.four()?;
226 if !(0xdc00..0xe000).contains(&second) {
227 return Err(self.fail("half of a surrogate pair"));
228 }
229 let joined = 0x10000 + ((first - 0xd800) << 10) + (second - 0xdc00);
230 return char::from_u32(joined).ok_or_else(|| self.fail("not a character"));
231 }
232 char::from_u32(first).ok_or_else(|| self.fail("half of a surrogate pair"))
233 }
234
235 fn four(&mut self) -> Result<u32, BadJson> {
236 let digits = self.source.get(self.at..self.at + 4).ok_or_else(|| self.fail("\\u needs four hex digits"))?;
237 let value = u32::from_str_radix(digits, 16).map_err(|_| self.fail("\\u needs four hex digits"))?;
238 self.at += 4;
239 Ok(value)
240 }
241}
242
243#[cfg(test)]
244#[path = "tests/parse.rs"]
245mod tests;