rs-05-json-value
0.000
Proposed solution
```rust
// src/lib.rs
use std::collections::HashMap;
use std::fmt;
use std::str::FromStr;
#[derive(Debug, Clone, PartialEq)]
pub enum Value {
Null,
Bool(bool),
Number(f64),
Str(String),
Array(Vec<Value>),
Object(HashMap<String, Value>),
}
#[derive(Debug, Clone, PartialEq)]
pub struct ParseError {
message: String,
position: usize,
}
impl ParseError {
fn new(message: &str, position: usize) -> Self {
ParseError {
message: message.to_string(),
position,
}
}
}
impl fmt::Display for ParseError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "ParseError at position {}: {}", self.position, self.message)
}
}
fn parse(input: &str) -> Result<Value, ParseError> {
let mut chars = input.chars().enumerate();
parse_value(&mut chars)
}
fn parse_value(chars: &mut std::iter::Enumerate<char>) -> Result<Value, ParseError> {
skip_whitespace(chars);
match chars.next().unwrap() {
'{' => parse_object(chars),
'[' => parse_array(chars),
't' => parse_bool(true, chars),
'f' => parse_bool(false, chars),
'n' => parse_null(chars),
'"' => parse_str(chars),
c if c.is_digit(10) || c == '.' || c == 'e' || c == '-' || c == '+' || c == '*' || c == '/' => parse_number(chars),
_ => Err(ParseError::new(&format!("Unexpected character: {}", c)),
}
}
fn parse_object(chars: &mut std::iter::Enumerate<char>) -> Result<Value, ParseError> {
let mut object = HashMap::new();
skip_whitespace(chars);
if chars.next().unwrap() != '{' {
return Err(ParseError::new("Expected '{'"));
}
while let Some((_, ch)) = chars.next() {
if ch == '}' {
break;
}
skip_whitespace(chars);
if ch != '"' {
return Err(ParseError::new("Expected '\"'"));
}
let key = parse_str(chars)?;
skip_whitespace(chars);
if chars.next().unwrap() != ':' {
return Err(ParseError::new("Expected ':'"));
}
skip_whitespace(chars);
if chars.next().unwrap() == '}' {
return Err(ParseError::new("Unexpected '}'"));
}
let value = parse_value(chars)?;
object.insert(key, value);
skip_whitespace(chars);
if chars.next().unwrap() == '}' {
break;
}
if chars.next().unwrap() != ',' {
return Err(ParseError::new("Expected ','"));
}
}
Ok(Value::Object(object))
}
fn parse_array(chars: &mut std::iter::Enumerate<char>) -> Result<Value, ParseError> {
let mut array = Vec::new();
skip_whitespace(chars);
if chars.next().unwrap() != '[' {
return Err(ParseError::new("Expected '['"));
}
while let Some((_, ch)) = chars.next() {
if ch == ']' {
break;
}
skip_whitespace(chars);
if ch == ']' {
return Err(ParseError::new("Unexpected ']'");
}
let value = parse_value(chars)?;
array.push(value);
skip_whitespace(chars);
if chars.next().unwrap() == ']' {
break;
}
if chars.next().unwrap() != ',' {
return Err(ParseError::new("Expected ','"));
}
}
Ok(Value::Array(array))
}
fn parse_bool(value: bool, chars: &mut std::iter::Enumerate<char>) -> Result<Value, ParseError> {
if let Some((_, ch)) = chars.next() {
if ch == 't' {
if chars.next().unwrap() == 'r' {
if chars.next().unwrap() == 'u' {
if chars.next().unwrap() == 'e' {
if chars.next().unwrap() == ' ' {
return Ok(Value::Bool(true));
}
}
}
}
} else if ch == 'f' {
if chars.next().unwrap() == 'a' {
if chars.next().unwrap() == 'l' {
if chars.next().unwrap() == 's' {
if chars.next().unwrap() == 'e' {
return Ok(Value::Bool(false));
}
}
}
}
}
}
Err(ParseError::new("Invalid boolean literal"))
}
fn parse_null(chars: &mut std::iter::Enumerate<char>) -> Result<Value, ParseError> {
if let Some((_, ch)) = chars.next() {
if ch == 'n' {
if chars.next().unwrap() == 'u' {
if chars.next().unwrap() == 'l' {
if chars.next().unwrap() == 'l' {
return Ok(Value::Null);
}
}
}
}
}
Err(ParseError::new("Invalid null literal"))
}
fn parse_str(chars: &mut std::iter::Enumerate<char>) -> Result<Value, ParseError> {
let mut str = String::new();
while let Some((_, ch)) = chars.next() {
if ch == '"' {
break;
}
match ch {
'"' => return Err(ParseError::new("Unterminated string")),
'\\' => {
chars.next();
match chars.next() {
'"' => str.push('"'),
'\\' => str.push('\\'),
'n' => str.push('\n'),
't' => str.push('\t'),
'r' => str.push('\r'),
'b' => str.push('\b'),
'f' => str.push('\f'),
c if c.is_ascii_hexdigit() => {
let mut hex_digits = String::new();
for _ in 0..2 {
hex_digits.push(chars.next().unwrap());
}
str.push_str(&str::from_utf8_lossy(&hex_digits).to_string());
}
_ => return Err(ParseError::new("Invalid escape sequence")),
}
}
_ => str.push(ch),
}
}
Ok(Value::Str(str))
}
fn parse_number(chars: &mut std::iter::Enumerate<char>) -> Result<Value, ParseError> {
let mut number = String::new();
while let Some((_, ch)) = chars.next() {
if ch.is_digit(10) || ch == '.' || ch == 'e' || ch == '+' || ch == '-' || ch == '*' || ch == '/' {
number.push(ch);
} else {
break;
}
}
if let Ok(num) = f64::from_str(&number) {
Ok(Value::Number(num))
} else {
Err(ParseError::new("Invalid number"))
}
}
fn skip_whitespace(chars: &mut std::iter::Enumerate<char>) {
while let Some((_, ch)) = chars.next() {
if !ch.is_whitespace() {
break;
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_parse_null() {
let input = "null";
assert_eq!(parse(input).unwrap(), Value::Null);
}
#[test]
fn test_parse_bool_true() {
let input = "true";
assert_eq!(parse(input).unwrap(), Value::Bool(true));
}
#[test]
fn test_parse_bool_false() {
let input = "false";
assert_eq!(parse(input).unwrap(), Value::Bool(false));
}
#[test]
fn test_parse_number() {
let input = "123.456";
assert_eq!(parse(input).unwrap(), Value::Number(123.456));
}
#[test]
fn test_parse_string() {
let input = "\"Hello, world!\"";
assert_eq!(parse(input).unwrap(), Value::Str("Hello, world!".to_string()));
}
#[test]
fn test_parse_array() {
let input = "[1, true, null, [2, 3]]";
assert_eq!(
parse(input).unwrap(),
Value::Array(vec![
Value::Number(1.0),
Value::Bool(true),
Value::Null,
Value::Array(vec![Value::Number(2.0), Value::Number(3.0)]
])
);
}
#[test]
fn test_parse_object() {
let input = "{\"key1\": \"value1\", \"key2\": [1, true, null]}";
assert_eq!(
parse(input).unwrap(),
Value::Object(HashMap::from([
("key1".to_string(), Value::Str("value1".to_string())),
("key2".to_string(), Value::Array(vec![
Value::Number(1.0),
Value::Bool(true),
Value::Null
]))
]))
);
}
#[test]
fn test_parse_malformed_input() {
let input = "invalid input";
assert!(parse(input).is_err());
}
#[test]
fn test_parse_unterminated_string() {
let input = "\"Hello, world";
assert!(parse(input).is_err());
}
#[test]
fn test_parse_invalid_number() {
let input = "123abc";
assert!(parse(input).is_err());
}
#[test]
fn test_parse_invalid_array() {
let input = "[1, 2, 3";
assert!(parse(input).is_err());
}
#[test]
fn test_parse_invalid_object() {
let input = "{key1: value1";
assert!(parse(input).is_err());
}
}
```Errors (stderr)
error: unknown character escape: `b`
--> src/lib.rs:210:39
|
210 | 'b' => str.push('\b'),
| ^ unknown character escape
|
= help: for more information, visit <https://doc.rust-lang.org/reference/tokens.html#literals>
help: if you meant to write a literal backslash (perhaps escaping in a regular expression), consider a raw string literal
|
210 - 'b' => str.push('\b'),
210 + 'b' => str.push(r"\b"),
|
error: unknown character escape: `f`
--> src/lib.rs:211:39
|
211 | 'f' => str.push('\f'),
| ^ unknown character escape
|
= help: for more information, visit <https://doc.rust-lang.org/reference/tokens.html#literals>
help: if you meant to write a literal backslash (perhaps escaping in a regular expression), consider a raw string literal
|
211 - 'f' => str.push('\f'),
211 + 'f' => str.push(r"\f"),
|
error: mismatched closing delimiter: `}`
--> src/lib.rs:54:17
|
46 | match chars.next().unwrap() {
| - closing delimiter possibly meant for this
...
54 | _ => Err(ParseError::new(&format!("Unexpected character: {}", c)),
| ^ unclosed delimiter
55 | }
| ^ mismatched closing delimiter
error: mismatched closing delimiter: `}`
--> src/lib.rs:127:23
|
126 | if ch == ']' {
| - closing delimiter possibly meant for this
127 | return Err(ParseError::new("Unexpected ']'");
| ^ unclosed delimiter
128 | }
| ^ mismatched closing delimiter
error: mismatched closing delimiter: `]`
--> src/lib.rs:298:29
|
294 | Value::Array(vec![
| - closing delimiter possibly meant for this
...
298 | Value::Array(vec![Value::Number(2.0), Value::Number(3.0)]
| ^ unclosed delimiter
299 | ])
| ^ mismatched closing delimiter
error: could not compile `challenge` (lib) due to 5 previous errors
error: could not compile `challenge` (lib test) due to 5 previous errors
Self-repair attempts
[
{
"total": 1,
"answer": "```rust\n// src/lib.rs\n\nuse std::collections::HashMap;\nuse std::fmt;\nuse std::str::FromStr;\n\n#[derive(Debug, Clone, PartialEq)]\npub enum Value {\n Null,\n Bool(bool),\n Number(f64),\n Str(String),\n Array(Vec<Value>),\n Object(HashMap<String, Value>),\n}\n\n#[derive(Debug, Clone, PartialEq)]\npub struct ParseError {\n message: String,\n position: usize,\n}\n\nimpl ParseError {\n fn new(message: &str, position: usize) -> Self {\n ParseError {\n message: message.to_string(),\n position,\n }\n }\n}\n\nimpl fmt::Display for ParseError {\n fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {\n write!(f, \"ParseError at position {}: {}\", self.position, self.message)\n }\n}\n\nfn parse(input: &str) -> Result<Value, ParseError> {\n let mut chars = input.chars().enumerate();\n parse_value(&mut chars)\n}\n\nfn parse_value(chars: &mut std::iter::Enumerate<char>) -> Result<Value, ParseError> {\n skip_whitespace(chars);\n\n match chars.next().unwrap() {\n '{' => parse_object(chars),\n '[' => parse_array(chars),\n 't' => parse_bool(true, chars),\n 'f' => parse_bool(false, chars),\n 'n' => parse_null(chars),\n '\"' => parse_str(chars),\n c if c.is_digit(10) || c == '.' || c == 'e' || c == '-' || c == '+' || c == '*' || c == '/' => parse_number(chars),\n _ => Err(ParseError::new(&format!(\"Unexpected character: {}\", c)),\n }\n}\n\nfn parse_object(chars: &mut std::iter::Enumerate<char>) -> Result<Value, ParseError> {\n let mut object = HashMap::new();\n\n skip_whitespace(chars);\n\n if chars.next().unwrap() != '{' {\n return Err(ParseError::new(\"Expected '{'\"));\n }\n\n while let Some((_, ch)) = chars.next() {\n if ch == '}' {\n break;\n }\n\n skip_whitespace(chars);\n\n if ch != '\"' {\n return Err(ParseError::new(\"Expected '\\\"'\"));\n }\n\n let key = parse_str(chars)?;\n\n skip_whitespace(chars);\n\n if chars.next().unwrap() != ':' {\n return Err(ParseError::new(\"Expected ':'\"));\n }\n\n skip_whitespace(chars);\n\n if chars.next().unwrap() == '}' {\n return Err(ParseError::new(\"Unexpected '}'\"));\n }\n\n let value = parse_value(chars)?;\n\n object.insert(key, value);\n\n skip_whitespace(chars);\n\n if chars.next().unwrap() == '}' {\n break;\n }\n\n if chars.next().unwrap() != ',' {\n return Err(ParseError::new(\"Expected ','\"));\n }\n }\n\n Ok(Value::Object(object))\n}\n\nfn parse_array(chars: &mut std::iter::Enumerate<char>) -> Result<Value, ParseError> {\n let mut array = Vec::new();\n\n skip_whitespace(chars);\n\n if chars.next().unwrap() != '[' {\n return Err(ParseError::new(\"Expected '['\"));\n }\n\n while let Some((_, ch)) = chars.next() {\n if ch == ']' {\n break;\n }\n\n skip_whitespace(chars);\n\n if ch == ']' {\n return Err(ParseError::new(\"Unexpected ']'\");\n }\n\n let value = parse_value(chars)?;\n\n array.push(value);\n\n skip_whitespace(chars);\n\n if chars.next().unwrap() == ']' {\n break;\n }\n\n if chars.next().unwrap() != ',' {\n return Err(ParseError::new(\"Expected ','\"));\n }\n }\n\n Ok(Value::Array(array))\n}\n\nfn parse_bool(value: bool, chars: &mut std::iter::Enumerate<char>) -> Result<Value, ParseError> {\n if let Some((_, ch)) = chars.next() {\n if ch == 't' {\n if chars.next().unwrap() == 'r' {\n if chars.next().unwrap() == 'u' {\n if chars.next().unwrap() == 'e' {\n if chars.next().unwrap() == ' ' {\n return Ok(Value::Bool(true));\n }\n }\n }\n }\n } else if ch == 'f' {\n if chars.next().unwrap() == 'a' {\n if chars.next().unwrap() == 'l' {\n if chars.next().unwrap() == 's' {\n if chars.next().unwrap() == 'e' {\n return Ok(Value::Bool(false));\n }\n }\n }\n }\n }\n }\n\n Err(ParseError::new(\"Invalid boolean literal\"))\n}\n\nfn parse_null(chars: &mut std::iter::Enumerate<char>) -> Result<Value, ParseError> {\n if let Some((_, ch)) = chars.next() {\n if ch == 'n' {\n if chars.next().unwrap() == 'u' {\n if chars.next().unwrap() == 'l' {\n if chars.next().unwrap() == 'l' {\n return Ok(Value::Null);\n }\n }\n }\n }\n }\n\n Err(ParseError::new(\"Invalid null literal\"))\n}\n\nfn parse_str(chars: &mut std::iter::Enumerate<char>) -> Result<Value, ParseError> {\n let mut str = String::new();\n\n while let Some((_, ch)) = chars.next() {\n if ch == '\"' {\n break;\n }\n\n match ch {\n '\"' => return Err(ParseError::new(\"Unterminated string\")),\n '\\\\' => {\n chars.next();\n match chars.next() {\n '\"' => str.push('\"'),\n '\\\\' => str.push('\\\\'),\n 'n' => str.push('\\n'),\n 't' => str.push('\\t'),\n 'r' => str.push('\\r'),\n 'b' => str.push('\\b'),\n 'f' => str.push('\\f'),\n c if c.is_ascii_hexdigit() => {\n let mut hex_digits = String::new();\n for _ in 0..2 {\n hex_digits.push(chars.next().unwrap());\n }\n str.push_str(&str::from_utf8_lossy(&hex_digits).to_string());\n }\n _ => return Err(ParseError::new(\"Invalid escape sequence\")),\n }\n }\n _ => str.push(ch),\n }\n }\n\n Ok(Value::Str(str))\n}\n\nfn parse_number(chars: &mut std::iter::Enumerate<char>) -> Result<Value, ParseError> {\n let mut number = String::new();\n\n while let Some((_, ch)) = chars.next() {\n if ch.is_digit(10) || ch == '.' || ch == 'e' || ch == '+' || ch == '-' || ch == '*' || ch == '/' {\n number.push(ch);\n } else {\n break;\n }\n }\n\n if let Ok(num) = f64::from_str(&number) {\n Ok(Value::Number(num))\n } else {\n Err(ParseError::new(\"Invalid number\"))\n }\n}\n\nfn skip_whitespace(chars: &mut std::iter::Enumerate<char>) {\n while let Some((_, ch)) = chars.next() {\n if !ch.is_whitespace() {\n break;\n }\n }\n}\n\n#[cfg(test)]\nmod tests {\n use super::*;\n\n #[test]\n fn test_parse_null() {\n let input = \"null\";\n assert_eq!(parse(input).unwrap(), Value::Null);\n }\n\n #[test]\n fn test_parse_bool_true() {\n let input = \"true\";\n assert_eq!(parse(input).unwrap(), Value::Bool(true));\n }\n\n #[test]\n fn test_parse_bool_false() {\n let input = \"false\";\n assert_eq!(parse(input).unwrap(), Value::Bool(false));\n }\n\n #[test]\n fn test_parse_number() {\n let input = \"123.456\";\n assert_eq!(parse(input).unwrap(), Value::Number(123.456));\n }\n\n #[test]\n fn test_parse_string() {\n let input = \"\\\"Hello, world!\\\"\";\n assert_eq!(parse(input).unwrap(), Value::Str(\"Hello, world!\".to_string()));\n }\n\n #[test]\n fn test_parse_array() {\n let input = \"[1, true, null, [2, 3]]\";\n assert_eq!(\n parse(input).unwrap(),\n Value::Array(vec![\n Value::Number(1.0),\n Value::Bool(true),\n Value::Null,\n Value::Array(vec![Value::Number(2.0), Value::Number(3.0)]\n ])\n );\n }\n\n #[test]\n fn test_parse_object() {\n let input = \"{\\\"key1\\\": \\\"value1\\\", \\\"key2\\\": [1, true, null]}\";\n assert_eq!(\n parse(input).unwrap(),\n Value::Object(HashMap::from([\n (\"key1\".to_string(), Value::Str(\"value1\".to_string())),\n (\"key2\".to_string(), Value::Array(vec![\n Value::Number(1.0),\n Value::Bool(true),\n Value::Null\n ]))\n ]))\n );\n }\n\n #[test]\n fn test_parse_malformed_input() {\n let input = \"invalid input\";\n assert!(parse(input).is_err());\n }\n\n #[test]\n fn test_parse_unterminated_string() {\n let input = \"\\\"Hello, world\";\n assert!(parse(input).is_err());\n }\n\n #[test]\n fn test_parse_invalid_number() {\n let input = \"123abc\";\n assert!(parse(input).is_err());\n }\n\n #[test]\n fn test_parse_invalid_array() {\n let input = \"[1, 2, 3\";\n assert!(parse(input).is_err());\n }\n\n #[test]\n fn test_parse_invalid_object() {\n let input = \"{key1: value1\";\n assert!(parse(input).is_err());\n }\n}\n```",
"passed": 0,
"test_error": "error: unknown character escape: `b`\n --> src/lib.rs:210:39\n |\n210 | 'b' => str.push('\\b'),\n | ^ unknown character escape\n |\n = help: for more information, visit <https://doc.rust-lang.org/reference/tokens.html#literals>\nhelp: if you meant to write a literal backslash (perhaps escaping in a regular expression), consider a raw string literal\n |\n210 - 'b' => str.push('\\b'),\n210 + 'b' => str.push(r\"\\b\"),\n |\n\nerror: unknown character escape: `f`\n --> src/lib.rs:211:39\n |\n211 | 'f' => str.push('\\f'),\n | ^ unknown character escape\n |\n = help: for more information, visit <https://doc.rust-lang.org/reference/tokens.html#literals>\nhelp: if you meant to write a literal backslash (perhaps escaping in a regular expression), consider a raw string literal\n |\n211 - 'f' => str.push('\\f'),\n211 + 'f' => str.push(r\"\\f\"),\n |\n\nerror: mismatched closing delimiter: `}`\n --> src/lib.rs:54:17\n |\n46 | match chars.next().unwrap() {\n | - closing delimiter possibly meant for this\n...\n54 | _ => Err(ParseError::new(&format!(\"Unexpected character: {}\", c)),\n | ^ unclosed delimiter\n55 | }\n | ^ mismatched closing delimiter\n\nerror: mismatched closing delimiter: `}`\n --> src/lib.rs:127:23\n |\n126 | if ch == ']' {\n | - closing delimiter possibly meant for this\n127 | return Err(ParseError::new(\"Unexpected ']'\");\n | ^ unclosed delimiter\n128 | }\n | ^ mismatched closing delimiter\n\nerror: mismatched closing delimiter: `]`\n --> src/lib.rs:298:29\n |\n294 | Value::Array(vec![\n | - closing delimiter possibly meant for this\n...\n298 | Value::Array(vec![Value::Number(2.0), Value::Number(3.0)]\n | ^ unclosed delimiter\n299 | ])\n | ^ mismatched closing delimiter\n\nerror: could not compile `challenge` (lib) due to 5 previous errors\nerror: could not compile `challenge` (lib test) due to 5 previous errors"
},
{
"total": 1,
"answer": "```rust\n// src/lib.rs\n\nuse std::collections::HashMap;\nuse std::fmt;\nuse std::str::FromStr;\n\n#[derive(Debug, Clone, PartialEq)]\npub enum Value {\n Null,\n Bool(bool),\n Number(f64),\n Str(String),\n Array(Vec<Value>),\n Object(HashMap<String, Value>),\n}\n\n#[derive(Debug, Clone, PartialEq)]\npub struct ParseError {\n message: String,\n position: usize,\n}\n\nimpl ParseError {\n fn new(message: &str, position: usize) -> Self {\n ParseError {\n message: message.to_string(),\n position,\n }\n }\n}\n\nimpl fmt::Display for ParseError {\n fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {\n write!(f, \"ParseError at position {}: {}\", self.position, self.message)\n }\n}\n\nfn parse(input: &str) -> Result<Value, ParseError> {\n let mut chars = input.chars().enumerate();\n parse_value(chars)\n}\n\nfn parse_value(chars: &mut std::iter::Enumerate<char>) -> Result<Value, ParseError> {\n skip_whitespace(chars);\n\n match chars.next().unwrap() {\n '{' => parse_object(chars),\n '[' => parse_array(chars),\n 't' => parse_bool(true, chars),\n 'f' => parse_bool(false, chars),\n 'n' => parse_null(chars),\n '\"' => parse_str(chars),\n c if c.is_digit(10) || c == '.' || c == 'e' || c == '-' || c == '+' || c == '*' || c == '/' => parse_number(chars),\n _ => Err(ParseError::new(&format!(\"Unexpected character: {}\", c)),\n }\n}\n\nfn parse_object(chars: &mut std::iter::Enumerate<char>) -> Result<Value, ParseError> {\n let mut object = HashMap::new();\n\n skip_whitespace(chars);\n\n if chars.next().unwrap() != '{' {\n return Err(ParseError::new(\"Expected '{'\"));\n }\n\n while let Some((_, ch)) = chars.next() {\n if ch == '}' {\n break;\n }\n\n skip_whitespace(chars);\n\n if ch != '\"' {\n return Err(ParseError::new(\"Expected '\\\"'\"));\n }\n\n let key = parse_str(chars)?;\n\n skip_whitespace(chars);\n\n if chars.next().unwrap() != ':' {\n return Err(ParseError::new(\"Expected ':'\"));\n }\n\n skip_whitespace(chars);\n\n if chars.next().unwrap() == '}' {\n return Err(ParseError::new(\"Unexpected '}'\"));\n }\n\n let value = parse_value(chars)?;\n\n object.insert(key, value);\n\n skip_whitespace(chars);\n\n if chars.next().unwrap() == '}' {\n break;\n }\n\n if chars.next().unwrap() != ',' {\n return Err(ParseError::new(\"Expected ','\"));\n }\n }\n\n Ok(Value::Object(object))\n}\n\nfn parse_array(chars: &mut std::iter::Enumerate<char>) -> Result<Value, ParseError> {\n let mut array = Vec::new();\n\n skip_whitespace(chars);\n\n if chars.next().unwrap() != '[' {\n return Err(ParseError::new(\"Expected '['\"));\n }\n\n while let Some((_, ch)) = chars.next() {\n if ch == ']' {\n break;\n }\n\n skip_whitespace(chars);\n\n if ch == ']' {\n return Err(ParseError::new(\"Unexpected ']'\");\n }\n\n let value = parse_value(chars)?;\n\n array.push(value);\n\n skip_whitespace(chars);\n\n if chars.next().unwrap() == ']' {\n break;\n }\n\n if chars.next().unwrap() != ',' {\n return Err(ParseError::new(\"Expected ','\"));\n }\n }\n\n Ok(Value::Array(array))\n}\n\nfn parse_bool(value: bool, chars: &mut std::iter::Enumerate<char>) -> Result<Value, ParseError> {\n if let Some((_, ch)) = chars.next() {\n if ch == 't' {\n if chars.next().unwrap() == 'r' {\n if chars.next().unwrap() == 'u' {\n if chars.next().unwrap() == 'e' {\n if chars.next().unwrap() == ' ' {\n return Ok(Value::Bool(true));\n }\n }\n }\n }\n } else if ch == 'f' {\n if chars.next().unwrap() == 'a' {\n if chars.next().unwrap() == 'l' {\n if chars.next().unwrap() == 's' {\n if chars.next().unwrap() == 'e' {\n return Ok(Value::Bool(false));\n }\n }\n }\n }\n }\n }\n\n Err(ParseError::new(\"Invalid boolean literal\"))\n}\n\nfn parse_null(chars: &mut std::iter::Enumerate<char>) -> Result<Value, ParseError> {\n if let Some((_, ch)) = chars.next() {\n if ch == 'n' {\n if chars.next().unwrap() == 'u' {\n if chars.next().unwrap() == 'l' {\n if chars.next().unwrap() == 'l' {\n return Ok(Value::Null);\n }\n }\n }\n }\n }\n\n Err(ParseError::new(\"Invalid null literal\"))\n}\n\nfn parse_str(chars: &mut std::iter::Enumerate<char>) -> Result<Value, ParseError> {\n let mut str = String::new();\n\n while let Some((_, ch)) = chars.next() {\n if ch == '\"' {\n break;\n }\n\n match ch {\n '\"' => return Err(ParseError::new(\"Unterminated string\")),\n '\\\\' => {\n chars.next();\n match chars.next() {\n '\"' => str.push('\"'),\n '\\\\' => str.push('\\\\'),\n 'n' => str.push('\\n'),\n 't' => str.push('\\t'),\n 'r' => str.push('\\r'),\n 'b' => str.push('\\b'),\n 'f' => str.push('\\f'),\n c if c.is_ascii_hexdigit() => {\n let mut hex_digits = String::new();\n for _ in 0..2 {\n hex_digits.push(chars.next().unwrap());\n }\n str.push_str(&str::from_utf8_lossy(&hex_digits).to_string());\n }\n _ => return Err(ParseError::new(\"Invalid escape sequence\")),\n }\n }\n _ => str.push(ch),\n }\n }\n\n Ok(Value::Str(str))\n}\n\nfn parse_number(chars: &mut std::iter::Enumerate<char>) -> Result<Value, ParseError> {\n let mut number = String::new();\n\n while let Some((_, ch)) = chars.next() {\n if ch.is_digit(10) || ch == '.' || ch == 'e' || ch == '+' || ch == '-' || ch == '*' || ch == '/' {\n number.push(ch);\n } else {\n break;\n }\n }\n\n if let Ok(num) = f64::from_str(&number) {\n Ok(Value::Number(num))\n } else {\n Err(ParseError::new(\"Invalid number\"))\n }\n}\n\nfn skip_whitespace(chars: &mut std::iter::Enumerate<char>) {\n while let Some((_, ch)) = chars.next() {\n if !ch.is_whitespace() {\n break;\n }\n }\n}\n\n#[cfg(test)]\nmod tests {\n use super::*;\n\n #[test]\n fn test_parse_null() {\n let input = \"null\";\n assert_eq!(parse(input).unwrap(), Value::Null);\n }\n\n #[test]\n fn test_parse_bool_true() {\n let input = \"true\";\n assert_eq!(parse(input).unwrap(), Value::Bool(true));\n }\n\n #[test]\n fn test_parse_bool_false() {\n let input = \"false\";\n assert_eq!(parse(input).unwrap(), Value::Bool(false));\n }\n\n #[test]\n fn test_parse_number() {\n let input = \"123.456\";\n assert_eq!(parse(input).unwrap(), Value::Number(123.456));\n }\n\n #[test]\n fn test_parse_string() {\n let input = \"\\\"Hello, world!\\\"\";\n assert_eq!(parse(input).unwrap(), Value::Str(\"Hello, world!\".to_string()));\n }\n\n #[test]\n fn test_parse_array() {\n let input = \"[1, true, null, [2, 3]]\";\n assert_eq!(\n parse(input).unwrap(),\n Value::Array(vec![\n Value::Number(1.0),\n Value::Bool(true),\n Value::Null,\n Value::Array(vec![Value::Number(2.0), Value::Number(3.0)]\n ])\n );\n }\n\n #[test]\n fn test_parse_object() {\n let input = \"{\\\"key1\\\": \\\"value1\\\", \\\"key2\\\": [1, true, null]}\";\n assert_eq!(\n parse(input).unwrap(),\n Value::Object(HashMap::from([\n (\"key1\".to_string(), Value::Str(\"value1\".to_string())),\n (\"key2\".to_string(), Value::Array(vec![\n Value::Number(1.0),\n Value::Bool(true),\n Value::Null\n ]))\n ]))\n );\n }\n\n #[test]\n fn test_parse_malformed_input() {\n let input = \"invalid input\";\n assert!(parse(input).is_err());\n }\n\n #[test]\n fn test_parse_unterminated_string() {\n let input = \"\\\"Hello, world\";\n assert!(parse(input).is_err());\n }\n\n #[test]\n fn test_parse_invalid_number() {\n let input = \"123abc\";\n assert!(parse(input).is_err());\n }\n\n #[test]\n fn test_parse_invalid_array() {\n let input = \"[1, 2, 3\";\n assert!(parse(input).is_err());\n }\n\n #[test]\n fn test_parse_invalid_object() {\n let input = \"{key1: value1\";\n assert!(parse(input).is_err());\n }\n\n #[test]\n fn test_parse_backspace() {\n let input = \"\\\"Hello, \\bworld\\\"\";\n assert_eq!(parse(input).unwrap(), Value::Str(\"Hello, world\".to_string()));\n }\n\n #[test]\n fn test_parse_hex_escape() {\n let input = \"\\\"Hello, \\\\u0041\\\"\";\n assert_eq!(parse(input).unwrap(), Value::Str(\"Hello, A\".to_string()));\n }\n}\n```",
"passed": 0,
"test_error": ": if you meant to write a literal backslash (perhaps escaping in a regular expression), consider a raw string literal\n |\n210 - 'b' => str.push('\\b'),\n210 + 'b' => str.push(r\"\\b\"),\n |\n\nerror: unknown character escape: `f`\n --> src/lib.rs:211:39\n |\n211 | 'f' => str.push('\\f'),\n | ^ unknown character escape\n |\n = help: for more information, visit <https://doc.rust-lang.org/reference/tokens.html#literals>\nhelp: if you meant to write a literal backslash (perhaps escaping in a regular expression), consider a raw string literal\n |\n211 - 'f' => str.push('\\f'),\n211 + 'f' => str.push(r\"\\f\"),\n |\n\nerror: unknown character escape: `b`\n --> src/lib.rs:351:32\n |\n351 | let input = \"\\\"Hello, \\bworld\\\"\";\n | ^ unknown character escape\n |\n = help: for more information, visit <https://doc.rust-lang.org/reference/tokens.html#literals>\nhelp: if you meant to write a literal backslash (perhaps escaping in a regular expression), consider a raw string literal\n |\n351 | let input = r\"\\\"Hello, \\bworld\\\"\";\n | +\n\nerror: mismatched closing delimiter: `}`\n --> src/lib.rs:54:17\n |\n46 | match chars.next().unwrap() {\n | - closing delimiter possibly meant for this\n...\n54 | _ => Err(ParseError::new(&format!(\"Unexpected character: {}\", c)),\n | ^ unclosed delimiter\n55 | }\n | ^ mismatched closing delimiter\n\nerror: mismatched closing delimiter: `}`\n --> src/lib.rs:127:23\n |\n126 | if ch == ']' {\n | - closing delimiter possibly meant for this\n127 | return Err(ParseError::new(\"Unexpected ']'\");\n | ^ unclosed delimiter\n128 | }\n | ^ mismatched closing delimiter\n\nerror: mismatched closing delimiter: `]`\n --> src/lib.rs:298:29\n |\n294 | Value::Array(vec![\n | - closing delimiter possibly meant for this\n...\n298 | Value::Array(vec![Value::Number(2.0), Value::Number(3.0)]\n | ^ unclosed delimiter\n299 | ])\n | ^ mismatched closing delimiter\n\nerror: could not compile `challenge` (lib test) due to 6 previous errors\nerror: could not compile `challenge` (lib) due to 6 previous errors"
},
{
"total": 1,
"answer": "```rust\n// src/lib.rs\n\nuse std::collections::HashMap;\nuse std::fmt;\nuse std::str::FromStr;\n\n#[derive(Debug, Clone, PartialEq)]\npub enum Value {\n Null,\n Bool(bool),\n Number(f64),\n Str(String),\n Array(Vec<Value>),\n Object(HashMap<String, Value>),\n}\n\n#[derive(Debug, Clone, PartialEq)]\npub struct ParseError {\n message: String,\n position: usize,\n}\n\nimpl ParseError {\n fn new(message: &str, position: usize) -> Self {\n ParseError {\n message: message.to_string(),\n position,\n }\n }\n}\n\nimpl fmt::Display for ParseError {\n fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {\n write!(f, \"ParseError at position {}: {}\", self.position, self.message)\n }\n}\n\nfn parse(input: &str) -> Result<Value, ParseError> {\n let mut chars = input.chars().enumerate();\n parse_value(chars)\n}\n\nfn parse_value(chars: &mut std::iter::Enumerate<char>) -> Result<Value, ParseError> {\n skip_whitespace(chars);\n\n match chars.next().unwrap() {\n '{' => parse_object(chars),\n '[' => parse_array(chars),\n 't' => parse_bool(true, chars),\n 'f' => parse_bool(false, chars),\n 'n' => parse_null(chars),\n '\"' => parse_str(chars),\n c if c.is_digit(10) || c == '.' || c == 'e' || c == '-' || c == '+' || c == '*' || c == '/' => parse_number(chars),\n _ => Err(ParseError::new(&format!(\"Unexpected character: {}\", c)),\n }\n}\n\nfn parse_object(chars: &mut std::iter::Enumerate<char>) -> Result<Value, ParseError> {\n let mut object = HashMap::new();\n\n skip_whitespace(chars);\n\n if chars.next().unwrap() != '{' {\n return Err(ParseError::new(\"Expected '{'\"));\n }\n\n while let Some((_, ch)) = chars.next() {\n if ch == '}' {\n break;\n }\n\n skip_whitespace(chars);\n\n if ch != '\"' {\n return Err(ParseError::new(\"Expected '\\\"'\"));\n }\n\n let key = parse_str(chars)?;\n\n skip_whitespace(chars);\n\n if chars.next().unwrap() != ':' {\n return Err(ParseError::new(\"Expected ':'\"));\n }\n\n skip_whitespace(chars);\n\n if chars.next().unwrap() == '}' {\n return Err(ParseError::new(\"Unexpected '}'\"));\n }\n\n let value = parse_value(chars)?;\n\n object.insert(key, value);\n\n skip_whitespace(chars);\n\n if chars.next().unwrap() == '}' {\n break;\n }\n\n if chars.next().unwrap() != ',' {\n return Err(ParseError::new(\"Expected ','\"));\n }\n }\n\n Ok(Value::Object(object))\n}\n\nfn parse_array(chars: &mut std::iter::Enumerate<char>) -> Result<Value, ParseError> {\n let mut array = Vec::new();\n\n skip_whitespace(chars);\n\n if chars.next().unwrap() != '[' {\n return Err(ParseError::new(\"Expected '['\"));\n }\n\n while let Some((_, ch)) = chars.next() {\n if ch == ']' {\n break;\n }\n\n skip_whitespace(chars);\n\n if ch == ']' {\n return Err(ParseError::new(\"Unexpected ']'\");\n }\n\n let value = parse_value(chars)?;\n\n array.push(value);\n\n skip_whitespace(chars);\n\n if chars.next().unwrap() == ']' {\n break;\n }\n\n if chars.next().unwrap() != ',' {\n return Err(ParseError::new(\"Expected ','\"));\n }\n }\n\n Ok(Value::Array(array))\n}\n\nfn parse_bool(value: bool, chars: &mut std::iter::Enumerate<char>) -> Result<Value, ParseError> {\n if let Some((_, ch)) = chars.next() {\n if ch == 't' {\n if chars.next().unwrap() == 'r' {\n if chars.next().unwrap() == 'u' {\n if chars.next().unwrap() == 'e' {\n if chars.next().unwrap() == ' ' {\n return Ok(Value::Bool(true));\n }\n }\n }\n }\n } else if ch == 'f' {\n if chars.next().unwrap() == 'a' {\n if chars.next().unwrap() == 'l' {\n if chars.next().unwrap() == 's' {\n if chars.next().unwrap() == 'e' {\n return Ok(Value::Bool(false));\n }\n }\n }\n }\n }\n }\n\n Err(ParseError::new(\"Invalid boolean literal\"))\n}\n\nfn parse_null(chars: &mut std::iter::Enumerate<char>) -> Result<Value, ParseError> {\n if let Some((_, ch)) = chars.next() {\n if ch == 'n' {\n if chars.next().unwrap() == 'u' {\n if chars.next().unwrap() == 'l' {\n if chars.next().unwrap() == 'l' {\n return Ok(Value::Null);\n }\n }\n }\n }\n }\n\n Err(ParseError::new(\"Invalid null literal\"))\n}\n\nfn parse_str(chars: &mut std::iter::Enumerate<char>) -> Result<Value, ParseError> {\n let mut str = String::new();\n\n while let Some((_, ch)) = chars.next() {\n if ch == '\"' {\n break;\n }\n\n match ch {\n '\"' => return Err(ParseError::new(\"Unterminated string\")),\n '\\\\' => {\n chars.next();\n match chars.next() {\n '\"' => str.push('\"'),\n '\\\\' => str.push('\\\\'),\n 'n' => str.push('\\n'),\n 't' => str.push('\\t'),\n 'r' => str.push('\\r'),\n 'b' => str.push('\\b'),\n 'f' => str.push('\\f'),\n c if c.is_ascii_hexdigit() => {\n let mut hex_digits = String::new();\n for _ in 0..2 {\n hex_digits.push(chars.next().unwrap());\n }\n str.push_str(&str::from_utf8_lossy(&hex_digits).to_string());\n }\n _ => return Err(ParseError::new(\"Invalid escape sequence\")),\n }\n }\n _ => str.push(ch),\n }\n }\n\n Ok(Value::Str(str))\n}\n\nfn parse_number(chars: &mut std::iter::Enumerate<char>) -> Result<Value, ParseError> {\n let mut number = String::new();\n\n while let Some((_, ch)) = chars.next() {\n if ch.is_digit(10) || ch == '.' || ch == 'e' || ch == '+' || ch == '-' || ch == '*' || ch == '/' {\n number.push(ch);\n } else {\n break;\n }\n }\n\n if let Ok(num) = f64::from_str(&number) {\n Ok(Value::Number(num))\n } else {\n Err(ParseError::new(\"Invalid number\"))\n }\n}\n\nfn skip_whitespace(chars: &mut std::iter::Enumerate<char>) {\n while let Some((_, ch)) = chars.next() {\n if !ch.is_whitespace() {\n break;\n }\n }\n}\n\n#[cfg(test)]\nmod tests {\n use super::*;\n\n #[test]\n fn test_parse_null() {\n let input = \"null\";\n assert_eq!(parse(input).unwrap(), Value::Null);\n }\n\n #[test]\n fn test_parse_bool_true() {\n let input = \"true\";\n assert_eq!(parse(input).unwrap(), Value::Bool(true));\n }\n\n #[test]\n fn test_parse_bool_false() {\n let input = \"false\";\n assert_eq!(parse(input).unwrap(), Value::Bool(false));\n }\n\n #[test]\n fn test_parse_number() {\n let input = \"123.456\";\n assert_eq!(parse(input).unwrap(), Value::Number(123.456));\n }\n\n #[test]\n fn test_parse_string() {\n let input = \"\\\"Hello, world!\\\"\";\n assert_eq!(parse(input).unwrap(), Value::Str(\"Hello, world!\".to_string()));\n }\n\n #[test]\n fn test_parse_array() {\n let input = \"[1, true, null, [2, 3]]\";\n assert_eq!(\n parse(input).unwrap(),\n Value::Array(vec![\n Value::Number(1.0),\n Value::Bool(true),\n Value::Null,\n Value::Array(vec![Value::Number(2.0), Value::Number(3.0)]\n ])\n );\n }\n\n #[test]\n fn test_parse_object() {\n let input = \"{\\\"key1\\\": \\\"value1\\\", \\\"key2\\\": [1, true, null]}\";\n assert_eq!(\n parse(input).unwrap(),\n Value::Object(HashMap::from([\n (\"key1\".to_string(), Value::Str(\"value1\".to_string())),\n (\"key2\".to_string(), Value::Array(vec![\n Value::Number(1.0),\n Value::Bool(true),\n Value::Null\n ]))\n ]))\n );\n }\n\n #[test]\n fn test_parse_malformed_input() {\n let input = \"invalid input\";\n assert!(parse(input).is_err());\n }\n\n #[test]\n fn test_parse_unterminated_string() {\n let input = \"\\\"Hello, world\";\n assert!(parse(input).is_err());\n }\n\n #[test]\n fn test_parse_invalid_number() {\n let input = \"123abc\";\n assert!(parse(input).is_err());\n }\n\n #[test]\n fn test_parse_invalid_array() {\n let input = \"[1, 2, 3\";\n assert!(parse(input).is_err());\n }\n\n #[test]\n fn test_parse_invalid_object() {\n let input = \"{key1: value1\";\n assert!(parse(input).is_err());\n }\n\n #[test]\n fn test_parse_backspace() {\n let input = \"\\\"Hello, \\bworld\\\"\";\n assert_eq!(parse(input).unwrap(), Value::Str(\"Hello, world\".to_string()));\n }\n\n #[test]\n fn test_parse_hex_escape() {\n let input = \"\\\"Hello, \\\\u0041\\\"\";\n assert_eq!(parse(input).unwrap(), Value::Str(\"Hello, A\".to_string()));\n }\n\n #[test]\n fn test_parse_raw_string() {\n let input = r#\"\\\"Hello, \\bworld\\\"\"#;\n assert_eq!(parse(input).unwrap(), Value::Str(\"Hello, world\".to_string()));\n }\n}\n```",
"passed": 0,
"test_error": ""
}
]System prompt
You are an expert programmer. Solve the task exactly as specified. Output your solution as fenced code blocks using the required file name(s) and the exact function/type signatures requested. Prefer correctness; do not include prose outside code unless asked.