use serde_json::Value;
pub fn parse_streaming_json(json: &str) -> Value {
if json.trim().is_empty() {
return Value::Object(serde_json::Map::new());
}
if let Ok(value) = serde_json::from_str::<Value>(json) {
return value;
}
let fixed = fix_incomplete_json(json);
if let Ok(value) = serde_json::from_str::<Value>(&fixed) {
return value;
}
Value::Object(serde_json::Map::new())
}
fn fix_incomplete_json(json: &str) -> String {
let mut result = json.to_string();
let mut stack: Vec<char> = Vec::new();
let mut in_string = false;
let mut escape_next = false;
for ch in json.chars() {
if escape_next {
escape_next = false;
continue;
}
match ch {
'\\' if in_string => escape_next = true,
'"' => in_string = !in_string,
'{' | '[' if !in_string => stack.push(ch),
'}' if !in_string => {
if let Some('{') = stack.last() {
stack.pop();
}
}
']' if !in_string => {
if let Some('[') = stack.last() {
stack.pop();
}
}
_ => {}
}
}
if in_string {
result.push('"');
}
while let Some(ch) = stack.pop() {
match ch {
'{' => result.push('}'),
'[' => result.push(']'),
_ => {}
}
}
result
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_empty_json() {
let result = parse_streaming_json("");
assert!(result.is_object());
assert!(result.as_object().unwrap().is_empty());
}
#[test]
fn test_complete_json() {
let result = parse_streaming_json(r#"{"name": "test", "value": 123}"#);
assert_eq!(result["name"], "test");
assert_eq!(result["value"], 123);
}
#[test]
fn test_incomplete_json_object() {
let result = parse_streaming_json(r#"{"name": "test""#);
assert_eq!(result["name"], "test");
}
#[test]
fn test_incomplete_json_nested() {
let result = parse_streaming_json(r#"{"outer": {"inner": "value""#);
assert_eq!(result["outer"]["inner"], "value");
}
#[test]
fn test_incomplete_json_array() {
let result = parse_streaming_json(r#"{"items": [1, 2, 3"#);
let items = result["items"].as_array().unwrap();
assert_eq!(items.len(), 3);
}
#[test]
fn test_incomplete_json_string() {
let result = parse_streaming_json(r#"{"text": "hello"#);
assert_eq!(result["text"], "hello");
}
#[test]
fn test_escaped_quotes() {
let json = r#"{"text": "hello \"world\""}"#;
let result = parse_streaming_json(json);
assert_eq!(result["text"], r#"hello "world""#);
}
}