How to call a JS function from Rust?
Hi,
I'd like to call a JS function from Rust but I can't seem to find an example that does so. I got this far with the examples and blog tutorials.
How can I call
add(1, 2)
from rust?11 Replies
I wasn't able to find the answer to your question in the official Deno documentation. However, based on the code snippets you've provided, I can offer some general advice.
In your JavaScript code, if you want to make the
add
function available globally, you can assign it to globalThis
:
This will make the add
function accessible as a global function, which you can then attempt to call from your Rust code.
In your Rust code, you are setting up a JsRuntime
and loading a module, but you are not showing how you are trying to call the add
function. To call a JavaScript function from Rust, you would typically use the JsRuntime
to evaluate a script that calls the function. However, the specifics of how to do this depend on the APIs provided by the Rust library you are using for JavaScript integration (which seems to be Deno's runtime in this case).
Please note that the advice provided here is not based on the Deno documentation, and you should double-check the accuracy of this advice. If you are using Deno's runtime or another library for embedding JavaScript in Rust, you should consult the documentation or community resources for that specific library to find the best way to call JavaScript functions from Rust.i am also having this issue. i wasn to use the
call_with_args
method but i'm not sure how to get a v8::Function
from my runtime (or scope, or wherever those live)Based on this I think it would look something like this (replace main with "add")
I imagine you would need to do
globalThis.add = add
GitHub
senc/src/engine.rs at a6e220d1d8a6418014b0c048513bb0d7e98c46aa · fe...
Hermetic runtime for TypeScript optimized for generating configuration files (including IaC). - fensak-io/senc
I'm trying to do the same thing and have got this working up to the point of invoking
call_with_args
.
Now the problem is with the borrow checker. That call_with_args
requires a mutable borrow of the js_runtime
. But it's already been mutably borrowed up here:
Any suggestions for how to resolve that?
Oh, and related, the docs for call_with_args
say:
The event loop must be polled seperately for this future to resolve. If the event loop is not polled, the future will never make progress.I verified that, because when I successfully invoke the function, it hangs forever, not making progress. But calling
run_event_loop
also involves a mutable borrow of js_runtime
. So it results in the same complaint from the borrow checker.If you get to know a solution let me know, i'm also looking for it
For now, I got it to build and run by enclosing the first mutable borrow within a lexical scope and having it return the
Future
from the call_with_args
. Then in a second lexical scope, do the run_event_loop
. Like this:
This does get the result I want. But I don't yet understand what's happening with scopes well enough to reason about the fact that a separate scope is used in the second block. It seems like that might be a problem, but I'm not sure what that would be. Still learning...That's certainly odd, if i find how to make it less odd i'll tell you
@Mike I haven't read all the code in the gists yet, but this issue seems to have answers https://github.com/denoland/deno_core/issues/515
seems to be the author of this discord thread and post even
Ok, it looks to me like what I did with lexical scoping is the same solution as what's in those gists. Only those are cleaner overall. The final gist has this:
The implementation of
call_with_args
is where the second mutable borrow happens: it also invokes handle_scope
. I'd pulled that apart because I thought (not yet understanding scopes), that it should be the same scope used in both places.
So I could clean mine up to look more like that, but in principle, both have these two features:
1. using lexical scopes to fix the double mutable borrow
2. invoking handle_scope()
twice
I think I want to consider that confirmation ...?I guess so 😄
Something that's still bugging me about this is memory management.
call_with_args
requires that the arguments are &[Global<Value>]
.
And in the example code, getting a global seems to involve:
1. creating a local
2. promoting it to global
But does that then mean it's not eligible for garbage collection?
In my case, this function calling would happen many times in a long-running process, where the range of possible args is unlimited. So if every invocation of the function involves creating globals that won't be garbage collected, doesn't that mean memory leak?Once these values are dropped (eg after loop iteration) then there will be no longer a global and they can be GCed