Hi! I'd love to be able to create some value of type Foo in Rust, return it to JavaScript as an opaque object, and then get back a reference to it. I imagine API like
struct JsBox<T: Send+Sync> { ... }
impl<T> JsBox<T> {
fn new<S: Scope<'j>>(scope: &mut S, value: T) -> Handle<'j, JsBox<T>> { ... }
}
impl<T> Deref for JsBox<T> {
type Target = T;
}
Looks like currently the only way to move a Rust value to JavaScript is to wrap it into a JsClass, but it's often not convenient. For example, JsClass always has an init method, but often it does not makes sense (or outright impossible) to give JavaScript an ability to create an instance of the type.
I am not sure that the my description of the problem makes sense, so there's a TL;DR version. I want to
1) create a value of some type T in Rust.
2) return this value to JavaScript as an opaque thing.
3) receive this opaque thing as a parameter and extract a &T from it.
You could use Box::into_raw, then cast that to usize and return it as JsNumber, then once you get the number back you cast it back to *mut T or *const T and make it a regular reference with &*. This will obviously leak unless at some point in the future you re-create the Box and drop it, but then you also must be sure that JS does not have any references to it left or you can cause use after free.
Hm, can JsNumer handle usize? It's an f64, right? The safe solution along this lines would be to have a global HashMap<u32, T> registry of T values on Rust side. However, it also will leak memory and I really want to avoid it, because my types hold onto a lot of stuff. In theory, it's possible to add some acquire/release protocol on JavaScript side, but, at this point, just hacking it via declare_types is simpler :)
You have 52 bits of precision on f64, so unless your hardware has more than 4.5 petabytes of RAM you should be fine. Alternatively you can make it a pair of two 32bit integers.
Also, instead of hashmap you could just store your stuff on Vec<T> and return the index :p.
https://github.com/GabrielCastro/neon-serde may be of interest to you
@softprops I already do use neon-sreder, however I am interested in round-tripping a Rust struct as is, without serialization, which is not applicable in my particular case.
@matklad Would you be up for writing this up as an RFC? I think it would help understand the motivation and design better.
I am unlikely to write an RFC, but this thing from NAPi is exactly what I need:
https://nodejs.org/api/n-api.html#n_api_napi_create_external
@matklad well that is cool but how do you use it from rust? napi crate seems to be year old and without any further updates
is there a simple way to call napi_create_external_arraybuffer()?