use std::collections::HashMap; use std::iter::FromIterator; use crate::ParseError::UnexpectedEndOfInput; #[derive(Debug, PartialEq)] pub enum JSONValue { Object(HashMap), Array(Vec), String(String), Number(f64), True, False, Null, } #[derive(Debug)] pub enum ParseError { UnexpectedEndOfInput(String), ExpectedEndOfInput(String), ExpectedObjectKey(String), ExpectedToken(String), UnexpectedToken(String), ExpectedDigit(String), ExpectedEscapeChar(String), ExpectedUnicodeEscape(String), } #[derive(Debug)] pub struct JSON { chars: Vec, i: usize } pub type JSONResult = Result; type PartialResult = Result, ParseError>; impl JSON { fn new(json: &str) -> Self { JSON { chars: json.chars().collect(), i: 0 } } fn parse_value(&mut self) -> JSONResult { self.skip_whitespace(); let mut types = self.parse_string()?.into_iter() .chain(self.parse_number()?.into_iter()) .chain(self.parse_object()?.into_iter()) .chain(self.parse_array()?.into_iter()) .chain(self.parse_keyword("true", JSONValue::True)?.into_iter()) .chain(self.parse_keyword("false", JSONValue::False)?.into_iter()) .chain(self.parse_keyword("null", JSONValue::Null)?.into_iter()); match types.next() { Some(val) => Ok(val), None => Err(UnexpectedEndOfInput(String::new())) } } fn parse_object(&mut self) -> PartialResult { if self.chars[self.i] != '{' { return Ok(None); } self.i += 1; self.skip_whitespace(); let mut result: HashMap = HashMap::new(); let mut initial = true; // if it is not '}', // we take the path of string -> whitespace -> ':' -> value -> ... while self.chars[self.i] != '}' { if initial == false { self.eat_char(',')?; self.skip_whitespace(); } let key = match self.parse_string()? { Some(value) => match value { JSONValue::String(s) => s, _ => panic!("parse_string returned non-string value"), }, None => String::new() }; self.skip_whitespace(); self.eat_char(':')?; let value = self.parse_value()?; result.insert(key, value); initial = false; } // Move to the next character: '}' self.i += 1; Ok(Some(JSONValue::Object(result))) } fn parse_array(&mut self) -> PartialResult { if self.chars[self.i] != '[' { return Ok(None); } self.i += 1; self.skip_whitespace(); let mut result: Vec = vec![]; let mut initial = true; while self.chars[self.i] != ']' { if initial == false { self.eat_char(',')?; } let value = self.parse_value()?; result.push(value); initial = false; } // move to next character: ']' self.i += 1; Ok(Some(JSONValue::Array(result))) } fn parse_string(&mut self) -> PartialResult { todo!(); } fn parse_number(&mut self) -> PartialResult { todo!(); } fn parse_keyword(&mut self, search: &str, value: JSONValue) -> PartialResult { let slice = &String::from_iter(&self.chars[self.i..self.i+search.len()]); if slice == search { self.i += search.len(); return Ok(Some(value)); } Ok(None) } fn skip_whitespace(&mut self) { while self.chars[self.i].is_ascii_whitespace() { self.i += 1; } } fn eat_char(&mut self, ch: char) -> Result<(), ParseError> { if self.chars[self.i] != ch { let msg = format!(r#"Expected "{}"."#, ch); return Err(ParseError::ExpectedToken(msg)); } self.i += 1; Ok(()) } pub fn parse(json: &str) -> JSONResult { JSON::new(json).parse_value() } } #[cfg(test)] mod tests { use super::*; #[test] fn it_works() { assert_eq!(2 + 2, 4); } }