Neon: Construct a JsBuffer

Created on 6 Sep 2016  路  9Comments  路  Source: neon-bindings/neon

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??)

Most helpful comment

@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?

All 9 comments

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`

Was this page helpful?
0 / 5 - 0 ratings

Related issues

vasishath picture vasishath  路  3Comments

crazyfrozenpenguin picture crazyfrozenpenguin  路  3Comments

hardliner66 picture hardliner66  路  3Comments

chpio picture chpio  路  6Comments

manuel2258 picture manuel2258  路  5Comments