#![cfg(feature = "alloc")] use nom::{ branch::alt, bytes::complete::{escaped, tag, take_while}, character::complete::{alphanumeric1 as alphanumeric, char, one_of}, combinator::{cut, map}, error::{context, ParseError}, multi::separated_list0, number::complete::double, sequence::{preceded, separated_pair, terminated}, IResult, }; use std::collections::HashMap; use std::cell::Cell; use std::str; #[derive(Clone, Debug)] pub struct JsonValue<'a, 'b> { input: &'a str, pub offset: &'b Cell, } impl<'a, 'b: 'a> JsonValue<'a, 'b> { pub fn new(input: &'a str, offset: &'b Cell) -> JsonValue<'a, 'b> { JsonValue { input, offset } } pub fn offset(&self, input: &'a str) { let offset = input.as_ptr() as usize - self.input.as_ptr() as usize; self.offset.set(offset); } pub fn data(&self) -> &'a str { &self.input[self.offset.get()..] } pub fn string(&self) -> Option<&'a str> { println!("string()"); match string(self.data()) { Ok((i, s)) => { self.offset(i); println!("-> {}", s); Some(s) } _ => None, } } pub fn boolean(&self) -> Option { println!("boolean()"); match boolean(self.data()) { Ok((i, o)) => { self.offset(i); println!("-> {}", o); Some(o) } _ => None, } } pub fn number(&self) -> Option { println!("number()"); match double::<_, ()>(self.data()) { Ok((i, o)) => { self.offset(i); println!("-> {}", o); Some(o) } _ => None, } } pub fn array(&self) -> Option>> { println!("array()"); match tag::<_, _, ()>("[")(self.data()) { Err(_) => None, Ok((i, _)) => { println!("["); self.offset(i); let mut first = true; let mut done = false; let mut previous = std::usize::MAX; let v = self.clone(); Some(std::iter::from_fn(move || { if done { return None; } // if we ignored one of the items, skip over the value if v.offset.get() == previous { println!("skipping value"); match value(v.data()) { Ok((i, _)) => { v.offset(i); } Err(_) => {} } } match tag::<_, _, ()>("]")(v.data()) { Ok((i, _)) => { println!("]"); v.offset(i); done = true; return None; } Err(_) => {} }; if first { first = false; } else { match tag::<_, _, ()>(",")(v.data()) { Ok((i, _)) => { println!(","); v.offset(i); } Err(_) => { done = true; return None; } } } println!("-> {}", v.data()); previous = v.offset.get(); Some(v.clone()) })) } } } pub fn object(&self) -> Option)>> { println!("object()"); match tag::<_, _, ()>("{")(self.data()) { Err(_) => None, Ok((i, _)) => { self.offset(i); println!("{{"); let mut first = true; let mut done = false; let mut previous = std::usize::MAX; let v = self.clone(); Some(std::iter::from_fn(move || { if done { return None; } // if we ignored one of the items, skip over the value if v.offset.get() == previous { println!("skipping value"); match value(v.data()) { Ok((i, _)) => { v.offset(i); } Err(_) => {} } } match tag::<_, _, ()>("}")(v.data()) { Ok((i, _)) => { println!("}}"); v.offset(i); done = true; return None; } Err(_) => {} }; if first { first = false; } else { match tag::<_, _, ()>(",")(v.data()) { Ok((i, _)) => { println!(","); v.offset(i); } Err(_) => { done = true; return None; } } } match string(v.data()) { Ok((i, key)) => { v.offset(i); match tag::<_, _, ()>(":")(v.data()) { Err(_) => None, Ok((i, _)) => { v.offset(i); previous = v.offset.get(); println!("-> {} => {}", key, v.data()); Some((key, v.clone())) } } } _ => None, } })) } } } } fn sp<'a, E: ParseError<&'a str>>(i: &'a str) -> IResult<&'a str, &'a str, E> { let chars = " \t\r\n"; take_while(move |c| chars.contains(c))(i) } fn parse_str<'a, E: ParseError<&'a str>>(i: &'a str) -> IResult<&'a str, &'a str, E> { escaped(alphanumeric, '\\', one_of("\"n\\"))(i) } fn string<'a>(i: &'a str) -> IResult<&'a str, &'a str> { context( "string", preceded(char('\"'), cut(terminated(parse_str, char('\"')))), )(i) } fn boolean<'a>(input: &'a str) -> IResult<&'a str, bool> { alt((map(tag("false"), |_| false), map(tag("true"), |_| true)))(input) } fn array<'a>(i: &'a str) -> IResult<&'a str, ()> { context( "array", preceded( char('['), cut(terminated( map(separated_list0(preceded(sp, char(',')), value), |_| ()), preceded(sp, char(']')), )), ), )(i) } fn key_value<'a>(i: &'a str) -> IResult<&'a str, (&'a str, ())> { separated_pair(preceded(sp, string), cut(preceded(sp, char(':'))), value)(i) } fn hash<'a>(i: &'a str) -> IResult<&'a str, ()> { context( "map", preceded( char('{'), cut(terminated( map(separated_list0(preceded(sp, char(',')), key_value), |_| ()), preceded(sp, char('}')), )), ), )(i) } fn value<'a>(i: &'a str) -> IResult<&'a str, ()> { preceded( sp, alt(( hash, array, map(string, |_| ()), map(double, |_| ()), map(boolean, |_| ()), )), )(i) } /// object(input) -> iterator over (key, JsonValue) /// array(input) -> iterator over JsonValue /// /// JsonValue.string -> iterator over String (returns None after first successful call) /// /// object(input).filter(|(k, _)| k == "users").flatten(|(_, v)| v.object()).filter(|(k, _)| k == "city").flatten(|(_,v)| v.string()) fn main() { /*let data = "{ \"users\": { \"user1\" : { \"city\": \"Nantes\", \"country\": \"France\" }, \"user2\" : { \"city\": \"Bruxelles\", \"country\": \"Belgium\" }, \"user3\": { \"city\": \"Paris\", \"country\": \"France\", \"age\": 30 } }, \"countries\": [\"France\", \"Belgium\"] }"; */ let data = "{\"users\":{\"user1\":{\"city\":\"Nantes\",\"country\":\"France\"},\"user2\":{\"city\":\"Bruxelles\",\"country\":\"Belgium\"},\"user3\":{\"city\":\"Paris\",\"country\":\"France\",\"age\":30}},\"countries\":[\"France\",\"Belgium\"]}"; let offset = Cell::new(0); { let parser = JsonValue::new(data, &offset); if let Some(o) = parser.object() { let s: HashMap<&str, &str> = o .filter(|(k, _)| *k == "users") .filter_map(|(_, v)| v.object()) .flatten() .filter_map(|(user, v)| v.object().map(|o| (user, o))) .map(|(user, o)| { o.filter(|(k, _)| *k == "city") .filter_map(move |(_, v)| v.string().map(|s| (user, s))) }) .flatten() .collect(); println!("res = {:?}", s); } }; }