Closed cutsoy closed 1 year ago
@cutsoy Thanks for this contribution! This seems like an interesting idea.
Can you help me understand the use case a bit better? Are these Object
using napi_wrap
or similar? What is guaranteeing they are ABI compatible?
My hope is that there might be a higher level design that is possible that doesn't need to expose type tags directly, but rather as an implementation detail.
Of course!
My use case is basically this:
import { foo } from 'foo';
import { bar } from 'bar';
const ptr = foo();
bar(ptr);
In this case, foo
and bar
are different NAPI modules (not even necessarily Rust) that can safely operate on the same native value (assuming the type tag is correct and that ptr
is ABI-safe and/or has an ABI-safe interface).
The ptr
here can indeed be a wrap, an external or even just a tagged & sealed { ptr: ... }
, doesn't really matter.
A concrete example of why this may be useful is something like numpy
, a C library for Python where N-dimensional arrays are stored "in C" with an interface in Python but which also allows other 3rd-party C libraries to directly manipulate the data "in C". Rewritten in JS, this would be similar to the following:
import { randn } from 'numpy';
import { pinv } from 'linalg';
const a = randn(9, 6);
const B = pinv(a);
Note that type tagging alone is not an unsafe
operation. It's essentially just a way to tag an object with a 128-bit number in a way that it cannot be changed/removed. I think you could even tag an object that originated from the JS-side, etc.
In order to get the entire thing working, some sort of JsUnsafeCell
would also be necessary (where JsBox
is essentially JsUnsafeCell
+ type tagging).
@cutsoy Thanks for sharing more details on your interesting use case!
@dherman and I discussed this on a call this morning. Our concern is that this is a lower level feature that doesn't seem to fit with the rest of Neon (predominantly high-level, safe features). While this feature is safe by itself, most usages of it would require unsafe elsewhere to accomplish a goal.
A different idea we had is to expose a new feature in Neon called sys
. When this feature flag is enabled, Neon will provide:
Context::to_raw
for getting a napi_env
Throw::new
, an unsafe
function for creating a Throw
sigilManaged::to_raw
and Managed::from_raw
for getting napi_value
and creating JsValue
from them (this is already public, but we had plans to make it private prior to 1.0)neon::sys
(e.g., napi_type_tag_object
)This feature would allow building extensions to Neon out-of-tree.
What do you think about this? Is this something that would sufficiently solve your use case? Thanks for your feedback!
Yes, that would be very helpful!
It would indeed solve my particular use case and it's probably also very useful for others.
Let me know if I can help out!
https://github.com/neon-bindings/neon/pull/970 provides a workaround.
This PR implements type tagging for arbitrary
Object
s. My use case for this is that I have two Node modules written in Rust that share an ABI-safeJsObject
-like value. Instead of usingTypeId<T>
(which is not equal across builds), I generate au128
for each ABI version and tag ABI-safe objects with this number.Example code: