use std::io::Write;
use crate::constants::PAIRED_MARKERS;
use crate::parser::marker::Marker;
pub struct JSONParser {
buffer: String,
markers: Vec<Marker>,
}
impl JSONParser {
pub fn new() -> Self {
Self {
buffer: String::new(),
markers: Vec::new(),
}
}
pub fn is_in_json(&self) -> bool {
!self.markers.is_empty()
}
fn remove_markers_pair(&mut self, item: &char) {
let mut markers_to_reverse: Vec<Marker> = self.markers.clone();
markers_to_reverse.reverse();
for marker in markers_to_reverse.iter() {
if marker.is_counter_part(item) {
self.markers.pop();
return;
}
}
}
fn update_markers(&mut self, item: &char) {
if let Some(marker) = Marker::new(item) {
self.markers.push(marker);
return;
}
self.remove_markers_pair(item);
if self.markers.is_empty() {
self.buffer.clear();
return;
}
}
pub fn extract_json_from_stream<W: Write>(&mut self, writer: &mut W, json_object: &str) -> Result<(), Box<dyn std::error::Error>> {
for item in json_object.chars() {
if self.is_in_json() {
self.buffer.push(item);
self.update_markers(&item);
write!(writer, "{}", item)?;
continue;
}
if PAIRED_MARKERS.contains(&item) {
self.buffer.push(item);
self.update_markers(&item);
write!(writer, "{}", item)?;
}
}
Ok(())
}
}
#[cfg(test)]
mod tests {
use super::*;
use std::io::BufWriter;
#[test]
fn test_json_parser_empty() {
let parser = JSONParser::new();
assert!(!parser.is_in_json());
assert!(parser.markers.is_empty());
}
#[test]
fn test_json_parser_extract_simple_json() {
let mut parser = JSONParser::new();
let mut buffer = Vec::new();
{
let mut writer = BufWriter::new(&mut buffer);
parser.extract_json_from_stream(&mut writer, "{}").unwrap();
writer.flush().unwrap();
}
assert!(!parser.is_in_json());
let output = String::from_utf8(buffer).unwrap();
assert_eq!(output, "{}");
}
#[test]
fn test_json_parser_extract_nested_json() {
let mut parser = JSONParser::new();
let mut buffer = Vec::new();
{
let mut writer = BufWriter::new(&mut buffer);
parser.extract_json_from_stream(&mut writer, "{\"key\": [1, 2, 3]}").unwrap();
assert!(!parser.is_in_json());
}
let output = String::from_utf8(buffer).unwrap();
assert_eq!(output, "{\"key\": [1, 2, 3]}");
}
#[test]
fn test_json_parser_extract_partial_json() {
let mut parser = JSONParser::new();
let mut buffer = Vec::new();
{
let mut writer = BufWriter::new(&mut buffer);
parser.extract_json_from_stream(&mut writer, "{\"key").unwrap();
assert!(parser.is_in_json());
parser.extract_json_from_stream(&mut writer, "\": [1, 2, 3]}").unwrap();
assert!(!parser.is_in_json());
}
let output = String::from_utf8(buffer).unwrap();
assert_eq!(output, "{\"key\": [1, 2, 3]}");
}
#[test]
fn test_json_parser_extract_json_mixed_with_text() {
let mut parser = JSONParser::new();
let mut buffer = Vec::new();
{
let mut writer = BufWriter::new(&mut buffer);
parser.extract_json_from_stream(&mut writer, "Some plain text {\"id\": 123, \"data\": ").unwrap();
assert!(parser.is_in_json());
parser.extract_json_from_stream(&mut writer, "{\"nested\": [1, 2, {\"deep\": true}]}}").unwrap();
assert!(!parser.is_in_json());
parser.extract_json_from_stream(&mut writer, " followed by more text").unwrap();
assert!(!parser.is_in_json());
parser.extract_json_from_stream(&mut writer, " and another {\"array\": [4, 5, 6]}").unwrap();
assert!(!parser.is_in_json());
}
let output = String::from_utf8(buffer).unwrap();
assert_eq!(output,
"{\"id\": 123, \"data\": {\"nested\": [1, 2, {\"deep\": true}]}}{\"array\": [4, 5, 6]}");
}
}