use wasmtime::anyhow;
use crate::app::{DecoderParam, ParamType};
use super::super::types::DecodedValue;
pub fn parse_json_results(json: &str) -> anyhow::Result<Vec<DecodedValue>> {
let json = json.trim();
if json == "[]" || json.is_empty() {
return Ok(Vec::new());
}
let mut results = Vec::new();
let chars: Vec<char> = json.chars().collect();
let len = chars.len();
if chars.first() != Some(&'[') || chars.last() != Some(&']') {
return Err(anyhow::anyhow!("Expected JSON array"));
}
let mut i = 1; while i < len - 1 {
skip_ws_comma(&chars, &mut i, len);
if i >= len - 1 || chars[i] == ']' {
break;
}
if chars[i] != '{' {
i += 1;
continue;
}
i += 1;
let mut label = String::new();
let mut value = String::new();
let mut offset: Option<usize> = None;
let mut length: Option<usize> = None;
while i < len && chars[i] != '}' {
skip_ws_comma(&chars, &mut i, len);
if i >= len || chars[i] == '}' {
break;
}
let key = parse_json_string(&chars, &mut i);
while i < len && (chars[i] == ':' || chars[i].is_whitespace()) {
i += 1;
}
if i < len && chars[i] == '"' {
let val = parse_json_string(&chars, &mut i);
match key.as_str() {
"label" => label = val,
"value" => value = val,
_ => {}
}
} else if i < len && (chars[i].is_ascii_digit() || chars[i] == '-') {
let num = parse_json_number(&chars, &mut i);
match key.as_str() {
"offset" => offset = Some(num as usize),
"length" => length = Some(num as usize),
_ => {}
}
} else {
while i < len && chars[i] != ',' && chars[i] != '}' {
i += 1;
}
}
}
if i < len && chars[i] == '}' {
i += 1;
}
if !label.is_empty() {
let range = match (offset, length) {
(Some(o), Some(l)) => Some((o, l)),
_ => None,
};
results.push(DecodedValue {
label,
value,
range,
color_index: None,
});
}
}
Ok(results)
}
pub fn parse_param_definitions(json: &str) -> Vec<DecoderParam> {
let json = json.trim();
if json == "[]" || json.is_empty() {
return Vec::new();
}
let chars: Vec<char> = json.chars().collect();
let len = chars.len();
if chars.first() != Some(&'[') || chars.last() != Some(&']') {
return Vec::new();
}
let mut params = Vec::new();
let mut i = 1;
while i < len - 1 {
skip_ws_comma(&chars, &mut i, len);
if i >= len - 1 || chars[i] == ']' {
break;
}
if chars[i] != '{' {
i += 1;
continue;
}
i += 1;
let mut name = String::new();
let mut type_str = String::from("string");
let mut default = String::new();
let mut choices: Vec<String> = Vec::new();
while i < len && chars[i] != '}' {
skip_ws_comma(&chars, &mut i, len);
if i >= len || chars[i] == '}' {
break;
}
let key = parse_json_string(&chars, &mut i);
while i < len && (chars[i] == ':' || chars[i].is_whitespace()) {
i += 1;
}
if i < len && chars[i] == '"' {
let val = parse_json_string(&chars, &mut i);
match key.as_str() {
"name" => name = val,
"type" => type_str = val,
"default" => default = val,
_ => {}
}
} else if i < len && chars[i] == '[' {
i += 1;
while i < len && chars[i] != ']' {
skip_ws_comma(&chars, &mut i, len);
if i < len && chars[i] == '"' {
choices.push(parse_json_string(&chars, &mut i));
} else if i < len && chars[i] != ']' {
i += 1;
}
}
if i < len {
i += 1; }
} else {
while i < len && chars[i] != ',' && chars[i] != '}' {
i += 1;
}
}
}
if i < len && chars[i] == '}' {
i += 1;
}
if !name.is_empty() {
let param_type = match type_str.as_str() {
"int" => ParamType::Int,
"bool" => ParamType::Bool,
"choice" => ParamType::Choice(choices),
_ => ParamType::String,
};
params.push(DecoderParam {
name,
param_type,
default: default.clone(),
value: default,
});
}
}
params
}
pub fn build_params_json(params: &[(String, String)]) -> String {
let mut json = String::from("{");
for (i, (k, v)) in params.iter().enumerate() {
if i > 0 {
json.push(',');
}
json.push('"');
json_escape_into(&mut json, k);
json.push_str("\":\"");
json_escape_into(&mut json, v);
json.push('"');
}
json.push('}');
json
}
fn skip_ws_comma(chars: &[char], i: &mut usize, len: usize) {
while *i < len && (chars[*i].is_whitespace() || chars[*i] == ',') {
*i += 1;
}
}
fn parse_json_number(chars: &[char], i: &mut usize) -> i64 {
let len = chars.len();
let start = *i;
if *i < len && chars[*i] == '-' {
*i += 1;
}
while *i < len && chars[*i].is_ascii_digit() {
*i += 1;
}
let s: String = chars[start..*i].iter().collect();
s.parse().unwrap_or(0)
}
fn parse_json_string(chars: &[char], i: &mut usize) -> String {
let len = chars.len();
while *i < len && chars[*i] != '"' {
*i += 1;
}
if *i >= len {
return String::new();
}
*i += 1;
let mut s = String::new();
while *i < len && chars[*i] != '"' {
if chars[*i] == '\\' && *i + 1 < len {
*i += 1;
match chars[*i] {
'n' => s.push('\n'),
't' => s.push('\t'),
'\\' => s.push('\\'),
'"' => s.push('"'),
'/' => s.push('/'),
_ => {
s.push('\\');
s.push(chars[*i]);
}
}
} else {
s.push(chars[*i]);
}
*i += 1;
}
if *i < len {
*i += 1; }
s
}
fn json_escape_into(out: &mut String, s: &str) {
for c in s.chars() {
match c {
'"' => out.push_str("\\\""),
'\\' => out.push_str("\\\\"),
'\n' => out.push_str("\\n"),
'\t' => out.push_str("\\t"),
_ => out.push(c),
}
}
}