use crate::{ErrorKind, Fragment, FragmentStatus};
#[inline]
pub fn extract_fragments(
data: &[u8],
structural_indices: &[u32],
bracket_pairs: &[(u32, u32)],
output: &mut Vec<Fragment>,
) {
let mut idx = 0;
while idx < structural_indices.len() {
let pos = structural_indices[idx];
let byte = data[pos as usize];
match byte {
b'{' | b'[' => {
let close_pos_opt = bracket_pairs
.binary_search_by_key(&pos, |(open, _close)| *open)
.ok()
.map(|pair_idx| bracket_pairs[pair_idx].1);
if let Some(close_pos) = close_pos_opt {
let status = FragmentStatus::Complete;
output.push(Fragment {
start: pos as usize,
length: (close_pos - pos + 1) as usize,
status,
});
idx += 1;
while idx < structural_indices.len() && structural_indices[idx] <= close_pos {
idx += 1;
}
} else {
let fragment_start = pos;
let mut scan_idx = idx + 1;
let mut fragment_end = data.len() as u32;
let mut unclosed_braces = if byte == b'{' { 1 } else { 0 };
let mut unclosed_brackets = if byte == b'[' { 1 } else { 0 };
while scan_idx < structural_indices.len() {
let scan_pos = structural_indices[scan_idx];
let scan_byte = data[scan_pos as usize];
match scan_byte {
b'{' | b'[' => {
let has_pair = bracket_pairs
.binary_search_by_key(&scan_pos, |(open, _close)| *open)
.is_ok();
if has_pair {
fragment_end = scan_pos;
break;
} else {
if scan_byte == b'{' {
unclosed_braces += 1;
} else {
unclosed_brackets += 1;
}
}
}
b'}' => {
if unclosed_braces > 0 {
unclosed_braces -= 1;
if unclosed_braces == 0 && unclosed_brackets == 0 {
fragment_end = scan_pos + 1;
break;
}
}
}
b']' => {
if unclosed_brackets > 0 {
unclosed_brackets -= 1;
if unclosed_braces == 0 && unclosed_brackets == 0 {
fragment_end = scan_pos + 1;
break;
}
}
}
_ => {}
}
scan_idx += 1;
}
output.push(Fragment {
start: fragment_start as usize,
length: (fragment_end - fragment_start) as usize,
status: FragmentStatus::Incomplete(if byte == b'{' {
ErrorKind::MissingClosingBrace
} else {
ErrorKind::MissingClosingBracket
}),
});
idx = scan_idx;
}
}
_ => {
idx += 1;
}
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_extract_simple_object() {
let json = br#"{"key":"value"}"#;
let indices = vec![0, 1, 6, 7, 14]; let bracket_pairs = vec![(0, 14)];
let mut fragments = vec![];
extract_fragments(
json,
&indices,
&bracket_pairs,
&mut fragments,
);
assert_eq!(fragments.len(), 1);
assert_eq!(fragments[0].start, 0);
assert_eq!(fragments[0].length, 15);
assert!(fragments[0].is_complete());
}
#[test]
fn test_extract_simple_array() {
let json = br#"[1,2,3]"#;
let indices = vec![0, 2, 4, 6]; let bracket_pairs = vec![(0, 6)];
let mut fragments = vec![];
extract_fragments(
json,
&indices,
&bracket_pairs,
&mut fragments,
);
assert_eq!(fragments.len(), 1);
assert_eq!(fragments[0].start, 0);
assert_eq!(fragments[0].length, 7);
assert!(fragments[0].is_complete());
}
}