Skip to content

Commit

Permalink
feat(neon): JsFunction::bind() and Object::prop() (#1056)
Browse files Browse the repository at this point in the history
Implements `JsFunction::bind()`, which creates a builder for calling a function using the `Try{From,Into}Js` traits.

```rust
let n = f.bind(&mut cx)
    .args((1, 2, 3))?
    .arg(4)?
    .arg_with(|cx| Ok(cx.number(5)))?
    .call::<f64>()?;
```

Also implements `Object::prop()`, which creates a builder for accessing object properties using the `Try{From,Into}Js` traits.

```rust
let x: f64 = obj
    .prop(&mut cx, "x")
    .get()?;

obj.prop(&mut cx, "y")
    .set(x)?;

let s: String = obj.prop(&mut cx, "toString")
    .bind()?
    .call()?;
```

Finally, it offers a shorthand convenience method `Object::method()`, which extracts an object property and binds it as a method:

```rust
let s: String = obj.method(&mut cx, "toString").call()?;
```

---------

Co-authored-by: K.J. Valencik <kjvalencik@gmail.com>
  • Loading branch information
dherman and kjvalencik authored Oct 1, 2024
1 parent d421b00 commit d7b27ef
Show file tree
Hide file tree
Showing 21 changed files with 891 additions and 278 deletions.
25 changes: 10 additions & 15 deletions crates/neon/src/context/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -45,10 +45,9 @@
//! # use neon::prelude::*;
//! fn log(cx: &mut Cx, msg: &str) -> NeonResult<()> {
//! cx.global::<JsObject>("console")?
//! .call_method_with(cx, "log")?
//! .arg(cx.string(msg))
//! .exec(cx)?;
//!
//! .method(cx, "log")?
//! .arg(msg)?
//! .exec()?;
//! Ok(())
//! }
//!
Expand Down Expand Up @@ -107,22 +106,18 @@
//! # fn iterate(mut cx: FunctionContext) -> JsResult<JsUndefined> {
//! let iterator = cx.argument::<JsObject>(0)?; // iterator object
//! let next: Handle<JsFunction> = // iterator's `next` method
//! iterator.get(&mut cx, "next")?;
//! iterator.prop(&mut cx, "next").get()?;
//! let mut numbers = vec![]; // results vector
//! let mut done = false; // loop controller
//!
//! while !done {
//! done = cx.execute_scoped(|mut cx| { // temporary scope
//! let obj: Handle<JsObject> = next // temporary object
//! .call_with(&cx)
//! .this(iterator)
//! .apply(&mut cx)?;
//! let number: Handle<JsNumber> = // temporary number
//! obj.get(&mut cx, "value")?;
//! numbers.push(number.value(&mut cx));
//! let done: Handle<JsBoolean> = // temporary boolean
//! obj.get(&mut cx, "done")?;
//! Ok(done.value(&mut cx))
//! .bind(&mut cx)
//! .this(iterator)?
//! .call()?;
//! numbers.push(obj.prop(&mut cx, "value").get()?); // temporary number
//! obj.prop(&mut cx, "done").get() // temporary boolean
//! })?;
//! }
//! # Ok(cx.undefined())
Expand Down Expand Up @@ -505,7 +500,7 @@ pub trait Context<'a>: ContextInternal<'a> {
/// # let v: Handle<JsFunction> =
/// {
/// let global = cx.global_object();
/// global.get(cx, name)
/// global.prop(cx, name).get()
/// }
/// # ?;
/// # Ok(v)
Expand Down
10 changes: 4 additions & 6 deletions crates/neon/src/event/channel.rs
Original file line number Diff line number Diff line change
Expand Up @@ -75,13 +75,11 @@ type Callback = Box<dyn FnOnce(sys::Env) + Send + 'static>;
/// // loop. This _will_ block the event loop while executing.
/// channel.send(move |mut cx| {
/// let callback = callback.into_inner(&mut cx);
/// let this = cx.undefined();
/// let args = vec![
/// cx.null().upcast::<JsValue>(),
/// cx.number(result).upcast(),
/// ];
///
/// callback.call(&mut cx, this, args)?;
/// callback
/// .bind(&mut cx)
/// .args(((), result))?
/// .exec()?;
///
/// Ok(())
/// });
Expand Down
37 changes: 17 additions & 20 deletions crates/neon/src/event/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -78,31 +78,28 @@
//! // loop. This _will_ block the event loop while executing.
//! channel.send(move |mut cx| {
//! let callback = callback.into_inner(&mut cx);
//! let this = cx.undefined();
//! let args = match result {
//!
//! match result {
//! Ok(psd) => {
//! // Extract data from the parsed file.
//! let width = cx.number(psd.width());
//! let height = cx.number(psd.height());
//!
//! // Save the data in a result object.
//! let obj = cx.empty_object();
//! obj.set(&mut cx, "width", width)?;
//! obj.set(&mut cx, "height", height)?;
//! vec![
//! cx.null().upcast::<JsValue>(),
//! obj.upcast(),
//! ]
//! let obj = cx.empty_object()
//! .prop(&mut cx, "width").set(psd.width())?
//! .prop("height").set(psd.height())?
//! .this();
//!
//! callback
//! .bind(&mut cx)
//! .args(((), obj))?
//! .exec()?;
//! }
//! Err(err) => {
//! let err = cx.string(err.to_string());
//! vec![
//! err.upcast::<JsValue>(),
//! ]
//! use neon::types::extract::Error;
//! callback
//! .bind(&mut cx)
//! .arg(Error::from(err))?
//! .exec()?;
//! }
//! };
//!
//! callback.call(&mut cx, this, args)?;
//! }
//!
//! Ok(())
//! });
Expand Down
22 changes: 9 additions & 13 deletions crates/neon/src/handle/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,22 +27,18 @@
//!
//! ## Example
//!
//! This Neon function takes an object as its argument, extracts two properties,
//! `width` and `height`, and multiplies them together as numbers. Each JavaScript
//! value in the calculation is stored locally in a `Handle`.
//! This Neon function takes an object as its argument, extracts an object property,
//! `homeAddress`, and then extracts a string property, `zipCode` from that second
//! object. Each JavaScript value in the calculation is stored locally in a `Handle`.
//!
//! ```
//! # use neon::prelude::*;
//! fn area(mut cx: FunctionContext) -> JsResult<JsNumber> {
//! let rect: Handle<JsObject> = cx.argument(0)?;
//!
//! let width: Handle<JsNumber> = rect.get(&mut cx, "width")?;
//! let w: f64 = width.value(&mut cx);
//!
//! let height: Handle<JsNumber> = rect.get(&mut cx, "height")?;
//! let h: f64 = height.value(&mut cx);
//!
//! Ok(cx.number(w * h))
//! # use neon::export;
//! #[export]
//! fn customer_zip_code<'cx>(cx: &mut FunctionContext<'cx>, customer: Handle<'cx, JsObject>) -> JsResult<'cx, JsString> {
//! let home_address: Handle<JsObject> = customer.prop(cx, "homeAddress").get()?;
//! let zip_code: Handle<JsString> = home_address.prop(cx, "zipCode").get()?;
//! Ok(zip_code)
//! }
//! ```
Expand Down
Loading

0 comments on commit d7b27ef

Please sign in to comment.