1#![cfg(feature = "alloc")]
2
3use nom::{
4  branch::alt,
5  bytes::complete::{escaped, tag, take_while},
6  character::complete::{alphanumeric1 as alphanumeric, char, one_of},
7  combinator::{cut, map},
8  error::{context, ParseError},
9  multi::separated_list0,
10  number::complete::double,
11  sequence::{preceded, separated_pair, terminated},
12  IResult,
13};
14use std::collections::HashMap;
15
16use std::cell::Cell;
17use std::str;
18
19#[derive(Clone, Debug)]
20pub struct JsonValue<'a, 'b> {
21  input: &'a str,
22  pub offset: &'b Cell<usize>,
23}
24
25impl<'a, 'b: 'a> JsonValue<'a, 'b> {
26  pub fn new(input: &'a str, offset: &'b Cell<usize>) -> JsonValue<'a, 'b> {
27    JsonValue { input, offset }
28  }
29
30  pub fn offset(&self, input: &'a str) {
31    let offset = input.as_ptr() as usize - self.input.as_ptr() as usize;
32    self.offset.set(offset);
33  }
34
35  pub fn data(&self) -> &'a str {
36    &self.input[self.offset.get()..]
37  }
38
39  pub fn string(&self) -> Option<&'a str> {
40    println!("string()");
41    match string(self.data()) {
42      Ok((i, s)) => {
43        self.offset(i);
44        println!("-> {}", s);
45        Some(s)
46      }
47      _ => None,
48    }
49  }
50
51  pub fn boolean(&self) -> Option<bool> {
52    println!("boolean()");
53    match boolean(self.data()) {
54      Ok((i, o)) => {
55        self.offset(i);
56        println!("-> {}", o);
57        Some(o)
58      }
59      _ => None,
60    }
61  }
62
63  pub fn number(&self) -> Option<f64> {
64    println!("number()");
65    match double::<_, ()>(self.data()) {
66      Ok((i, o)) => {
67        self.offset(i);
68        println!("-> {}", o);
69        Some(o)
70      }
71      _ => None,
72    }
73  }
74
75  pub fn array(&self) -> Option<impl Iterator<Item = JsonValue<'a, 'b>>> {
76    println!("array()");
77
78    match tag::<_, _, ()>("[")(self.data()) {
79      Err(_) => None,
80      Ok((i, _)) => {
81        println!("[");
82        self.offset(i);
83        let mut first = true;
84        let mut done = false;
85        let mut previous = std::usize::MAX;
86
87        let v = self.clone();
88
89        Some(std::iter::from_fn(move || {
90          if done {
91            return None;
92          }
93
94          // if we ignored one of the items, skip over the value
95          if v.offset.get() == previous {
96            println!("skipping value");
97            match value(v.data()) {
98              Ok((i, _)) => {
99                v.offset(i);
100              }
101              Err(_) => {}
102            }
103          }
104
105          match tag::<_, _, ()>("]")(v.data()) {
106            Ok((i, _)) => {
107              println!("]");
108              v.offset(i);
109              done = true;
110              return None;
111            }
112            Err(_) => {}
113          };
114
115          if first {
116            first = false;
117          } else {
118            match tag::<_, _, ()>(",")(v.data()) {
119              Ok((i, _)) => {
120                println!(",");
121                v.offset(i);
122              }
123              Err(_) => {
124                done = true;
125                return None;
126              }
127            }
128          }
129
130          println!("-> {}", v.data());
131          previous = v.offset.get();
132          Some(v.clone())
133        }))
134      }
135    }
136  }
137
138  pub fn object(&self) -> Option<impl Iterator<Item = (&'a str, JsonValue<'a, 'b>)>> {
139    println!("object()");
140    match tag::<_, _, ()>("{")(self.data()) {
141      Err(_) => None,
142      Ok((i, _)) => {
143        self.offset(i);
144
145        println!("{{");
146
147        let mut first = true;
148        let mut done = false;
149        let mut previous = std::usize::MAX;
150
151        let v = self.clone();
152
153        Some(std::iter::from_fn(move || {
154          if done {
155            return None;
156          }
157
158          // if we ignored one of the items, skip over the value
159          if v.offset.get() == previous {
160            println!("skipping value");
161            match value(v.data()) {
162              Ok((i, _)) => {
163                v.offset(i);
164              }
165              Err(_) => {}
166            }
167          }
168
169          match tag::<_, _, ()>("}")(v.data()) {
170            Ok((i, _)) => {
171              println!("}}");
172              v.offset(i);
173              done = true;
174              return None;
175            }
176            Err(_) => {}
177          };
178
179          if first {
180            first = false;
181          } else {
182            match tag::<_, _, ()>(",")(v.data()) {
183              Ok((i, _)) => {
184                println!(",");
185                v.offset(i);
186              }
187              Err(_) => {
188                done = true;
189                return None;
190              }
191            }
192          }
193
194          match string(v.data()) {
195            Ok((i, key)) => {
196              v.offset(i);
197
198              match tag::<_, _, ()>(":")(v.data()) {
199                Err(_) => None,
200                Ok((i, _)) => {
201                  v.offset(i);
202
203                  previous = v.offset.get();
204
205                  println!("-> {} => {}", key, v.data());
206                  Some((key, v.clone()))
207                }
208              }
209            }
210            _ => None,
211          }
212        }))
213      }
214    }
215  }
216}
217
218fn sp<'a, E: ParseError<&'a str>>(i: &'a str) -> IResult<&'a str, &'a str, E> {
219  let chars = " \t\r\n";
220
221  take_while(move |c| chars.contains(c))(i)
222}
223
224fn parse_str<'a, E: ParseError<&'a str>>(i: &'a str) -> IResult<&'a str, &'a str, E> {
225  escaped(alphanumeric, '\\', one_of("\"n\\"))(i)
226}
227
228fn string<'a>(i: &'a str) -> IResult<&'a str, &'a str> {
229  context(
230    "string",
231    preceded(char('\"'), cut(terminated(parse_str, char('\"')))),
232  )(i)
233}
234
235fn boolean<'a>(input: &'a str) -> IResult<&'a str, bool> {
236  alt((map(tag("false"), |_| false), map(tag("true"), |_| true)))(input)
237}
238
239fn array<'a>(i: &'a str) -> IResult<&'a str, ()> {
240  context(
241    "array",
242    preceded(
243      char('['),
244      cut(terminated(
245        map(separated_list0(preceded(sp, char(',')), value), |_| ()),
246        preceded(sp, char(']')),
247      )),
248    ),
249  )(i)
250}
251
252fn key_value<'a>(i: &'a str) -> IResult<&'a str, (&'a str, ())> {
253  separated_pair(preceded(sp, string), cut(preceded(sp, char(':'))), value)(i)
254}
255
256fn hash<'a>(i: &'a str) -> IResult<&'a str, ()> {
257  context(
258    "map",
259    preceded(
260      char('{'),
261      cut(terminated(
262        map(separated_list0(preceded(sp, char(',')), key_value), |_| ()),
263        preceded(sp, char('}')),
264      )),
265    ),
266  )(i)
267}
268
269fn value<'a>(i: &'a str) -> IResult<&'a str, ()> {
270  preceded(
271    sp,
272    alt((
273      hash,
274      array,
275      map(string, |_| ()),
276      map(double, |_| ()),
277      map(boolean, |_| ()),
278    )),
279  )(i)
280}
281
282/// object(input) -> iterator over (key, JsonValue)
283/// array(input) -> iterator over JsonValue
284///
285/// JsonValue.string -> iterator over String (returns None after first successful call)
286///
287/// object(input).filter(|(k, _)| k == "users").flatten(|(_, v)| v.object()).filter(|(k, _)| k == "city").flatten(|(_,v)| v.string())
288fn main() {
289  /*let data = "{
290  \"users\": {
291    \"user1\" : { \"city\": \"Nantes\", \"country\": \"France\" },
292    \"user2\" : { \"city\": \"Bruxelles\", \"country\": \"Belgium\" },
293    \"user3\": { \"city\": \"Paris\", \"country\": \"France\", \"age\": 30 }
294  },
295  \"countries\": [\"France\", \"Belgium\"]
296  }";
297  */
298  let data = "{\"users\":{\"user1\":{\"city\":\"Nantes\",\"country\":\"France\"},\"user2\":{\"city\":\"Bruxelles\",\"country\":\"Belgium\"},\"user3\":{\"city\":\"Paris\",\"country\":\"France\",\"age\":30}},\"countries\":[\"France\",\"Belgium\"]}";
299
300  let offset = Cell::new(0);
301  {
302    let parser = JsonValue::new(data, &offset);
303
304    if let Some(o) = parser.object() {
305      let s: HashMap<&str, &str> = o
306        .filter(|(k, _)| *k == "users")
307        .filter_map(|(_, v)| v.object())
308        .flatten()
309        .filter_map(|(user, v)| v.object().map(|o| (user, o)))
310        .map(|(user, o)| {
311          o.filter(|(k, _)| *k == "city")
312            .filter_map(move |(_, v)| v.string().map(|s| (user, s)))
313        })
314        .flatten()
315        .collect();
316
317      println!("res = {:?}", s);
318    }
319  };
320}
321