use crate::quickjs_utils;
use crate::quickjsrealmadapter::QuickJsRealmAdapter;
use crate::valueref::JSValueRef;
use hirofa_utils::js_utils::JsError;
use libquickjs_sys as q;
use std::ffi::CString;
pub fn parse_q(q_ctx: &QuickJsRealmAdapter, input: &str) -> Result<JSValueRef, JsError> {
unsafe { parse(q_ctx.context, input) }
}
pub unsafe fn parse(context: *mut q::JSContext, input: &str) -> Result<JSValueRef, JsError> {
let s = CString::new(input).ok().unwrap();
let f_n = CString::new("JSON.parse").ok().unwrap();
let len = input.len();
let val = q::JS_ParseJSON(context, s.as_ptr(), len as _, f_n.as_ptr());
let ret = JSValueRef::new(context, val, false, true, "json::parse result");
if ret.is_exception() {
if let Some(ex) = QuickJsRealmAdapter::get_exception(context) {
Err(ex)
} else {
Err(JsError::new_str("unknown error while parsing json"))
}
} else {
Ok(ret)
}
}
pub fn stringify_q(
q_ctx: &QuickJsRealmAdapter,
input: &JSValueRef,
opt_space: Option<JSValueRef>,
) -> Result<JSValueRef, JsError> {
unsafe { stringify(q_ctx.context, input, opt_space) }
}
pub unsafe fn stringify(
context: *mut q::JSContext,
input: &JSValueRef,
opt_space: Option<JSValueRef>,
) -> Result<JSValueRef, JsError> {
let space_ref = match opt_space {
None => quickjs_utils::new_null_ref(),
Some(s) => s,
};
let val = q::JS_JSONStringify(
context,
*input.borrow_value(),
quickjs_utils::new_null(),
*space_ref.borrow_value(),
);
let ret = JSValueRef::new(context, val, false, true, "json::stringify result");
if ret.is_exception() {
if let Some(ex) = QuickJsRealmAdapter::get_exception(context) {
Err(ex)
} else {
Err(JsError::new_str("unknown error in json::stringify"))
}
} else {
Ok(ret)
}
}
#[cfg(test)]
pub mod tests {
use crate::facades::tests::init_test_rt;
use crate::quickjs_utils::json::parse_q;
use crate::quickjs_utils::{get_global_q, json, objects, primitives};
use hirofa_utils::js_utils::adapters::JsRealmAdapter;
use hirofa_utils::js_utils::facades::values::JsValueFacade;
use hirofa_utils::js_utils::facades::JsRuntimeFacade;
use hirofa_utils::js_utils::Script;
use std::collections::HashMap;
#[test]
fn test_json() {
let rt = init_test_rt();
rt.exe_rt_task_in_event_loop(|q_js_rt| {
let q_ctx = q_js_rt.get_main_context();
let obj = objects::create_object_q(q_ctx).ok().unwrap();
objects::set_property_q(q_ctx, &obj, "a", &primitives::from_i32(532))
.ok()
.unwrap();
objects::set_property_q(q_ctx, &obj, "b", &primitives::from_bool(true))
.ok()
.unwrap();
objects::set_property_q(
q_ctx,
&obj,
"c",
&primitives::from_string_q(q_ctx, "abc").ok().unwrap(),
)
.ok()
.unwrap();
let str_res = json::stringify_q(q_ctx, &obj, None).ok().unwrap();
assert_eq!(str_res.get_ref_count(), 1);
let json = primitives::to_string_q(q_ctx, &str_res).ok().unwrap();
assert_eq!(json.as_str(), "{\"a\":532,\"b\":true,\"c\":\"abc\"}");
let obj2 = json::parse_q(q_ctx, json.as_str()).ok().unwrap();
assert_eq!(
532,
primitives::to_i32(&objects::get_property_q(q_ctx, &obj2, "a").ok().unwrap())
.ok()
.unwrap()
);
});
}
#[tokio::test]
async fn test_json_arg() {
let rt = init_test_rt();
rt.js_eval(
None,
Script::new(
"myFunc.js",
r#"
function myFunction(argObj) {
console.log("I got an %s", typeof argObj);
console.log("It looks like this %s", argObj);
return "hello " + argObj["key"];
}
"#,
),
)
.await
.ok()
.expect("myFunc failed to parse");
let mut my_json_deserable_object = HashMap::new();
my_json_deserable_object.insert("key", "value");
let json = serde_json::to_string(&my_json_deserable_object)
.ok()
.expect("serializing failed");
let func_res = rt
.js_loop_realm(None, move |_rt, realm| {
let js_obj = parse_q(realm, json.as_str())
.ok()
.expect("parsing json failed");
let global = get_global_q(realm);
let func_res = crate::quickjs_utils::functions::invoke_member_function_q(
realm,
&global,
"myFunction",
vec![js_obj],
);
realm.to_js_value_facade(&func_res.ok().expect("func failed"))
})
.await;
let jsv = func_res.ok().expect("got err");
assert_eq!(jsv.stringify(), "String: hello value");
}
#[tokio::test]
async fn test_json_arg2() {
let rt = init_test_rt();
rt.js_eval(
None,
Script::new(
"myFunc.js",
r#"
function myFunction(argObj) {
console.log("I got an %s", typeof argObj);
console.log("It looks like this %s", argObj);
return "hello " + argObj["key"];
}
"#,
),
)
.await
.ok()
.expect("myFunc failed to parse");
let mut my_json_deserable_object = HashMap::new();
my_json_deserable_object.insert("key", "value");
let json = serde_json::to_string(&my_json_deserable_object)
.ok()
.expect("serializing failed");
let json_js_value_facade = JsValueFacade::JsonStr { json };
let func_res = rt
.js_function_invoke(None, &[], "myFunction", vec![json_js_value_facade])
.await;
let jsv = func_res.ok().expect("got err");
assert_eq!(jsv.stringify(), "String: hello value");
}
}