use std::{collections::HashMap, io::Read}; use futures::FutureExt; use stap::{just, many0, many1, tag, Anchor, Cursor, Input, InputRef, Parsing}; async fn skip_whitespace(iref: &mut InputRef<'_, u8>) { many0(iref, |&c| c.is_ascii_whitespace()).await; } async fn null(iref: &mut InputRef<'_, u8>) -> Result<(), ()> { tag(iref, b"null").await.map(|_| ()) } async fn bool(iref: &mut InputRef<'_, u8>) -> Result { if tag(iref, b"true").await.is_ok() { Ok(true) } else if tag(iref, b"false").await.is_ok() { Ok(false) } else { Err(()) } } async fn number(iref: &mut InputRef<'_, u8>) -> Result { let mut anchor = Anchor::new(iref); let _ = just(&mut anchor, b'-').await; many1(&mut anchor, |&c| c.is_ascii_digit()).await?; if just(&mut anchor, b'.').await.is_ok() { many0(&mut anchor, |&c| c.is_ascii_digit()).await; } if just(&mut anchor, b'e').await.is_ok() || just(&mut anchor, b'E').await.is_ok() { let _ = just(&mut anchor, b'-').await; let _ = many1(&mut anchor, |&c| c.is_ascii_digit()).await; } let range = anchor.range(); anchor.forget(); iref.scope_cursor(move |c| { let s = std::str::from_utf8(&c.buf()[range]).unwrap(); let n: f64 = s.parse().unwrap(); Ok(n) }) } // TODO: unescape string async fn string(iref: &mut InputRef<'_, u8>) -> Result { just(iref, b'"').await?; let mut last = b'"'; let range = many0(iref, |&c| { let ret = last == b'\\' || c != b'"'; last = c; ret }) .await; just(iref, b'"').await?; iref.scope_cursor(move |c| { let s = std::str::from_utf8(&c.buf()[range]).unwrap(); let s = s.to_string(); Ok(s) }) } async fn array(iref: &mut InputRef<'_, u8>) -> Result, ()> { just(iref, b'[').await?; let mut array = Vec::new(); let mut first = true; loop { skip_whitespace(iref).await; if just(iref, b']').await.is_ok() { break; } if !first { just(iref, b',').await?; skip_whitespace(iref).await; } first = false; let value = Box::pin(json(iref)).await?; array.push(value); } Ok(array) } async fn object(iref: &mut InputRef<'_, u8>) -> Result, ()> { just(iref, b'{').await?; let mut map = HashMap::new(); let mut first = true; loop { skip_whitespace(iref).await; if just(iref, b'}').await.is_ok() { break; } if !first { just(iref, b',').await?; skip_whitespace(iref).await; } first = false; let key = string(iref).await?; skip_whitespace(iref).await; just(iref, b':').await?; skip_whitespace(iref).await; let value = Box::pin(json(iref)).await?; map.insert(key, value); } Ok(map) } async fn json(iref: &mut InputRef<'_, u8>) -> Result { if let Ok(()) = null(iref).await { return Ok(Json::Null); } if let Ok(b) = bool(iref).await { return Ok(Json::Bool(b)); } if let Ok(n) = number(iref).await { return Ok(Json::Number(n)); } if let Ok(s) = string(iref).await { return Ok(Json::String(s)); } if let Ok(a) = array(iref).await { return Ok(Json::Array(a)); } if let Ok(o) = object(iref).await { return Ok(Json::Object(o)); } Err(()) } #[derive(Debug, PartialEq)] #[allow(dead_code)] enum Json { Null, Bool(bool), String(String), Number(f64), Array(Vec), Object(HashMap), } fn main() { println!("Please input a JSON string\nIt will exit when parsing has succeeded or failed:"); let mut input = Input::new(Cursor { buf: Vec::new(), index: 0, }); let mut parsing = Parsing::new(&mut input, |mut iref| { async move { json(&mut iref).await }.boxed_local() }); let mut buf = [0; 4096]; let mut stdin = std::io::stdin().lock(); while !parsing.poll() { let n = stdin.read(&mut buf).unwrap(); if n == 0 { break; } parsing.cursor_mut().buf.extend_from_slice(&buf[..n]); } dbg!(parsing.into_result()); } #[test] fn test_json() { let example = r#"{"a": "b", "c": {"d": "e"}, "f": 114514, "g": [1, "2"], "h": true, "i": null}"#; let mut input = Input::new(Cursor { buf: example.as_bytes().to_vec(), index: 0, }); let mut parsing = Parsing::new(&mut input, |mut iref| { async move { json(&mut iref).await }.boxed_local() }); assert!(parsing.poll()); let expected = Json::Object( vec![ ("a".to_string(), Json::String("b".to_string())), ( "c".to_string(), Json::Object( vec![("d".to_string(), Json::String("e".to_string()))] .into_iter() .collect(), ), ), ("f".to_string(), Json::Number(114514f64)), ( "g".to_string(), Json::Array(vec![Json::Number(1f64), Json::String("2".to_string())]), ), ("h".to_string(), Json::Bool(true)), ("i".to_string(), Json::Null), ] .into_iter() .collect(), ); assert_eq!(parsing.into_result().unwrap(), Ok(expected)); }