use std::error::Error;
use std::fmt;
use std::iter::Peekable;
use indexmap::IndexMap;
#[derive(Debug)]
pub enum JsonValue {
Object(IndexMap<String, JsonValue>),
Array(Vec<JsonValue>),
String(String),
Number(f64),
Bool(bool),
Null,
}
impl JsonValue {
pub fn from<S: AsRef<str>>(s: S) -> Result<JsonValue, ParseError> {
parse(s)
}
pub fn new_object() -> JsonValue {
JsonValue::Object(IndexMap::default())
}
pub fn new_array() -> JsonValue {
JsonValue::Array(Vec::default())
}
pub fn new_string() -> JsonValue {
JsonValue::String(String::default())
}
pub fn new_number() -> JsonValue {
JsonValue::Number(f64::default())
}
pub fn new_bool() -> JsonValue {
JsonValue::Bool(bool::default())
}
pub fn new_null() -> JsonValue {
JsonValue::Null
}
pub fn is_object(&self) -> bool {
matches!(self, JsonValue::Object(_))
}
pub fn is_array(&self) -> bool {
matches!(self, JsonValue::Array(_))
}
pub fn is_string(&self) -> bool {
matches!(self, JsonValue::String(_))
}
pub fn is_number(&self) -> bool {
matches!(self, JsonValue::Number(_))
}
pub fn is_bool(&self) -> bool {
matches!(self, JsonValue::Bool(_))
}
pub fn is_null(&self) -> bool {
matches!(self, JsonValue::Null)
}
pub fn as_object(&self) -> Option<&IndexMap<String, JsonValue>> {
match self { JsonValue::Object(o) => Some(o), _ => None }
}
pub fn as_array(&self) -> Option<&Vec<JsonValue>> {
match self { JsonValue::Array(a) => Some(a), _ => None }
}
pub fn as_string(&self) -> Option<&String> {
match self { JsonValue::String(s) => Some(s), _ => None }
}
pub fn as_number(&self) -> Option<&f64> {
match self { JsonValue::Number(n) => Some(n), _ => None }
}
pub fn as_bool(&self) -> Option<&bool> {
match self { JsonValue::Bool(b) => Some(b), _ => None }
}
pub fn as_null(&self) -> Option<&()> {
match self { JsonValue::Null => Some(&()), _ => None }
}
pub fn into_object(self) -> Option<IndexMap<String, JsonValue>> {
match self { JsonValue::Object(o) => Some(o), _ => None }
}
pub fn into_array(self) -> Option<Vec<JsonValue>> {
match self { JsonValue::Array(a) => Some(a), _ => None }
}
pub fn into_string(self) -> Option<String> {
match self { JsonValue::String(s) => Some(s), _ => None }
}
pub fn into_number(self) -> Option<f64> {
match self { JsonValue::Number(n) => Some(n), _ => None }
}
pub fn into_bool(self) -> Option<bool> {
match self { JsonValue::Bool(b) => Some(b), _ => None }
}
pub fn into_null(self) -> Option<()> {
match self { JsonValue::Null => Some(()), _ => None }
}
}
impl AsRef<JsonValue> for JsonValue {
fn as_ref(&self) -> &JsonValue {
self
}
}
impl PartialEq for JsonValue {
fn eq(&self, other: &Self) -> bool {
match (self, other) {
(JsonValue::Object(a), JsonValue::Object(b)) => a == b,
(JsonValue::Array(a), JsonValue::Array(b)) => a == b,
(JsonValue::String(a), JsonValue::String(b)) => a == b,
(JsonValue::Number(a), JsonValue::Number(b)) => a == b || a.is_nan() && b.is_nan(),
(JsonValue::Bool(a), JsonValue::Bool(b)) => a == b,
(JsonValue::Null, JsonValue::Null) => true,
_ => false,
}
}
}
impl Eq for JsonValue {}
impl fmt::Display for JsonValue {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}", stringify(self))
}
}
impl std::str::FromStr for JsonValue {
type Err = ParseError;
fn from_str(s: &str) -> Result<Self, Self::Err> {
parse(s)
}
}
pub fn stringify<O: AsRef<JsonValue>>(o: O) -> String {
let o = o.as_ref();
let result = match o {
JsonValue::Null => "null".to_string(),
JsonValue::Bool(b) => b.to_string(),
JsonValue::Number(n) => {
if *n == 0.0 {
"0".to_string()
} else if !n.is_finite() {
"null".to_string()
} else {
let abs = n.abs();
if abs < 1e-6 || abs >= 1e21 {
let s = format!("{:e}", n);
let (mantissa, exponent) = s.split_at(s.find('e').unwrap() + 1);
if exponent.starts_with('-') {
s
} else {
format!("{}+{}", mantissa, exponent)
}
} else {
n.to_string()
}
}
},
JsonValue::String(s) => {
let mut escaped = String::with_capacity(s.len() + 2);
escaped.push('"');
for c in s.chars() {
match c {
'"' => escaped.push_str("\\\""),
'\\' => escaped.push_str("\\\\"),
'\n' => escaped.push_str("\\n"),
'\t' => escaped.push_str("\\t"),
'\r' => escaped.push_str("\\r"),
'\x08' => escaped.push_str("\\b"),
'\x0C' => escaped.push_str("\\f"),
c if (c as u32) < 0x20 => {
use std::fmt::Write;
write!(escaped, "\\u{:04x}", c as u32).unwrap();
}
_ => escaped.push(c),
}
}
escaped.push('"');
escaped
},
JsonValue::Array(a) => {
let mut elements = Vec::new();
for item in a {
elements.push(stringify(item));
}
format!("[{}]", elements.join(","))
},
JsonValue::Object(d) => {
let mut members = Vec::new();
for (k, v) in d {
members.push(format!("\"{}\":{}", k, stringify(v)));
}
format!("{{{}}}", members.join(","))
},
};
result
}
#[derive(Debug, PartialEq, Eq)]
pub enum ParseError {
UnexpectedEndOfJsonInput,
UnexpectedToken { ch: char, pos: usize },
UnterminatedString { pos: usize },
BadControlCharacter { pos: usize },
BadEscapedCharacter { pos: usize },
BadUnicodeEscape { pos: usize },
IllegalUnicodeEscapeOrSurrogate { pos: usize },
NoNumberAfterMinusSign { pos: usize },
UnexpectedNumber { pos: usize },
UnterminatedFractionalNumber { pos: usize },
ExponentPartIsMissingANumber { pos: usize },
UnexpectedNonWhitespaceAfterJson { ch: char, pos: usize },
UnexpectedCharacterAfterArrayElement { ch: char, pos: usize },
UnexpectedEndOfArray,
ExpectedPropertyName { pos: usize },
ExpectedSemicolonAfterPropertyName { pos: usize },
UnexpectedCharacterAfterObjectMember { ch: char, pos: usize },
UnexpectedEndOfObject,
}
impl Error for ParseError {}
impl fmt::Display for ParseError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
ParseError::UnexpectedEndOfJsonInput => {
write!(f, "Unexpected end of JSON input")
}
ParseError::UnexpectedToken { ch, pos } => {
write!(f, "Unexpected token '{}' at position {}", ch, pos)
}
ParseError::UnterminatedString { pos } => {
write!(f, "Unterminated string in JSON at position {}", pos)
}
ParseError::BadControlCharacter { pos } => {
write!(f, "Bad control character in string literal in JSON at position {}", pos)
}
ParseError::BadEscapedCharacter { pos } => {
write!(f, "Bad escaped character in JSON at position {}", pos)
}
ParseError::BadUnicodeEscape { pos } => {
write!(f, "Bad Unicode escape in JSON at position {}", pos)
}
ParseError::IllegalUnicodeEscapeOrSurrogate { pos } => {
write!(f, "Illegal or Surrogate Unicode escape sequence at position {}", pos)
}
ParseError::NoNumberAfterMinusSign { pos } => {
write!(f, "No number after minus sign in JSON at position {}", pos)
}
ParseError::UnexpectedNumber { pos } => {
write!(f, "Unexpected number in JSON at position {}", pos)
}
ParseError::UnterminatedFractionalNumber { pos } => {
write!(f, "Unterminated fractional number in JSON at position {}", pos)
}
ParseError::ExponentPartIsMissingANumber { pos } => {
write!(f, "Exponent part is missing a number in JSON at position {}", pos)
}
ParseError::UnexpectedNonWhitespaceAfterJson { ch, pos } => {
write!(f, "Unexpected non-whitespace character '{}' after JSON at position {}", ch, pos)
}
ParseError::UnexpectedCharacterAfterArrayElement { ch, pos } => {
write!(f, "Unexpected character '{}' after array element in JSON at position {}: expected ',' or ']'", ch, pos)
}
ParseError::UnexpectedEndOfArray => {
write!(f, "Unexpected end of an array: expected ']'")
}
ParseError::ExpectedPropertyName { pos } => {
write!(f, "Expected property name or '}}' at position {}", pos)
}
ParseError::ExpectedSemicolonAfterPropertyName { pos } => {
write!(f, "Expected ':' after property name in JSON at position {}", pos)
}
ParseError::UnexpectedCharacterAfterObjectMember { ch, pos } => {
write!(f, "Unexpected character '{}' after object member in JSON at position {}: expected ',' or '}}'", ch, pos)
}
ParseError::UnexpectedEndOfObject => {
write!(f, "Unexpected end of an object: expected '}}'")
}
}
}
}
pub fn parse<S: AsRef<str>>(s: S) -> Result<JsonValue, ParseError> {
let mut s = s.as_ref().chars().enumerate().peekable();
let result = match_value(&mut s)?;
skip_whitespace(&mut s);
if let Some(&(p, c)) = s.peek() {
return Err(ParseError::UnexpectedNonWhitespaceAfterJson { ch: c, pos: p })
}
Ok(result)
}
fn skip_whitespace<I: Iterator<Item = (usize, char)>>(chars: &mut Peekable<I>) {
while matches!(chars.peek(), Some((_, ' ' | '\t' | '\n' | '\r'))) {
chars.next();
}
}
fn match_value<I: Iterator<Item = (usize, char)>>(chars: &mut Peekable<I>) -> Result<JsonValue, ParseError> {
skip_whitespace(chars);
if let Some(&(_, c)) = chars.peek() {
if c == '{' {
match_object(chars)
} else if c == '[' {
match_array(chars)
} else if c == '"' {
match_string(chars)
} else if c == '-' || c >= '0' && c <= '9' {
match_number(chars)
} else {
match_other(chars)
}
} else {
Err(ParseError::UnexpectedEndOfJsonInput)
}
}
fn match_object<I: Iterator<Item = (usize, char)>>(chars: &mut Peekable<I>) -> Result<JsonValue, ParseError> {
chars.next();
let mut object = IndexMap::new();
skip_whitespace(chars);
if let Some(&(_, c)) = chars.peek() {
if c == '}' {
chars.next();
return Ok(JsonValue::Object(object))
}
} else {
return Err(ParseError::UnexpectedEndOfObject)
}
loop {
skip_whitespace(chars);
match chars.peek() {
None => return Err(ParseError::UnexpectedEndOfObject),
Some(&(_, '"')) => {},
Some(&(p, _)) => return Err(ParseError::ExpectedPropertyName { pos: p }),
};
let key = match_string(chars)?.into_string().unwrap();
skip_whitespace(chars);
match chars.peek() {
None => return Err(ParseError::UnexpectedEndOfObject),
Some(&(_, ':')) => chars.next(),
Some(&(p, _)) => return Err(ParseError::ExpectedSemicolonAfterPropertyName { pos: p }),
};
let value = match_value(chars)?;
object.insert(key, value);
skip_whitespace(chars);
if let Some(&(p, c)) = chars.peek() {
if c == ',' {
chars.next();
continue;
}
if c == '}' {
chars.next();
break;
}
return Err(ParseError::UnexpectedCharacterAfterObjectMember { ch: c, pos: p })
} else {
return Err(ParseError::UnexpectedEndOfObject)
}
}
Ok(JsonValue::Object(object))
}
fn match_array<I: Iterator<Item = (usize, char)>>(chars: &mut Peekable<I>) -> Result<JsonValue, ParseError> {
chars.next();
let mut array = Vec::new();
skip_whitespace(chars);
if let Some(&(_, c)) = chars.peek() {
if c == ']' {
chars.next();
return Ok(JsonValue::Array(array))
}
} else {
return Err(ParseError::UnexpectedEndOfArray)
}
loop {
array.push(match_value(chars)?);
skip_whitespace(chars);
if let Some(&(p, c)) = chars.peek() {
if c == ',' {
chars.next();
continue;
}
if c == ']' {
chars.next();
break;
}
return Err(ParseError::UnexpectedCharacterAfterArrayElement { ch: c, pos: p })
} else {
return Err(ParseError::UnexpectedEndOfArray)
}
}
Ok(JsonValue::Array(array))
}
fn match_string<I: Iterator<Item = (usize, char)>>(chars: &mut Peekable<I>) -> Result<JsonValue, ParseError> {
let (p_start, c_start) = chars.next().unwrap();
assert!(c_start == '"');
let mut s = String::new();
while let Some((p, c)) = chars.next() {
if c == '"' {
return Ok(JsonValue::String(s))
} else if c == '\\' {
if let Some((p1, c1)) = chars.next() {
match c1 {
'"' | '\\' | '/' => s.push(c1),
'n' => s.push('\n'),
't' => s.push('\t'),
'r' => s.push('\r'),
'b' => s.push('\x08'),
'f' => s.push('\x14'),
'u' => {
let next4 = [chars.next(), chars.next(), chars.next(), chars.next()];
let mut unicode: u32 = 0;
for (i, item) in next4.iter().enumerate() {
let (pos, ch) = item.ok_or(ParseError::BadUnicodeEscape { pos: p1 + i + 1 })?;
unicode = (unicode << 4) + ch.to_digit(16).ok_or(ParseError::BadUnicodeEscape { pos })?;
}
s.push(char::from_u32(unicode).ok_or_else(|| ParseError::IllegalUnicodeEscapeOrSurrogate { pos: p })?);
},
_ => return Err(ParseError::BadEscapedCharacter { pos: p1 }),
}
} else {
return Err(ParseError::UnexpectedEndOfJsonInput)
}
} else if c >= '\0' && c <= '\x1F' {
return Err(ParseError::BadControlCharacter { pos: p })
} else {
s.push(c);
}
}
Err(ParseError::UnterminatedString { pos: p_start + s.len() + 1 })
}
fn match_number<I: Iterator<Item = (usize, char)>>(chars: &mut Peekable<I>) -> Result<JsonValue, ParseError> {
let (p_start, c_start) = chars.next().unwrap();
let mut s = String::from(c_start);
match chars.peek() {
Some(&(_, '0'..='9')) => {
if c_start == '0' {
return Err(ParseError::UnexpectedNumber { pos: p_start + 1 })
}
let (_, c_cur) = chars.next().unwrap();
if c_start == '-' && c_cur == '0' && matches!(chars.peek(), Some(&(_, '0'..='9'))) {
return Err(ParseError::UnexpectedNumber { pos: p_start + 2 })
}
s.push(c_cur);
while matches!(chars.peek(), Some(&(_, c)) if '0' <= c && c <= '9') {
s.push(chars.next().unwrap().1);
}
}
None | Some(_) => {
if c_start == '-' {
return Err(ParseError::NoNumberAfterMinusSign { pos: p_start + 1 })
}
}
}
if matches!(chars.peek(), Some(&(_, '.'))) {
let (p_frac, c_frac) = chars.next().unwrap();
s.push(c_frac);
if let Some(&(p, c)) = chars.peek() {
if !('0' <= c && c <= '9') {
return Err(ParseError::UnterminatedFractionalNumber { pos: p })
}
} else {
return Err(ParseError::UnterminatedFractionalNumber { pos: p_frac + 1 })
}
while matches!(chars.peek(), Some(&(_, c)) if '0' <= c && c <= '9') {
s.push(chars.next().unwrap().1);
}
}
if matches!(chars.peek(), Some(&(_, 'e' | 'E'))) {
let (p_exp, c_exp) = chars.next().unwrap();
s.push(c_exp);
let has_sign = matches!(chars.peek(), Some(&(_, '+' | '-')));
if has_sign {
s.push(chars.next().unwrap().1);
}
if let Some(&(p, c)) = chars.peek() {
if !('0' <= c && c <= '9') {
return Err(ParseError::ExponentPartIsMissingANumber { pos: p })
}
} else {
return Err(ParseError::ExponentPartIsMissingANumber { pos: p_exp + (has_sign as usize) + 1 })
}
while matches!(chars.peek(), Some(&(_, c)) if '0' <= c && c <= '9') {
s.push(chars.next().unwrap().1);
}
}
Ok(JsonValue::Number(s.parse::<f64>().unwrap()))
}
fn match_other<I: Iterator<Item = (usize, char)>>(chars: &mut Peekable<I>) -> Result<JsonValue, ParseError> {
let (p, c) = chars.next().unwrap();
if c == 't' {
expect_char(chars, 'r')?;
expect_char(chars, 'u')?;
expect_char(chars, 'e')?;
Ok(JsonValue::Bool(true))
} else if c == 'f' {
expect_char(chars, 'a')?;
expect_char(chars, 'l')?;
expect_char(chars, 's')?;
expect_char(chars, 'e')?;
Ok(JsonValue::Bool(false))
} else if c == 'n' {
expect_char(chars, 'u')?;
expect_char(chars, 'l')?;
expect_char(chars, 'l')?;
Ok(JsonValue::Null)
} else {
Err(ParseError::UnexpectedToken { ch: c, pos: p })
}
}
fn expect_char<I: Iterator<Item = (usize, char)>>(chars: &mut Peekable<I>, ch: char) -> Result<(), ParseError> {
if let Some(&(p, c)) = chars.peek() {
if c == ch {
chars.next();
Ok(())
} else {
Err(ParseError::UnexpectedToken { ch: c, pos: p })
}
} else {
Err(ParseError::UnexpectedEndOfJsonInput)
}
}
#[cfg(test)]
mod tests {
use indexmap::indexmap;
use super::*;
#[test]
fn test_stringify() {
fn case<O: AsRef<JsonValue>, S: AsRef<str>>(o: O, s: S) {
let o = o.as_ref();
let s = s.as_ref();
let s1 = stringify(o);
let s2 = o.to_string();
assert_eq!(s, s1);
assert_eq!(s, s2);
}
case(JsonValue::Null, "null");
case(JsonValue::Bool(true), "true");
case(JsonValue::Bool(false), "false");
case(JsonValue::Number(0.0), "0");
case(JsonValue::Number(-0.0), "0");
case(JsonValue::Number(0.1), "0.1");
case(JsonValue::Number(0.01), "0.01");
case(JsonValue::Number(0.001), "0.001");
case(JsonValue::Number(0.0001), "0.0001");
case(JsonValue::Number(0.00001), "0.00001");
case(JsonValue::Number(0.000001), "0.000001");
case(JsonValue::Number(0.0000001), "1e-7");
case(JsonValue::Number(1e-20), "1e-20");
case(JsonValue::Number(1e-40), "1e-40");
case(JsonValue::Number(1e-100), "1e-100");
case(JsonValue::Number(1e-200), "1e-200");
case(JsonValue::Number(1e-300), "1e-300");
case(JsonValue::Number(1e-323), "1e-323");
case(JsonValue::Number(1e-324), "0");
case(JsonValue::Number(10.0), "10");
case(JsonValue::Number(100.0), "100");
case(JsonValue::Number(1000.0), "1000");
case(JsonValue::Number(10000.0), "10000");
case(JsonValue::Number(100000.0), "100000");
case(JsonValue::Number(1000000.0), "1000000");
case(JsonValue::Number(1e10), "10000000000");
case(JsonValue::Number(1e20), "100000000000000000000");
case(JsonValue::Number(1e21), "1e+21");
case(JsonValue::Number(1e50), "1e+50");
case(JsonValue::Number(1e100), "1e+100");
case(JsonValue::Number(1e200), "1e+200");
case(JsonValue::Number(1e300), "1e+300");
case(JsonValue::Number(1e308), "1e+308");
case(JsonValue::Number(1.0), "1");
case(JsonValue::Number(1.5), "1.5");
case(JsonValue::Number(-42.42), "-42.42");
case(JsonValue::Number(0.123456789), "0.123456789");
case(JsonValue::Number(0.123456789123456789), "0.12345678912345678");
case(JsonValue::Number(0.123456789123456789123456789), "0.12345678912345678");
case(JsonValue::Number(1234567890.0), "1234567890");
case(JsonValue::Number(12345678901234567890.0), "12345678901234567000");
case(JsonValue::Number(123456789012345678901234567890.0), "1.2345678901234568e+29");
case(JsonValue::Number(1234567890123456789012345678901234567890.0), "1.2345678901234568e+39");
case(JsonValue::Number(1.5e21), "1.5e+21");
case(JsonValue::Number(1.5e-21), "1.5e-21");
case(JsonValue::Number(f64::NAN), "null");
case(JsonValue::Number(f64::INFINITY), "null");
case(JsonValue::Number(f64::NEG_INFINITY), "null");
case(JsonValue::String("".to_string()), "\"\"");
case(JsonValue::String(" ".to_string()), "\" \"");
case(
JsonValue::String("\u{0000}\u{0001}\u{0010}\u{0019}\u{0020}\u{0021}".to_string()),
"\"\\u0000\\u0001\\u0010\\u0019 !\""
);
case(
JsonValue::String("\u{0100}\u{0200}\u{0300}\u{0400}\u{0500}".to_string()),
"\"ĀȀ̀ЀԀ\""
);
case(
JsonValue::String("\u{1111}\u{2222}\u{3333}\u{4444}\u{5555}\u{6666}\u{7777}\u{8888}\u{9999}\u{aaaa}\u{bbbb}\u{cccc}".to_string()),
"\"ᄑ∢㌳䑄啕晦睷袈香ꪪ뮻쳌\""
);
case(JsonValue::String("привет".to_string()), "\"привет\"");
case(JsonValue::String("qwerty".to_string()), "\"qwerty\"");
case(JsonValue::String("line\n break".to_string()), "\"line\\n break\"");
case(JsonValue::String("quote\"test".to_string()), "\"quote\\\"test\"");
case(JsonValue::String("backslash\\".to_string()), "\"backslash\\\\\"");
case(JsonValue::String("tab\t char".to_string()), "\"tab\\t char\"");
case(JsonValue::String("newline\nand\t tab".to_string()), "\"newline\\nand\\t tab\"");
case(JsonValue::String("unicode\u{1F600}".to_string()), "\"unicode😀\"");
case(JsonValue::Array(vec![]), "[]");
case(
JsonValue::Array(vec![
JsonValue::Null,
JsonValue::Bool(true),
JsonValue::Number(3.14),
JsonValue::String("str".to_string())
]),
"[null,true,3.14,\"str\"]"
);
case(
JsonValue::Array(vec![
JsonValue::Array(vec![]),
JsonValue::Array(vec![
JsonValue::Number(1.0),
JsonValue::Number(2.0),
JsonValue::Array(vec![
JsonValue::String("deep".to_string())
])
])
]),
"[[],[1,2,[\"deep\"]]]"
);
case(JsonValue::Object(indexmap!{}), "{}");
case(
JsonValue::Object(indexmap!{
"null".to_string() => JsonValue::Null,
"bool".to_string() => JsonValue::Bool(false),
"num".to_string() => JsonValue::Number(42.0),
"str".to_string() => JsonValue::String("hello".to_string()),
}),
"{\"null\":null,\"bool\":false,\"num\":42,\"str\":\"hello\"}"
);
case(
JsonValue::Object(indexmap!{
"nested".to_string() => JsonValue::Object(indexmap!{
"arr".to_string() => JsonValue::Array(vec![
JsonValue::Number(1.0),
JsonValue::Number(2.0),
JsonValue::Object(indexmap!{
"deep".to_string() => JsonValue::Bool(true),
}),
]),
}),
}),
"{\"nested\":{\"arr\":[1,2,{\"deep\":true}]}}"
);
case(
JsonValue::Array(vec![
JsonValue::Object(indexmap!{}),
JsonValue::Array(vec![]),
JsonValue::String("".to_string()),
JsonValue::Null,
JsonValue::Number(10.0),
JsonValue::Bool(true),
]),
"[{},[],\"\",null,10,true]"
);
}
#[test]
fn test_parse() {
fn case(s: &str, o: Result<JsonValue, ParseError>) {
let o1 = parse(s);
let o2 = s.parse::<JsonValue>();
let o3 = JsonValue::from(s);
assert_eq!(o1, o);
assert_eq!(o2, o);
assert_eq!(o3, o);
}
case("", Err(ParseError::UnexpectedEndOfJsonInput));
case(" \t\r\n", Err(ParseError::UnexpectedEndOfJsonInput));
case("null null", Err(ParseError::UnexpectedNonWhitespaceAfterJson { ch: 'n', pos: 5 }));
case("|", Err(ParseError::UnexpectedToken { ch: '|', pos: 0 }));
case("null", Ok(JsonValue::Null));
case(" \t\r\nnull", Ok(JsonValue::Null));
case("null \t\r\n", Ok(JsonValue::Null));
case(" \t\r\nnull \t\r\n", Ok(JsonValue::Null));
case("true", Ok(JsonValue::Bool(true)));
case(" \t\r\ntrue", Ok(JsonValue::Bool(true)));
case("true \t\r\n", Ok(JsonValue::Bool(true)));
case(" \t\r\ntrue \t\r\n", Ok(JsonValue::Bool(true)));
case("false", Ok(JsonValue::Bool(false)));
case(" \t\r\nfalse", Ok(JsonValue::Bool(false)));
case("false \t\r\n", Ok(JsonValue::Bool(false)));
case(" \t\r\nfalse \t\r\n", Ok(JsonValue::Bool(false)));
case("\"", Err(ParseError::UnterminatedString { pos: 1 }));
case("\"abc", Err(ParseError::UnterminatedString { pos: 4 }));
case("\'", Err(ParseError::UnexpectedToken { ch: '\'', pos: 0 }));
case("\'\'", Err(ParseError::UnexpectedToken { ch: '\'', pos: 0 }));
case("\"\n\"", Err(ParseError::BadControlCharacter { pos: 1 }));
case("\"\\q\"", Err(ParseError::BadEscapedCharacter { pos: 2 }));
case("\"\\ux123\"", Err(ParseError::BadUnicodeEscape { pos: 3 }));
case("\"\\u1x23\"", Err(ParseError::BadUnicodeEscape { pos: 4 }));
case("\"\\u12x3\"", Err(ParseError::BadUnicodeEscape { pos: 5 }));
case("\"\\u123x\"", Err(ParseError::BadUnicodeEscape { pos: 6 }));
case("\"\\ud800\"", Err(ParseError::IllegalUnicodeEscapeOrSurrogate { pos: 1 }));
case("\"\\udbff\"", Err(ParseError::IllegalUnicodeEscapeOrSurrogate { pos: 1 }));
case("\"\"", Ok(JsonValue::String("".to_string())));
case("\" \"", Ok(JsonValue::String(" ".to_string())));
case("\"123\"", Ok(JsonValue::String("123".to_string())));
case("\"\\\"\\\\\\/\"", Ok(JsonValue::String("\"\\/".to_string())));
case("\"\\t\\n\\r\\b\\f\"", Ok(JsonValue::String("\t\n\r\x08\x14".to_string())));
case("\"\\u0041\"", Ok(JsonValue::String("A".to_string())));
case("\"\\u03A9\\u00A9\"", Ok(JsonValue::String("Ω©".to_string())));
case("\"Привет\"", Ok(JsonValue::String("Привет".to_string())));
case("+", Err(ParseError::UnexpectedToken { ch: '+', pos: 0 }));
case("+a", Err(ParseError::UnexpectedToken { ch: '+', pos: 0 }));
case("+0", Err(ParseError::UnexpectedToken { ch: '+', pos: 0 }));
case("+1", Err(ParseError::UnexpectedToken { ch: '+', pos: 0 }));
case("-", Err(ParseError::NoNumberAfterMinusSign { pos: 1 }));
case("-a", Err(ParseError::NoNumberAfterMinusSign { pos: 1 }));
case(".5", Err(ParseError::UnexpectedToken { ch: '.', pos: 0 }));
case("-.5", Err(ParseError::NoNumberAfterMinusSign { pos: 1 }));
case("00", Err(ParseError::UnexpectedNumber { pos: 1 }));
case("-00", Err(ParseError::UnexpectedNumber { pos: 2 }));
case("01", Err(ParseError::UnexpectedNumber { pos: 1 }));
case("-01", Err(ParseError::UnexpectedNumber { pos: 2 }));
case("001", Err(ParseError::UnexpectedNumber { pos: 1 }));
case("-001", Err(ParseError::UnexpectedNumber { pos: 2 }));
case("0.", Err(ParseError::UnterminatedFractionalNumber { pos: 2 }));
case("-0.", Err(ParseError::UnterminatedFractionalNumber { pos: 3 }));
case("1.", Err(ParseError::UnterminatedFractionalNumber { pos: 2 }));
case("-1.", Err(ParseError::UnterminatedFractionalNumber { pos: 3 }));
case("1.e10", Err(ParseError::UnterminatedFractionalNumber { pos: 2 }));
case("1e", Err(ParseError::ExponentPartIsMissingANumber { pos: 2 }));
case("1e+", Err(ParseError::ExponentPartIsMissingANumber { pos: 3 }));
case("1e-", Err(ParseError::ExponentPartIsMissingANumber { pos: 3 }));
case("0", Ok(JsonValue::Number(0.0)));
case("-0", Ok(JsonValue::Number(-0.0)));
case("0.0", Ok(JsonValue::Number(0.0)));
case("-0.0", Ok(JsonValue::Number(-0.0)));
case("1", Ok(JsonValue::Number(1.0)));
case("-1", Ok(JsonValue::Number(-1.0)));
case("1.0", Ok(JsonValue::Number(1.0)));
case("-1.0", Ok(JsonValue::Number(-1.0)));
case("1.000000", Ok(JsonValue::Number(1.0)));
case("-1.000000", Ok(JsonValue::Number(-1.0)));
case("123", Ok(JsonValue::Number(123.0)));
case("-123", Ok(JsonValue::Number(-123.0)));
case("123.000", Ok(JsonValue::Number(123.0)));
case("-123.000", Ok(JsonValue::Number(-123.0)));
case("0.5", Ok(JsonValue::Number(0.5)));
case("-0.5", Ok(JsonValue::Number(-0.5)));
case("123.456", Ok(JsonValue::Number(123.456)));
case("0e1", Ok(JsonValue::Number(0.0)));
case("-0E2", Ok(JsonValue::Number(-0.0)));
case("1e10", Ok(JsonValue::Number(1e10)));
case("1E10", Ok(JsonValue::Number(1e10)));
case("1e+10", Ok(JsonValue::Number(1e10)));
case("1e-10", Ok(JsonValue::Number(1e-10)));
case("0.1e+1", Ok(JsonValue::Number(0.1e1)));
case("-0.25E-2", Ok(JsonValue::Number(-0.25e-2)));
case("-123.456e-7", Ok(JsonValue::Number(-123.456e-7)));
case("1e308", Ok(JsonValue::Number(1e308)));
case("1e-308", Ok(JsonValue::Number(1e-308)));
case("1234567890123456789012345678901234567890", Ok(JsonValue::Number(1234567890123456789012345678901234567890.0)));
case("-1234567890123456789012345678901234567890", Ok(JsonValue::Number(-1234567890123456789012345678901234567890.0)));
case("[", Err(ParseError::UnexpectedEndOfArray));
case("]", Err(ParseError::UnexpectedToken { ch: ']', pos: 0 }));
case("[,", Err(ParseError::UnexpectedToken { ch: ',', pos: 1 }));
case("[,]", Err(ParseError::UnexpectedToken { ch: ',', pos: 1 }));
case("[0", Err(ParseError::UnexpectedEndOfArray));
case("0]", Err(ParseError::UnexpectedNonWhitespaceAfterJson { ch: ']', pos: 1 }));
case("[0,", Err(ParseError::UnexpectedEndOfJsonInput));
case("[0,]", Err(ParseError::UnexpectedToken { ch: ']', pos: 3 }));
case("[0,,]", Err(ParseError::UnexpectedToken { ch: ',', pos: 3 }));
case("[0 0]", Err(ParseError::UnexpectedCharacterAfterArrayElement { ch: '0', pos: 3 }));
case("[]", Ok(JsonValue::Array(vec![])));
case("[null]", Ok(JsonValue::Array(vec![JsonValue::Null])));
case("[true]", Ok(JsonValue::Array(vec![JsonValue::Bool(true)])));
case("[false]", Ok(JsonValue::Array(vec![JsonValue::Bool(false)])));
case("[0]", Ok(JsonValue::Array(vec![JsonValue::Number(0.0)])));
case("[\"Hello\"]", Ok(JsonValue::Array(vec![JsonValue::String("Hello".to_string())])));
case(
"[null, true, false, 0, \"Hello\"]",
Ok(JsonValue::Array(vec![
JsonValue::Null,
JsonValue::Bool(true),
JsonValue::Bool(false),
JsonValue::Number(0.0),
JsonValue::String("Hello".to_string()),
])),
);
case(
"[[1, 2, 3], [[], null, true, false, 0, \"Hello\"], []]",
Ok(JsonValue::Array(vec![
JsonValue::Array(vec![
JsonValue::Number(1.0),
JsonValue::Number(2.0),
JsonValue::Number(3.0),
]),
JsonValue::Array(vec![
JsonValue::Array(vec![]),
JsonValue::Null,
JsonValue::Bool(true),
JsonValue::Bool(false),
JsonValue::Number(0.0),
JsonValue::String("Hello".to_string()),
]),
JsonValue::Array(vec![]),
])),
);
case(
"[[], [[], [[], [[], []]]]]",
Ok(JsonValue::Array(vec![
JsonValue::Array(vec![]),
JsonValue::Array(vec![
JsonValue::Array(vec![]),
JsonValue::Array(vec![
JsonValue::Array(vec![]),
JsonValue::Array(vec![
JsonValue::Array(vec![]),
JsonValue::Array(vec![]),
]),
]),
]),
])),
);
case(
"[[[[[\"deep\"]]]]]",
Ok(JsonValue::Array(vec![
JsonValue::Array(vec![
JsonValue::Array(vec![
JsonValue::Array(vec![
JsonValue::Array(vec![
JsonValue::String("deep".to_string()),
]),
]),
]),
]),
])),
);
case("{", Err(ParseError::UnexpectedEndOfObject));
case("}", Err(ParseError::UnexpectedToken { ch: '}', pos: 0 }));
case("{,", Err(ParseError::ExpectedPropertyName { pos: 1 }));
case("{,}", Err(ParseError::ExpectedPropertyName { pos: 1 }));
case("{0", Err(ParseError::ExpectedPropertyName { pos: 1 }));
case("0}", Err(ParseError::UnexpectedNonWhitespaceAfterJson { ch: '}', pos: 1 }));
case("{0,", Err(ParseError::ExpectedPropertyName { pos: 1 }));
case("{0,}", Err(ParseError::ExpectedPropertyName { pos: 1 }));
case("{0,,}", Err(ParseError::ExpectedPropertyName { pos: 1 }));
case("{0 0}", Err(ParseError::ExpectedPropertyName { pos: 1 }));
case("{0:0}", Err(ParseError::ExpectedPropertyName { pos: 1 }));
case("{0: 0}", Err(ParseError::ExpectedPropertyName { pos: 1 }));
case("{\"0\":", Err(ParseError::UnexpectedEndOfJsonInput));
case("{\"0\"::", Err(ParseError::UnexpectedToken { ch: ':', pos: 5 }));
case("{\"0\":}", Err(ParseError::UnexpectedToken { ch: '}', pos: 5 }));
case("{\"1\": 2,}", Err(ParseError::ExpectedPropertyName { pos: 8 }));
case("{}", Ok(JsonValue::Object(IndexMap::new())));
case("{\"1\": 2}", Ok(JsonValue::Object(indexmap!{"1".to_string() => JsonValue::Number(2.0)})));
case("{\"3\" :4}", Ok(JsonValue::Object(indexmap!{"3".to_string() => JsonValue::Number(4.0)})));
case("{\"5\" : 6}", Ok(JsonValue::Object(indexmap!{"5".to_string() => JsonValue::Number(6.0)})));
case("{\"true\" : false, \"false\" : false, \"undefined\" : null}", Ok(JsonValue::Object(indexmap!{
"true".to_string() => JsonValue::Bool(false),
"false".to_string() => JsonValue::Bool(false),
"undefined".to_string() => JsonValue::Null,
})));
case("{\"a\": null, \"b\": true, \"c\": false, \"d\": 1, \"e\": \"Hello\"}", Ok(JsonValue::Object(indexmap!{
"a".to_string() => JsonValue::Null,
"b".to_string() => JsonValue::Bool(true),
"c".to_string() => JsonValue::Bool(false),
"d".to_string() => JsonValue::Number(1.0),
"e".to_string() => JsonValue::String("Hello".to_string()),
})));
case("{\"nested\": {\"inner\": [1, 2, {\"deep\": false}]}}", Ok(JsonValue::Object(indexmap!{
"nested".to_string() => JsonValue::Object(indexmap!{
"inner".to_string() => JsonValue::Array(vec![
JsonValue::Number(1.0),
JsonValue::Number(2.0),
JsonValue::Object(indexmap!{
"deep".to_string() => JsonValue::Bool(false),
}),
]),
}),
})));
case("{\"arr\": [], \"obj\": {}}", Ok(JsonValue::Object(indexmap!{
"arr".to_string() => JsonValue::Array(vec![]),
"obj".to_string() => JsonValue::Object(indexmap!{}),
})));
case("{\"a\": [1, 2, {\"b\": [true, false, null]}, 3], \"c\": {\"d\": \"text\", \"e\": [[], [{}]]}}", Ok(JsonValue::Object(indexmap!{
"a".to_string() => JsonValue::Array(vec![
JsonValue::Number(1.0),
JsonValue::Number(2.0),
JsonValue::Object(indexmap!{
"b".to_string() => JsonValue::Array(vec![
JsonValue::Bool(true),
JsonValue::Bool(false),
JsonValue::Null,
]),
}),
JsonValue::Number(3.0),
]),
"c".to_string() => JsonValue::Object(indexmap!{
"d".to_string() => JsonValue::String("text".to_string()),
"e".to_string() => JsonValue::Array(vec![
JsonValue::Array(vec![]),
JsonValue::Array(vec![
JsonValue::Object(indexmap!{}),
]),
]),
}),
})));
case("{\"num\": 123, \"bools\": [true, false], \"str\": \"value\", \"mix\": [{}, [], null]}", Ok(JsonValue::Object(indexmap!{
"num".to_string() => JsonValue::Number(123.0),
"bools".to_string() => JsonValue::Array(vec![
JsonValue::Bool(true),
JsonValue::Bool(false),
]),
"str".to_string() => JsonValue::String("value".to_string()),
"mix".to_string() => JsonValue::Array(vec![
JsonValue::Object(indexmap!{}),
JsonValue::Array(vec![]),
JsonValue::Null,
]),
})));
case(
"[{},[],\"\",null,10,true]",
Ok(JsonValue::Array(vec![
JsonValue::Object(indexmap!{}),
JsonValue::Array(vec![]),
JsonValue::String("".to_string()),
JsonValue::Null,
JsonValue::Number(10.0),
JsonValue::Bool(true),
]))
);
}
}