1#![no_std]
2
3use embedded_io::Write;
4use numtoa::base10;
5
6#[derive(Debug,PartialEq,Eq,Clone,Copy)]
8pub enum JsonValue<'a> {
9 String(&'a str),
10 Boolean(bool),
11 Number(i64),
12}
13
14#[derive(Debug,PartialEq,Eq,Clone,Copy)]
16pub struct JsonField<'a,'b> {
17 pub key: &'a str,
18 pub value: JsonValue<'b>,
19}
20
21impl <'a,'b> JsonField<'a,'b> {
22 pub fn new(key: &'a str, value: JsonValue<'b>) -> Self {
24 JsonField { key, value }
25 }
26 pub fn new_string(key: &'a str, value: &'b str) -> Self {
28 Self::new(key, JsonValue::String(value))
29 }
30 pub fn new_number(key: &'a str, value: i64) -> Self {
32 Self::new(key, JsonValue::Number(value))
33 }
34 pub fn new_boolean(key: &'a str, value: bool) -> Self {
36 Self::new(key, JsonValue::Boolean(value))
37 }
38}
39
40#[derive(Debug)]
42pub struct JsonObject<'a,const MAX_FIELDS: usize> {
43 fields: [JsonField<'a,'a>; MAX_FIELDS],
44 num_fields: usize,
45}
46
47#[derive(Debug)]
48pub enum JsonParseFailure {
49 Incomplete,
50 TooManyFields,
51 InvalidStructure,
52 InvalidStringField,
53 InvalidNumericField,
54 InvalidBooleanField,
55}
56
57pub const EMPTY_FIELD: JsonField<'static,'static> = JsonField{ key: "", value: JsonValue::Number(0)};
59
60impl <'a,'b> Default for JsonField<'a,'b> {
61 fn default() -> Self {
62 EMPTY_FIELD
63 }
64}
65
66impl<'a,const MAX_FIELDS: usize> Default for JsonObject<'a,MAX_FIELDS> {
67 fn default() -> Self {
68 Self::new()
69 }
70}
71
72impl <'a,const MAX_FIELDS: usize> JsonObject<'a,MAX_FIELDS> {
73
74 pub const fn new() -> Self {
75 JsonObject { fields: [EMPTY_FIELD; MAX_FIELDS], num_fields: 0 }
76 }
77
78 pub const fn as_slice(&self) -> &[JsonField<'a,'a>] {
79 self.fields.split_at(self.num_fields).0
80 }
81
82 pub const fn as_mut_slice(&mut self) -> &mut [JsonField<'a,'a>] {
83 self.fields.split_at_mut(self.num_fields).0
84 }
85
86 pub const fn push<'x: 'a,'y: 'a>(&mut self, field: JsonField<'x,'y>) -> Result<(),JsonField<'x,'y>> {
87 if self.num_fields == MAX_FIELDS {
88 return Err(field);
89 }
90 self.fields[self.num_fields] = field;
91 self.num_fields += 1;
92 Ok(())
93 }
94
95 pub fn pop(&mut self) -> Option<JsonField<'a,'a>> {
96 if self.num_fields == 0 {
97 return None;
98 }
99 let field = core::mem::take(&mut self.fields[self.num_fields]);
100 self.num_fields -= 1;
101 Some(field)
102 }
103
104 pub const fn push_field(&mut self, key: &'a str, value: JsonValue<'a>) -> Result<(),()> {
105 if self.num_fields == MAX_FIELDS {
106 return Err(());
107 }
108 self.fields[self.num_fields] = JsonField { key, value: value };
109 self.num_fields += 1;
110 Ok(())
111 }
112
113 pub fn parse_from(data: &'a [u8]) -> Result<(usize,Self),JsonParseFailure> {
114 let mut fields = [EMPTY_FIELD; MAX_FIELDS];
115 let (n, num_fields) = parse_json_object(data, fields.as_mut_slice())?;
116 let ret = Self {
117 fields,
118 num_fields
119 };
120 Ok((n,ret))
121 }
122
123 pub fn serialize_blocking<T: Write>(&self, output: T) -> Result<usize,T::Error> {
124 write_json_map(output, self.as_slice())
125 }
126
127}
128
129
130fn skip_json_string(index: &mut usize, data: &[u8]) -> Result<(),JsonParseFailure> {
131 let mut last_char_escape = false;
132 while *index < data.len() {
133 if data[*index] == b'\\' && !last_char_escape {
134 last_char_escape = true;
135 } else if data[*index] == b'"' && !last_char_escape {
136 return Ok(());
137 } else if !data[*index].is_ascii() {
138 return Err(JsonParseFailure::InvalidStringField);
139 } else {
140 last_char_escape = false
141 }
142 *index += 1;
143 }
144 Err(JsonParseFailure::Incomplete)
145}
146
147fn skip_json_numeric(index: &mut usize, data: &[u8]) -> Result<(),JsonParseFailure> {
148 while *index < data.len() && data[*index] <= b'9' && data[*index] >= b'0' {
149 *index += 1;
150 }
151 if *index == data.len() {
152 Err(JsonParseFailure::Incomplete)
153 } else if data[*index].is_ascii_whitespace() || data[*index] == b',' || data[*index] == b'}' {
154 Ok(())
155 } else {
156 Err(JsonParseFailure::InvalidNumericField)
157 }
158}
159
160fn skip_json_boolean(index: &mut usize, data: &[u8], value: bool) -> Result<(),JsonParseFailure> {
161 let start = *index;
162 let target = if value { "true" } else { "false" };
163 while (*index - start) < target.len() {
164 if *index >= data.len() {
165 return Err(JsonParseFailure::Incomplete)
166 }
167 if data[*index] != target.as_bytes()[*index-start] {
168 return Err(JsonParseFailure::InvalidBooleanField);
169 }
170 *index += 1;
171 }
172 Ok(())
173}
174
175fn skip_whitespace(index: &mut usize, data: &[u8]) -> Result<(),JsonParseFailure> {
176 while *index < data.len() && data[*index].is_ascii_whitespace() {
177 *index += 1;
178 }
179 if *index == data.len() {
180 Err(JsonParseFailure::Incomplete)
181 } else {
182 Ok(())
183 }
184}
185
186pub fn parse_json_object<'a>(data: &'a [u8], field_buffer: &mut [JsonField<'a,'a>]) -> Result<(usize,usize),JsonParseFailure> {
188 let mut current_data_index = 0;
189 let mut current_field_index = 0;
190 let mut map_entry_needs_comma = false;
191 skip_whitespace(&mut current_data_index, data)?;
192 if data[current_data_index] != b'{' {
193 return Err(JsonParseFailure::InvalidStructure);
194 }
195 let _map_start_index = current_data_index;
196 current_data_index += 1;
197 while current_data_index < data.len() {
198 skip_whitespace(&mut current_data_index, data)?;
199 if data[current_data_index] == b'}' {
200 return Ok((current_data_index+1,current_field_index))
201 } else if map_entry_needs_comma {
202 if data[current_data_index] != b',' {
203 return Err(JsonParseFailure::InvalidStructure);
204 }
205 current_data_index += 1;
206 map_entry_needs_comma = false;
207 } else {
208 map_entry_needs_comma = true;
209 let key_start_quote_index = current_data_index;
210 current_data_index += 1;
211 skip_json_string(&mut current_data_index, data)?;
212 let key_end_quote_index = current_data_index;
213 let string_key = core::str::from_utf8(&data[key_start_quote_index+1..key_end_quote_index]).expect("skipped json object key string");
214 current_data_index += 1;
215 skip_whitespace(&mut current_data_index, data)?;
216 if data[current_data_index] != b':' {
217 return Err(JsonParseFailure::InvalidStructure);
218 }
219 current_data_index += 1;
220 skip_whitespace(&mut current_data_index, data)?;
221
222 if data[current_data_index] == b'"' {
223 let value_start_quote_index = current_data_index;
224 current_data_index += 1;
225 skip_json_string(&mut current_data_index, data)?;
226 let value_end_quote_index = current_data_index;
227 current_data_index += 1;
228 let string_value = core::str::from_utf8(&data[value_start_quote_index+1..value_end_quote_index]).expect("skipped json object value string");
229 if current_field_index >= field_buffer.len() {
230 return Err(JsonParseFailure::TooManyFields);
231 }
232 field_buffer[current_field_index] = JsonField::new(string_key, JsonValue::String(string_value));
233 current_field_index += 1;
234 } else if data[current_data_index] == b't' || data[current_data_index] == b'f' {
235 let expect_true = data[current_data_index] == b't';
236 skip_json_boolean(&mut current_data_index, data, expect_true)?;
237 if current_field_index >= field_buffer.len() {
238 return Err(JsonParseFailure::TooManyFields);
239 }
240 field_buffer[current_field_index] = JsonField::new(string_key, JsonValue::Boolean(expect_true));
241 current_field_index += 1;
242 } else if (data[current_data_index] >= b'0' && data[current_data_index] < b'9') || data[current_data_index] == b'-' {
243 let numeric_start_index = current_data_index;
244 current_data_index += 1;
245 skip_json_numeric(&mut current_data_index, data)?;
246 let numeric_after_index = current_data_index;
247 let numeric_string = core::str::from_utf8(&data[numeric_start_index..numeric_after_index]).expect("skipped numeric digits");
248 let numeric_value: i64 = match numeric_string.parse() {
249 Ok(i) => i,
250 Err(_) => return Err(JsonParseFailure::InvalidNumericField),
251 };
252 if current_field_index >= field_buffer.len() {
253 return Err(JsonParseFailure::TooManyFields);
254 }
255 field_buffer[current_field_index] = JsonField::new(string_key, JsonValue::Number(numeric_value));
256 current_field_index += 1;
257 } else {
258 return Err(JsonParseFailure::InvalidStructure);
259 }
260 }
261 }
262 Err(JsonParseFailure::Incomplete)
263}
264
265fn tracked_write<T: Write>(mut output: T, counter: &mut usize, data: &str) -> Result<(), T::Error> {
266 output.write_all(data.as_bytes())?;
267 *counter += data.len();
268 Ok(())
269}
270
271fn write_escaped_json_string<T: Write>(mut output: T, counter: &mut usize, data: &str) -> Result<(), T::Error> {
272 tracked_write(&mut output, &mut *counter, "\"")?;
273 for field_character in data.chars() {
274 if field_character == '"' {
275 tracked_write(&mut output, &mut *counter, unsafe { core::str::from_utf8_unchecked(&[b'\\', field_character as u8]) })?;
276 } else {
277 tracked_write(&mut output, &mut *counter, unsafe { core::str::from_utf8_unchecked(&[field_character as u8]) })?;
278 }
279 }
280 tracked_write(&mut output, &mut *counter, "\"")?;
281 Ok(())
282}
283
284pub(crate) fn write_json_map<T: Write>(mut output: T, fields: &[JsonField]) -> Result<usize, T::Error> {
285 let mut ret = 0;
286 tracked_write(&mut output,&mut ret , "{")?;
287 let mut field_needs_comma = false;
288 for field in fields.iter() {
289 if field_needs_comma {
290 tracked_write(&mut output,&mut ret , ",")?;
291 } else {
292 field_needs_comma = true;
293 }
294 write_escaped_json_string(&mut output, &mut ret , field.key)?;
295 tracked_write(&mut output, &mut ret , ":")?;
296 match field.value {
297 JsonValue::String(s) => {
298 write_escaped_json_string(&mut output, &mut ret , s)?;
299 },
300 JsonValue::Boolean(false) => {
301 tracked_write(&mut output,&mut ret , "false")?;
302 },
303 JsonValue::Boolean(true) => {
304 tracked_write(&mut output,&mut ret , "true")?;
305 },
306 JsonValue::Number(n) => {
307 tracked_write(&mut output,&mut ret , &base10::i64(n))?;
308 },
309 }
310 }
311 tracked_write(&mut output, &mut ret , "}")?;
312 Ok(ret)
313}
314
315
316#[cfg(test)]
317mod tests {
318 use super::*;
319
320 #[test]
321 fn test_serialize_object_empty() {
322 let mut buffer = [0_u8; 1000];
323 let test_map = JsonObject::<0>::default();
324 let n = test_map.serialize_blocking(buffer.as_mut_slice()).unwrap();
325 assert_eq!(b"{}", buffer.split_at(n).0)
326 }
327
328 #[test]
329 fn test_serialize_object_simple() {
330 let mut buffer = [0_u8; 1000];
331 let mut test_map = JsonObject::<50>::default();
332 test_map.push_field("sub", JsonValue::String("1234567890")).unwrap();
333 test_map.push_field("name", JsonValue::String("John Doe")).unwrap();
334 test_map.push_field("iat", JsonValue::Number(1516239022)).unwrap();
335 test_map.push_field("something", JsonValue::Boolean(false)).unwrap();
336 let n = test_map.serialize_blocking(buffer.as_mut_slice()).unwrap();
337 assert_eq!(b"{\"sub\":\"1234567890\",\"name\":\"John Doe\",\"iat\":1516239022,\"something\":false}", buffer.split_at(n).0)
338 }
339
340 #[test]
341 fn test_parse_object_success_empty() {
342 let data = b"{}";
343 let (n,test_map) = JsonObject::<0>::parse_from(data).unwrap();
344 assert_eq!(data.len(),n);
345 assert!(test_map.as_slice().is_empty());
346 }
347
348 #[test]
349 fn test_parse_object_success_simple() {
350 let data = b"{\"sub\":\"1234567890\",\"name\":\"John Doe\",\"iat\":1516239022,\"something\":false}";
351 let (n,test_map) = JsonObject::<50>::parse_from(data).unwrap();
352 assert_eq!(data.len(),n);
353 let test_fields = test_map.as_slice();
354 assert_eq!(4, test_fields.len());
355 assert_eq!(JsonField { key: "sub", value: JsonValue::String("1234567890")}, test_fields[0]);
356 assert_eq!(JsonField { key: "name", value: JsonValue::String("John Doe")}, test_fields[1]);
357 assert_eq!(JsonField { key: "iat", value: JsonValue::Number(1516239022)}, test_fields[2]);
358 assert_eq!(JsonField { key: "something", value: JsonValue::Boolean(false)}, test_fields[3]);
359 }
360
361 #[test]
362 fn test_parse_object_failure_incomplete_simple() {
363 match JsonObject::<50>::parse_from(b"{") {
364 Err(JsonParseFailure::Incomplete) => {},
365 other => panic!("{:?}", other)
366 }
367 }
368
369 #[test]
370 fn test_parse_object_failure_incomplete_brace() {
371 match JsonObject::<50>::parse_from(b"{\"sub\":\"1234567890\",\"name\":\"John Doe\",\"iat\":1516239022,\"something\":false") {
372 Err(JsonParseFailure::Incomplete) => {},
373 other => panic!("{:?}", other)
374 }
375 }
376
377 #[test]
378 fn test_parse_object_failure_too_many_fields() {
379 match JsonObject::<0>::parse_from(b"{\"some\":\"thing\"}") {
380 Err(JsonParseFailure::TooManyFields) => {},
381 other => panic!("{:?}", other)
382 }
383 }
384
385}