• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 #![cfg(feature = "alloc")]
2 
3 use nom::{
4   branch::alt,
5   bytes::complete::{tag, take},
6   character::complete::{anychar, char, multispace0, none_of},
7   combinator::{map, map_opt, map_res, value, verify},
8   error::ParseError,
9   multi::{fold_many0, separated_list0},
10   number::complete::double,
11   sequence::{delimited, preceded, separated_pair},
12   IResult, Parser,
13 };
14 
15 use std::collections::HashMap;
16 
17 #[derive(Debug, PartialEq, Clone)]
18 pub enum JsonValue {
19   Null,
20   Bool(bool),
21   Str(String),
22   Num(f64),
23   Array(Vec<JsonValue>),
24   Object(HashMap<String, JsonValue>),
25 }
26 
boolean(input: &str) -> IResult<&str, bool>27 fn boolean(input: &str) -> IResult<&str, bool> {
28   alt((value(false, tag("false")), value(true, tag("true"))))(input)
29 }
30 
u16_hex(input: &str) -> IResult<&str, u16>31 fn u16_hex(input: &str) -> IResult<&str, u16> {
32   map_res(take(4usize), |s| u16::from_str_radix(s, 16))(input)
33 }
34 
unicode_escape(input: &str) -> IResult<&str, char>35 fn unicode_escape(input: &str) -> IResult<&str, char> {
36   map_opt(
37     alt((
38       // Not a surrogate
39       map(verify(u16_hex, |cp| !(0xD800..0xE000).contains(cp)), |cp| {
40         cp as u32
41       }),
42       // See https://en.wikipedia.org/wiki/UTF-16#Code_points_from_U+010000_to_U+10FFFF for details
43       map(
44         verify(
45           separated_pair(u16_hex, tag("\\u"), u16_hex),
46           |(high, low)| (0xD800..0xDC00).contains(high) && (0xDC00..0xE000).contains(low),
47         ),
48         |(high, low)| {
49           let high_ten = (high as u32) - 0xD800;
50           let low_ten = (low as u32) - 0xDC00;
51           (high_ten << 10) + low_ten + 0x10000
52         },
53       ),
54     )),
55     // Could be probably replaced with .unwrap() or _unchecked due to the verify checks
56     std::char::from_u32,
57   )(input)
58 }
59 
character(input: &str) -> IResult<&str, char>60 fn character(input: &str) -> IResult<&str, char> {
61   let (input, c) = none_of("\"")(input)?;
62   if c == '\\' {
63     alt((
64       map_res(anychar, |c| {
65         Ok(match c {
66           '"' | '\\' | '/' => c,
67           'b' => '\x08',
68           'f' => '\x0C',
69           'n' => '\n',
70           'r' => '\r',
71           't' => '\t',
72           _ => return Err(()),
73         })
74       }),
75       preceded(char('u'), unicode_escape),
76     ))(input)
77   } else {
78     Ok((input, c))
79   }
80 }
81 
string(input: &str) -> IResult<&str, String>82 fn string(input: &str) -> IResult<&str, String> {
83   delimited(
84     char('"'),
85     fold_many0(character, String::new, |mut string, c| {
86       string.push(c);
87       string
88     }),
89     char('"'),
90   )(input)
91 }
92 
ws<'a, O, E: ParseError<&'a str>, F: Parser<&'a str, O, E>>(f: F) -> impl Parser<&'a str, O, E>93 fn ws<'a, O, E: ParseError<&'a str>, F: Parser<&'a str, O, E>>(f: F) -> impl Parser<&'a str, O, E> {
94   delimited(multispace0, f, multispace0)
95 }
96 
array(input: &str) -> IResult<&str, Vec<JsonValue>>97 fn array(input: &str) -> IResult<&str, Vec<JsonValue>> {
98   delimited(
99     char('['),
100     ws(separated_list0(ws(char(',')), json_value)),
101     char(']'),
102   )(input)
103 }
104 
object(input: &str) -> IResult<&str, HashMap<String, JsonValue>>105 fn object(input: &str) -> IResult<&str, HashMap<String, JsonValue>> {
106   map(
107     delimited(
108       char('{'),
109       ws(separated_list0(
110         ws(char(',')),
111         separated_pair(string, ws(char(':')), json_value),
112       )),
113       char('}'),
114     ),
115     |key_values| key_values.into_iter().collect(),
116   )(input)
117 }
118 
json_value(input: &str) -> IResult<&str, JsonValue>119 fn json_value(input: &str) -> IResult<&str, JsonValue> {
120   use JsonValue::*;
121 
122   alt((
123     value(Null, tag("null")),
124     map(boolean, Bool),
125     map(string, Str),
126     map(double, Num),
127     map(array, Array),
128     map(object, Object),
129   ))(input)
130 }
131 
json(input: &str) -> IResult<&str, JsonValue>132 fn json(input: &str) -> IResult<&str, JsonValue> {
133   ws(json_value).parse(input)
134 }
135 
136 #[test]
json_string()137 fn json_string() {
138   assert_eq!(string("\"\""), Ok(("", "".to_string())));
139   assert_eq!(string("\"abc\""), Ok(("", "abc".to_string())));
140   assert_eq!(
141     string("\"abc\\\"\\\\\\/\\b\\f\\n\\r\\t\\u0001\\u2014\u{2014}def\""),
142     Ok(("", "abc\"\\/\x08\x0C\n\r\t\x01——def".to_string())),
143   );
144   assert_eq!(string("\"\\uD83D\\uDE10\""), Ok(("", "��".to_string())));
145 
146   assert!(string("\"").is_err());
147   assert!(string("\"abc").is_err());
148   assert!(string("\"\\\"").is_err());
149   assert!(string("\"\\u123\"").is_err());
150   assert!(string("\"\\uD800\"").is_err());
151   assert!(string("\"\\uD800\\uD800\"").is_err());
152   assert!(string("\"\\uDC00\"").is_err());
153 }
154 
155 #[test]
json_object()156 fn json_object() {
157   use JsonValue::*;
158 
159   let input = r#"{"a":42,"b":"x"}"#;
160 
161   let expected = Object(
162     vec![
163       ("a".to_string(), Num(42.0)),
164       ("b".to_string(), Str("x".to_string())),
165     ]
166     .into_iter()
167     .collect(),
168   );
169 
170   assert_eq!(json(input), Ok(("", expected)));
171 }
172 
173 #[test]
json_array()174 fn json_array() {
175   use JsonValue::*;
176 
177   let input = r#"[42,"x"]"#;
178 
179   let expected = Array(vec![Num(42.0), Str("x".to_string())]);
180 
181   assert_eq!(json(input), Ok(("", expected)));
182 }
183 
184 #[test]
json_whitespace()185 fn json_whitespace() {
186   use JsonValue::*;
187 
188   let input = r#"
189   {
190     "null" : null,
191     "true"  :true ,
192     "false":  false  ,
193     "number" : 123e4 ,
194     "string" : " abc 123 " ,
195     "array" : [ false , 1 , "two" ] ,
196     "object" : { "a" : 1.0 , "b" : "c" } ,
197     "empty_array" : [  ] ,
198     "empty_object" : {   }
199   }
200   "#;
201 
202   assert_eq!(
203     json(input),
204     Ok((
205       "",
206       Object(
207         vec![
208           ("null".to_string(), Null),
209           ("true".to_string(), Bool(true)),
210           ("false".to_string(), Bool(false)),
211           ("number".to_string(), Num(123e4)),
212           ("string".to_string(), Str(" abc 123 ".to_string())),
213           (
214             "array".to_string(),
215             Array(vec![Bool(false), Num(1.0), Str("two".to_string())])
216           ),
217           (
218             "object".to_string(),
219             Object(
220               vec![
221                 ("a".to_string(), Num(1.0)),
222                 ("b".to_string(), Str("c".to_string())),
223               ]
224               .into_iter()
225               .collect()
226             )
227           ),
228           ("empty_array".to_string(), Array(vec![]),),
229           ("empty_object".to_string(), Object(HashMap::new()),),
230         ]
231         .into_iter()
232         .collect()
233       )
234     ))
235   );
236 }
237