use std::ffi::c_void;
use indexmap::IndexMap;
use mumu::parser::interpreter::Interpreter;
use mumu::parser::types::Value;
use serde_json::{Map as JsonMap, Value as JsonVal};
mod codec; mod schema; mod validate; mod report;
#[export_name = "Cargo_lock"]
pub unsafe extern "C" fn cargo_lock(
interp_ptr: *mut c_void,
extra_str: *const c_void,
) -> i32 {
if interp_ptr.is_null() {
eprintln!("[json plugin] null interpreter pointer");
return 1;
}
let interpreter = &mut *(interp_ptr as *mut Interpreter);
if interpreter.is_verbose() {
if !extra_str.is_null() {
use std::ffi::CStr;
let extra = CStr::from_ptr(extra_str as *const i8).to_string_lossy();
eprintln!("[json plugin] loading (extra = \"{extra}\")");
} else {
eprintln!("[json plugin] loading");
}
}
codec::register_json_decode(interpreter);
codec::register_json_encode(interpreter);
schema::register_json_schema(interpreter);
validate::register_json_validate(interpreter);
report::register_json_report(interpreter);
if interpreter.is_verbose() {
eprintln!("[json plugin] ready");
}
0
}
pub fn jsonval_to_mumu(jv: &JsonVal) -> Value {
match jv {
JsonVal::Null => Value::Placeholder,
JsonVal::Bool(b) => Value::Bool(*b),
JsonVal::Number(n) => {
if let Some(i) = n.as_i64() {
if (i32::MIN as i64..=i32::MAX as i64).contains(&i) {
Value::Int(i as i32)
} else {
Value::Long(i)
}
} else if let Some(f) = n.as_f64() {
Value::Float(f)
} else {
Value::Placeholder
}
}
JsonVal::String(s) => Value::SingleString(s.clone()),
JsonVal::Array(arr) => {
if arr.iter().all(|v| v.is_i64()) {
Value::IntArray(arr.iter().map(|v| v.as_i64().unwrap() as i32).collect())
} else if arr.iter().all(|v| v.is_f64()) {
Value::FloatArray(arr.iter().map(|v| v.as_f64().unwrap()).collect())
} else if arr.iter().all(|v| v.is_string()) {
Value::StrArray(arr.iter().map(|v| v.as_str().unwrap().to_string()).collect())
} else {
let mut map = IndexMap::new();
for (i, sub) in arr.iter().enumerate() {
map.insert(i.to_string(), jsonval_to_mumu(sub));
}
Value::KeyedArray(map)
}
}
JsonVal::Object(obj) => {
let mut map = IndexMap::new();
for (k, v) in obj {
map.insert(k.clone(), jsonval_to_mumu(v));
}
Value::KeyedArray(map)
}
}
}
pub fn mumu_value_to_json(v: &Value) -> JsonVal {
match v {
Value::Placeholder => JsonVal::Null,
Value::Bool(b) => JsonVal::Bool(*b),
Value::Int(i) => JsonVal::Number((*i).into()),
Value::Long(l) => JsonVal::Number((*l).into()),
Value::Float(f) => JsonVal::Number(
serde_json::Number::from_f64(*f).unwrap_or_else(|| 0.into())
),
Value::SingleString(s) => JsonVal::String(s.clone()),
Value::IntArray(xs) => JsonVal::Array(
xs.iter().map(|n| JsonVal::Number((*n).into())).collect()
),
Value::FloatArray(fs) => JsonVal::Array(
fs.iter()
.map(|f| JsonVal::Number(
serde_json::Number::from_f64(*f).unwrap_or_else(|| 0.into())
))
.collect(),
),
Value::BoolArray(bs) => JsonVal::Array(bs.iter().map(|b| JsonVal::Bool(*b)).collect()),
Value::StrArray(ss) => JsonVal::Array(ss.iter().map(|s| JsonVal::String(s.clone())).collect()),
Value::Int2DArray(rows) => JsonVal::Array(rows.iter().map(|r|
JsonVal::Array(r.iter().map(|n| JsonVal::Number((*n).into())).collect())
).collect()),
Value::Float2DArray(rows) => JsonVal::Array(rows.iter().map(|r|
JsonVal::Array(r.iter().map(|f|
JsonVal::Number(serde_json::Number::from_f64(*f).unwrap_or_else(|| 0.into()))
).collect())
).collect()),
Value::KeyedArray(map) => {
let mut obj = JsonMap::new();
for (k, v) in map {
obj.insert(k.clone(), mumu_value_to_json(v));
}
JsonVal::Object(obj)
}
_ => JsonVal::Null,
}
}