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