Hey,
I'm working on a service that uses ed25519 signatures. Since our services are primarily written using Node, I wanted to create a Rust binding making it easier for our Javascript engineers to take advantage of our internal crypto libraries.
I investigated the implementation of JsBuffer in neon and came up with a solution, but I don't really like it.
Across Github, I found exactly 7 projects that use JsBuffer, only of which one directly returned a buffer:
let data: Handle<JsBuffer> = try!(JsBuffer::new(scope, chunk.data.len() as u32));
for (i, v) in chunk.data.iter().enumerate() {
try!(data.set(i as u32, JsInteger::new(scope, *v as i32)));
}
Ok(data)
(from https://github.com/mhsjlw/node-voxel-worldgen/blob/e06aacaa5c8230109104285a04a04d87699aa420/native/src/lib.rs#L32-L38)
Due to internal changes, this implementation broke and required some rewiring. I came up with this implementation:
let (kp_priv, kp_pub) = crypto::ed25519::keypair(&seed);
let outobj = JsObject::new(scope);
let jsb_kp_priv: Handle<JsBuffer> = try!(JsBuffer::new(scope, kp_priv.len() as u32));
for (i, byte) in kp_priv.iter().enumerate() {
unsafe {
jsb_kp_priv.set(&mut false, JsInteger::new(scope, i as i32).to_raw(), JsInteger::new(scope, *byte as i32).to_raw());
}
}
First, <JsBuffer>.set now has a boolean flag (https://github.com/rustbridge/neon/blob/63d69b03d183f633cc952ff8ba7a83334228ba71/crates/neon-sys/src/object.rs#L30) - I honestly have no idea what out (&mut bool) does. (Which is why I put an awkward &mut false there). Second, .set seems to be unsafe now (I'm on Rust nightly, maybe because of that?)
Could you give my implementation a facelift, preferably without unsafe? In C++ I'd copy my data onto a SlowBuffer and then assign that to a V8 buffer. Can I somehow simply instantiate a JsBuffer from a sized &[0u8; 32], et al.?
Thanks in advance.
馃檹馃嵒
P.s.: How can I cleanly pass a scope to a function? I don't get the lifetime issue sorted. I built a function that returns a Handle<JsBuffer>, but I can't cleanly pass a scope by itself:
fn js_vec_to_buf (data: &[u8]) -> Handle<JsBuffer>; (meh)
fn js_vec_to_buf (call: &Call, data: &[u8]) -> Handle<JsBuffer>; (even more meh because I only want the scope)
fn js_vec_to_buf<A: Scope> (scope: A, data: &[u8]) -> Handle<JsBuffer>; (meh, what's the correct lifetime??)
Actually, it seems like I cannot compile the object test at all on nightly: https://github.com/rustbridge/neon/blob/master/tests/native/src/js/objects.rs - here's the logs:
Seems like the problem was that this import breaks everything: use neon::js::Key. Also, <Handle<JsBuffer>>.set requires use neon::js::Key to be imported... which breaks <Handle<JsObject>>.set. Looks like I can /either/ have buffers OR objects at this moment.
Can I somehow craft a custom Uint8Array? Worst case would be a simple array with ints that could be passed to Buffer. (const publicKey = new Buffer(native.publicKey()))
For now I'll go with the latter way
@KenanSulayman The API you want is the Lock trait, which is implemented by JsBuffer and allows you to get access to the internal buffer as a Rust slice. I made a small example to demonstrate how you can use the Lock::grab method to do this:
https://github.com/dherman/neon-examples/blob/master/populate-buffer/native/src/lib.rs#L10-L15
Does this help?
Wow, that is a simple, yet truly remarkable solution. It worked straightaway.
If you happen to be in Berlin, drop me a note and the beers are on me 馃嵒
Besides that, is it possible to pass a scope around? It would allow for much cleaner and DRY code.
@KenanSulayman Yes, it's definitely possible, although unfortunately it's pretty verbose. At least for now, this is what you have to do. For example, let's say you have a helper function that takes an object and wants to get a property from the object:
fn my_helper_function<'a, S: Scope<'a>>(scope: &'a mut S, obj: Handle<'a, JsObject>) -> JsResult<'a, JsValue> {
// ...
}
Thanks!
@dherman https://github.com/dherman/neon-examples/blob/master/populate-buffer/native/src/lib.rs#L10-L15
not working for 0.2? Is there any example for 0.2?
error[E0432]: unresolved import `neon::vm`
--> src/lib.rs:7:11
|
7 | use neon::vm::{Call, JsResult, Lock};
| ^^ could not find `vm` in `neon`
Most helpful comment
@KenanSulayman The API you want is the
Locktrait, which is implemented byJsBufferand allows you to get access to the internal buffer as a Rust slice. I made a small example to demonstrate how you can use theLock::grabmethod to do this:https://github.com/dherman/neon-examples/blob/master/populate-buffer/native/src/lib.rs#L10-L15
Does this help?