1#![allow(dead_code)]
3
4extern crate alloc;
5use alloc::collections::BTreeMap;
6use alloc::string::String;
7use alloc::vec::Vec;
8use core::iter::Peekable;
9use core::str::Chars;
10
11#[derive(Debug, Clone, PartialEq)]
12pub enum JsonValue {
13 Null,
14 Bool(bool),
15 Number(f64),
16 String(String),
17 Array(Vec<JsonValue>),
18 Object(BTreeMap<String, JsonValue>),
19}
20
21pub fn parse(input: &str) -> Result<JsonValue, String> {
22 let mut chars = input.chars().peekable();
23 parse_value(&mut chars, 0)
24}
25
26pub use parse as parse_json;
27
28fn skip_whitespace(chars: &mut Peekable<Chars>) {
29 while let Some(&c) = chars.peek() {
30 if c.is_whitespace() {
31 chars.next();
32 } else {
33 break;
34 }
35 }
36}
37
38fn parse_value(chars: &mut Peekable<Chars>, depth: usize) -> Result<JsonValue, String> {
45 if depth > 30 {
46 return Err(String::from("Maximum nesting depth exceeded"));
47 }
48 skip_whitespace(chars);
49 match chars.peek() {
50 Some(&'n') => parse_null(chars),
51 Some(&'t') | Some(&'f') => parse_bool(chars),
52 Some(&'"') => parse_string(chars).map(JsonValue::String),
53 Some(&'[') => parse_array(chars, depth),
54 Some(&'{') => parse_object(chars, depth),
55 Some(&c) if c == '-' || c.is_ascii_digit() => parse_number(chars),
56 Some(c) => Err(alloc::format!("Unexpected character: {}", c)),
57 None => Err(String::from("Unexpected end of input")),
58 }
59}
60
61fn parse_null(chars: &mut Peekable<Chars>) -> Result<JsonValue, String> {
62 let expected = "null";
63 for ec in expected.chars() {
64 if chars.next() != Some(ec) {
65 return Err(String::from("Expected null"));
66 }
67 }
68 Ok(JsonValue::Null)
69}
70
71fn parse_bool(chars: &mut Peekable<Chars>) -> Result<JsonValue, String> {
72 let is_true = chars.peek() == Some(&'t');
73 let expected = if is_true { "true" } else { "false" };
74 for ec in expected.chars() {
75 if chars.next() != Some(ec) {
76 return Err(String::from("Expected bool"));
77 }
78 }
79 Ok(JsonValue::Bool(is_true))
80}
81
82fn parse_string(chars: &mut Peekable<Chars>) -> Result<String, String> {
83 chars.next(); let mut s = String::new();
85 while let Some(&c) = chars.peek() {
86 if c == '"' {
87 chars.next();
88 return Ok(s);
89 } else if c == '\\' {
90 chars.next();
91 if let Some(ec) = chars.next() {
92 match ec {
93 '"' => s.push('"'),
94 '\\' => s.push('\\'),
95 '/' => s.push('/'),
96 'b' => s.push('\x08'),
97 'f' => s.push('\x0C'),
98 'n' => s.push('\n'),
99 'r' => s.push('\r'),
100 't' => s.push('\t'),
101 _ => s.push(ec), }
103 } else {
104 return Err(String::from("Unexpected end of input in escape sequence"));
105 }
106 } else {
107 s.push(c);
108 chars.next();
109 }
110 }
111 Err(String::from("Unterminated string"))
112}
113
114fn parse_number(chars: &mut Peekable<Chars>) -> Result<JsonValue, String> {
115 let mut buf = [0u8; 64];
116 let mut len = 0usize;
117 while let Some(&c) = chars.peek() {
118 if c == '-' || c == '+' || c == '.' || c == 'e' || c == 'E' || c.is_ascii_digit() {
119 if len < buf.len() && c.is_ascii() {
120 buf[len] = c as u8;
121 len += 1;
122 }
123 chars.next();
124 } else {
125 break;
126 }
127 }
128 if let Ok(s) = core::str::from_utf8(&buf[..len]) {
129 match s.parse::<f64>() {
130 Ok(n) => Ok(JsonValue::Number(n)),
131 Err(_) => Err(alloc::format!("Invalid number: {}", s)),
132 }
133 } else {
134 Err(String::from("Invalid UTF-8 in number"))
135 }
136}
137
138fn parse_array(chars: &mut Peekable<Chars>, depth: usize) -> Result<JsonValue, String> {
139 chars.next(); let mut arr = Vec::new();
141 skip_whitespace(chars);
142 if chars.peek() == Some(&']') {
143 chars.next();
144 return Ok(JsonValue::Array(arr));
145 }
146 loop {
147 arr.push(parse_value(chars, depth + 1)?);
148 skip_whitespace(chars);
149 match chars.next() {
150 Some(',') => continue,
151 Some(']') => break,
152 _ => return Err(String::from("Expected ',' or ']' in array")),
153 }
154 }
155 Ok(JsonValue::Array(arr))
156}
157
158fn parse_object(chars: &mut Peekable<Chars>, depth: usize) -> Result<JsonValue, String> {
159 chars.next(); let mut obj = BTreeMap::new();
161 skip_whitespace(chars);
162 if chars.peek() == Some(&'}') {
163 chars.next();
164 return Ok(JsonValue::Object(obj));
165 }
166 loop {
167 skip_whitespace(chars);
168 if chars.peek() != Some(&'"') {
169 return Err(String::from("Expected string key in object"));
170 }
171 let key = parse_string(chars)?;
172 skip_whitespace(chars);
173 if chars.next() != Some(':') {
174 return Err(String::from("Expected ':' after key"));
175 }
176 let val = parse_value(chars, depth + 1)?;
177 obj.insert(key, val);
178 skip_whitespace(chars);
179 match chars.next() {
180 Some(',') => continue,
181 Some('}') => break,
182 _ => return Err(String::from("Expected ',' or '}' in object")),
183 }
184 }
185 Ok(JsonValue::Object(obj))
186}
187
188pub fn to_string(value: &JsonValue) -> String {
189 let mut out = String::new();
190 stringify_to(value, &mut out);
191 out
192}
193
194pub fn stringify_to(value: &JsonValue, out: &mut String) {
195 match value {
196 JsonValue::Null => out.push_str("null"),
197 JsonValue::Bool(true) => out.push_str("true"),
198 JsonValue::Bool(false) => out.push_str("false"),
199 JsonValue::Number(n) => {
200 use core::fmt::Write;
201 let _ = write!(out, "{}", n);
202 }
203 JsonValue::String(s) => {
204 out.push('"');
205 for c in s.chars() {
206 match c {
207 '"' => out.push_str("\\\""),
208 '\\' => out.push_str("\\\\"),
209 '\n' => out.push_str("\\n"),
210 '\r' => out.push_str("\\r"),
211 '\t' => out.push_str("\\t"),
212 c => out.push(c),
213 }
214 }
215 out.push('"');
216 }
217 JsonValue::Array(arr) => {
218 out.push('[');
219 for (i, v) in arr.iter().enumerate() {
220 if i > 0 {
221 out.push_str(", ");
222 }
223 stringify_to(v, out);
224 }
225 out.push(']');
226 }
227 JsonValue::Object(obj) => {
228 out.push('{');
229 let mut first = true;
230 for (k, v) in obj.iter() {
231 if !first {
232 out.push_str(", ");
233 }
234 first = false;
235 out.push('"');
236 out.push_str(k);
237 out.push_str("\": ");
238 stringify_to(v, out);
239 }
240 out.push('}');
241 }
242 }
243}