Comments (10)
Hi David,
Sounds like a good idea. I'll look into supporting that..
For now you could indeed serialize your value to json and use it in quickjs..
e.g.
this might not even be to different from how I may implement support for serde::Value it's just a bit more boilerplate code
#[tokio::test]
async fn test_json_arg() {
let rt = init_test_rt();
// init my javascript function
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");
// parse my obj to json
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| {
// this runs in the worker thread for the EventLoop so json String needs to be moved here
// now we parse the json to a JsValueRef
let js_obj = parse_q(realm, json.as_str()).ok().expect("parsing json failed");
// then we can invoke the function with that js_obj as input
// get the global obj as function container
let global = get_global_q(realm);
// invoke the function
let func_res = crate::quickjs_utils::functions::invoke_member_function_q(realm, &global, "myFunction", vec![js_obj]);
//return the value out of the worker thread as JsValueFacade
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");
}
from quickjs_es_runtime.
Oh, easier version (I forgot there allready was a JsValueFacade::JsonStr)
#[tokio::test]
async fn test_json_arg2() {
let rt = init_test_rt();
// init my javascript function
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");
// parse my obj to json
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");
}
from quickjs_es_runtime.
Thanks for the follow up! I was going to say the first version looked like it had to go too low level so was going to reply back with a simpler solution like the one you just shared once I had another chance to try out the code tonight - thanks for beating me to it!
I think the ideal solution to implement this would be to extend the JsValueConvertable trait to have support for native serde_json objects (with types serde_json::Map and serde_json::Value etc.) using to_js_value_facade() method so it works consistently with other values/code examples.
Ideally it also won't require having to convert it from json -> string -> JsValue and back again on return as that feels like there may be a performance hit in that somewhere!
from quickjs_es_runtime.
Hi, yes i agree, this should be handled natively..
I'll look into it
from quickjs_es_runtime.
should be usable in 0.8.7
from quickjs_es_runtime.
Thanks for implementing this. Unfortunately even after reading the code I'm struggling on how to use this. I can't see a .to_js_value_facade() implementation for serde_json:Value so I can easily pass an array of Objects to the function, and not entirely sure how to convert it back using the new method you added (serde_value_to_js_value_adapter) without getting the realm object. I was hoping or thinking it would work something like below:
let rows Vec<serde_json::Map<String, serde_json::Value>> = [..]
let result = PLUGIN_RT
.js_function_invoke(None, &[], &method_name, vec![rows.to_js_value_facade()])
.await
.unwrap();
let updated_rows: Vec<serde_json::Map<String, serde_json::Value>> = result.from_js_value_facade();
Can you show an example of how to call a function using the new code or add an implementation of to_js_value_facade for type serde_json::Value and serde_json::Map? Thanks!
from quickjs_es_runtime.
Ah yes, I forgot the to_js_value_facade for serde::Value, I'll impl that later today
but to convert a Value to JsValueFacade you can just use,
JsValueFacade::SerdeValue { value: my_serde_value }
And I assumed everything you get from serde is a Value, also Maps so I only implemented Value
How did you get a Vec<serde_json::Map<String, serde_json::Value>>
?
Can you alter that to get a Vec<Value>
? should be the same in the end
calling the function shoudl then be a matter of
let v: Vec<serde::Value> = vec![];
let js_value_facades: Vec<JsValueFacade> = v
.into_iter()
.map(|value| JsValueFacade::SerdeValue { value })
.collect();
let result = PLUGIN_RT
.js_function_invoke(None, &[], &method_name, js_value_facades)
.await
.unwrap();
The result will then be a JsValueFacade::JsObject
(which is basicly a reference to a value in the PLUGIN_RT)
(the reason for making this a reference and not a Map struct is so it may be used as input again for a different function and pass the actual reference to the js object)
Later I can impl a get_serde_value in JsValueFacade::JsObject which works just like js_get_object but return a Value instead of a HashMap<String, JsValueFacade>
Hmm I seem to be missing a handy util for turning a JsValueFacade into a json string.. i'll get back to that later also, in my current projects I mostly just return a json string from my functions so I don't need the extra job in the EventLoop (and thus my result JsValueFacade is a JsValueFacade::String)
to be continued...
from quickjs_es_runtime.
Hi - thanks, with a couple of modifications that worked to pass the array in, but still need to get the serde_json array back from the result - I can see its returning a JsValueFacade::Array of JsValueFacade::Object but not sure how to transform that back to a Vec<serde_json::Map<String, serde_json::Value>> as there's no .get_array() method on the result.
// Convert rows into JS values that can be passed to the QuickJS sandbox
let js_value_facades = JsValueFacade::Array {
val: rows
.into_iter()
.map(|value| JsValueFacade::SerdeValue {
value: Value::Object(value),
})
.collect(),
};
println!("js_value_facades: {:?}", js_value_facades);
// Run the plugin passing the array of results as a JSON object
let result = PLUGIN_RT
.js_function_invoke(None, &[], &method_name, vec![js_value_facades])
.await
.unwrap();
from quickjs_es_runtime.
I'm working on it under HiRoFa/utils#8
my_js_value_facade_result.to_serde_value(rti).await should do the trick when i'm done
from quickjs_es_runtime.
my testcases with utils:0.5.7 using from/to Value and from/to json
#[derive(Serialize)]
#[derive(Deserialize)]
#[serde(rename_all = "camelCase")]
struct User {
name: String,
last_name: String,
}
#[tokio::test]
async fn serde_tests_serialize() {
let rtb: QuickJsRuntimeBuilder = QuickJsRuntimeBuilder::new();
let rt = rtb.js_build();
// init my function
rt.js_eval(
None,
Script::new(
"test.js",
r#"
function myTest(user) {
return {
name: "proc_" + user.name,
lastName: "proc_" + user.lastName
}
}
"#,
),
)
.await.expect("script failed");
// create a user obj
let test_user_input = User {
last_name: "Anderson".to_string(),
name: "Mister".to_string(),
};
let args = vec![JsValueFacade::from_serializable(&test_user_input).expect("could not serialize to JsValueFacade")];
let res: JsValueFacade = rt
.js_function_invoke(None, &[], "myTest", args)
.await
.expect("func failed");
let rti = rt.js_get_runtime_facade_inner().upgrade().unwrap();
let json_result = res
.to_json_string(&*rti)
.await
.expect("could not serialize to json");
assert_eq!(
json_result.as_str(),
r#"{"name":"proc_Mister","lastName":"proc_Anderson"}"#
);
// serialize back to user
let user_output: User = serde_json::from_str(json_result.as_str()).unwrap();
assert_eq!(user_output.name.as_str(), "proc_Mister");
assert_eq!(user_output.last_name.as_str(), "proc_Anderson");
}
#[tokio::test]
async fn serde_tests_value() {
let rtb: QuickJsRuntimeBuilder = QuickJsRuntimeBuilder::new();
let rt = rtb.js_build();
// init my function
rt.js_eval(
None,
Script::new(
"test.js",
r#"
function myTest(user) {
return {
name: "proc_" + user.name,
lastName: "proc_" + user.lastName
}
}
"#,
),
)
.await.expect("script failed");
// create a user obj
let test_user_input = User {
last_name: "Anderson".to_string(),
name: "Mister".to_string(),
};
let input_value: serde_json::Value = serde_json::to_value(test_user_input).expect("could not to_value");
let args = vec![JsValueFacade::SerdeValue {value: input_value}];
let res: JsValueFacade = rt
.js_function_invoke(None, &[], "myTest", args)
.await
.expect("func failed");
let rti = rt.js_get_runtime_facade_inner().upgrade().unwrap();
// as value
let value_result: serde_json::Value = res
.to_serde_value(&*rti)
.await
.expect("could not serialize to json");
assert!(value_result.is_object());
// serialize back to user
let user_output: User = serde_json::from_value(value_result).unwrap();
assert_eq!(user_output.name.as_str(), "proc_Mister");
assert_eq!(user_output.last_name.as_str(), "proc_Anderson");
}
from quickjs_es_runtime.
Related Issues (20)
- Feat: function and struct to compute memory usage HOT 1
- Feat: TypedArrays HOT 1
- Panicked when running multiple promises concurrently HOT 2
- Document js_utils methods
- deprecate EsValueFacade HOT 1
- Segmentation fault: 11 & panic when using ScriptModuleLoader<QuickJsRealmAdapter> HOT 7
- fix MemoryUsage impl
- respect memory limit
- Main thread gets stuck randomly while awaiting for promise HOT 18
- thread panic occurred HOT 6
- Unexpected error logs even when the promise rejection is handled HOT 7
- Tokio Version in cargo.toml HOT 5
- Typescript support HOT 7
- fork quickjs HOT 6
- Can't get rust async code to work with promise HOT 4
- how to get the promise result HOT 2
- Incompatible with `tokio v1.40.0`. HOT 2
- `SIGSEGV: invalid memory reference` in bench. HOT 12
- Use Error.prepareStackTrace to map sourcemaps if swc is used with quickjs-ng
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from quickjs_es_runtime.