use serde::de::DeserializeOwned;
#[derive(Debug)]
pub(super) enum ArrayParseError {
Invalid(serde_json::Error),
NotSingle,
}
pub(super) fn parse_single_array<T>(answer: &str) -> Result<T, ArrayParseError>
where
T: DeserializeOwned,
{
let mut parsed = None;
let mut parse_error = None;
let mut offset = 0;
while let Some(relative_start) = answer[offset..].find('[') {
let start = offset + relative_start;
let Some(length) = json_array_length(&answer[start..]) else {
offset = start + 1;
continue;
};
let json = &answer[start..start + length];
match serde_json::from_str(json) {
Ok(value) => {
if parsed.is_some() {
return Err(ArrayParseError::NotSingle);
}
parsed = Some(value);
}
Err(error) => {
if serde_json::from_str::<serde_json::Value>(json).is_ok() {
if parse_error.is_none() {
parse_error = Some(error);
}
} else {
offset = start + 1;
continue;
}
}
}
offset = start + length;
}
parsed.ok_or_else(|| parse_error.map_or(ArrayParseError::NotSingle, ArrayParseError::Invalid))
}
fn json_array_length(candidate: &str) -> Option<usize> {
let mut depth = 0;
let mut in_string = false;
let mut escaped = false;
for (index, character) in candidate.char_indices() {
if in_string {
if escaped {
escaped = false;
} else if character == '\\' {
escaped = true;
} else if character == '"' {
in_string = false;
}
continue;
}
match character {
'"' => in_string = true,
'[' => depth += 1,
']' => {
depth -= 1;
if depth == 0 {
return Some(index + character.len_utf8());
}
}
_ => {}
}
}
None
}