Qqwy
RustlerElixirFun
With Rustler, it became a lot easier to create well-behaving Natively-Implemented-Functions (NIFs).
However, one question which arises from time to time (here, here, here, here, …), is how to call back into Elixir code from within native code: If you pass an anonymous function to a NIF, then how can we use this function inside the NIF?
The short answer: This is not supported.
The longer answer: … But if you get ready to jump through some hoops, you can still make it work!
The gist of it: (Thanks to Erlang Forums user @robashton and GitHub user @tessi’s explanations for inspiration!)
- In native code, create a manual ‘future’ (a mutex wrapping a potentially-empty value, and a condition variable).
- Wrap this ‘future’ into a reference which can be passed back to Elixir.
- Send
{fun, params, future_ref}to a particular process (or pool of processes) which you’ve been running. - Block the native code until the future is filled. (Or a timeout is triggered)
- In the elixir GenServer, run the function, (handle errors) and once the result is obtained, call a second NIF with the result and the future_ref.
- This NIF will ‘fill’ the future with the passed result and immediately return.
- Now the original native code will continue.
Or, in a diagram:
Until now, there were a couple of projects which did this manually, but it seemed to make sense to start working on a library to abstract this pattern once and for all.
This way, we can make sure it works well (no edge cases) and as efficient as it might be, with both a single GenServer you might run, as well as a full-fledged pool.
The project can be found at https://github.com/Qqwy/elixir-rustler_elixir_fun.
Work on RustlerElixirFun is still ongoing, but feedback would already be much appreciated.
Trending in Announcing
Other Trending Topics
Categories:
Sub Categories:
Forums
Popular Tags
- #ecto
- #liveview
- #troubleshooting
- #learning-elixir
- #deployment
- #library
- #erlang
- #testing
- #genserver
- #mix
- #absinthe
- #remote-other
- #otp
- #plug
- #how-to-question
- #macros
- #postgres
- #channels
- #elixirconf
- #exunit
- #discussion
- #code-sync
- #javascript
- #podcasts
- #onsite
- #dialyzer
- #docker
- #authentication
- #umbrella
- #full-time-contract
- #podcasts-by-brainlid
- #ecto-query
- #elixir-ls
- #blog-post
- #phoenix_html
- #iex
- #graphql
- #ai
- #genstage
- #elixirconf-us
- #websockets
- #supervisor
- #advent-of-code
- #distillery
- #processes
- #api
- #forms
- #metaprogramming
- #security
- #hex











Most Liked
Qqwy
A preliminary benchmark shows that calling a NIF which calls Elixir to run a trivial function which returns through the NIF back to the original caller takes roughly 85 times longer than calling a function directly in Elixir: 9.5µs vs 0.11µs.
I’m pretty sure that this overhead, while not neglegible, can still be considered ‘good enough’ for many projects, as the overhead of 9.5µs will often be overshadowed if there is some actual work (or communication with other processes or IO) going on inside the function.
Qqwy
Version 0.3.0 has been released.
It now has been thoroughly battle-tested by using it from within ArraysRRBVector.
Usage has become slightly simpler and less error-prone; on the Rust side an enum is now returned with the various possible results of a function call:
This way, we can be sure that all edge cases are considered when you use it in your code.