Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
41 commits
Select commit Hold shift + click to select a range
af90b67
Arguments builder API
dherman Sep 18, 2021
627ca9a
Arguments builder API take 2:
dherman Sep 19, 2021
4289c7d
Fix doc comment to match new draft API
dherman Sep 19, 2021
84a8259
Fix rustfmt issues and doctest where legacy/N-API incompatibly disagree
dherman Sep 19, 2021
8806054
Docs-driven development improvements:
dherman Sep 19, 2021
0bb1774
Add missing code close delimiter in doc comment
dherman Sep 19, 2021
35d75f1
Docs improvements
dherman Sep 19, 2021
ae2fc51
Doc comments for the new `JsFunction` methods.
dherman Sep 19, 2021
2b2443a
Simpler doctest fix, per @kjvalencik's review suggestion
dherman Sep 20, 2021
945e522
Arguments builder API
dherman Sep 18, 2021
211b54c
Fix rustfmt issues and doctest where legacy/N-API incompatibly disagree
dherman Sep 19, 2021
3c825e9
Rebase with main to pull in the doctest fix
dherman Sep 20, 2021
610f125
Seal the Arguments trait, as suggested in @kjvalencik's review.
dherman Oct 9, 2021
9aeb821
Arguments builders no longer require ownership and calling is immutable.
dherman Oct 9, 2021
6ab72a6
Change `do_call` and `do_construct` to private methods of `JsFunction…
dherman Oct 9, 2021
7334d8b
Fix linting errors.
dherman Oct 9, 2021
234ed2c
Track the function's class type in the `Call` and `FunctionCall` stru…
dherman Oct 10, 2021
7f68c41
API docs
dherman Oct 10, 2021
60ff331
Doctest fixes
dherman Oct 10, 2021
feddf1c
Take the generic type parameter back out of Call and FunctionCall.
dherman Oct 21, 2021
4e4b482
Rename `.new()` to `.construct()` as discussed in PR thread
dherman Oct 22, 2021
f919db9
Reverse order of type arguments to `.call()` as discussed in PR thread.
dherman Oct 22, 2021
58374b6
Rename `types::internal` to `types::private` and refer to private typ…
dherman Oct 23, 2021
9e6ba88
Rename `borrow::internal` to `borrow::private`
dherman Oct 23, 2021
48e48ef
Rename `context::internal` to `context::private`.
dherman Oct 23, 2021
94d9331
Revert "Rename `borrow::internal` to `borrow::private`"
dherman Oct 23, 2021
8f194b2
Fix tests and lints.
dherman Oct 23, 2021
ca5b738
Couple of style changes based on PR feedback
dherman Oct 23, 2021
e04c58b
Remove unnecessary `.args(())` from test case, per review
dherman Oct 24, 2021
248f4de
Experiment: does #[doc(hidden)] work for trait impls?
dherman Oct 24, 2021
a60f890
Hide the `Arguments` implementations from API docs for tuples over si…
dherman Oct 24, 2021
25ced7f
API change:
dherman Oct 24, 2021
c2acb40
Replace typestate API with more structured `.call_with() -> CallOptio…
dherman Oct 25, 2021
0378e58
WIP: adding context parameter to JsFunction::call_with
dherman Oct 26, 2021
4d42092
Both `call_with` and `construct_with` take `&cx`
dherman Oct 26, 2021
550c825
Style fixes
dherman Oct 26, 2021
7f8a32d
Move helper types to `neon::types::function` submodule.
dherman Oct 26, 2021
4453fd6
Merge branch 'main' into arguments-builder
dherman Oct 26, 2021
41e89e5
Fix doc test
dherman Oct 26, 2021
8683ef5
More unit tests!
dherman Oct 27, 2021
ca36c50
Fix lint errors
dherman Oct 27, 2021
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions crates/neon-runtime/src/napi/fun.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ pub unsafe fn call(
fun: Local,
this: Local,
argc: i32,
argv: *mut c_void,
argv: *const c_void,
) -> bool {
let status = napi::call_function(
env,
Expand All @@ -51,7 +51,7 @@ pub unsafe fn construct(
env: Env,
fun: Local,
argc: i32,
argv: *mut c_void,
argv: *const c_void,
) -> bool {
let status = napi::new_instance(env, fun, argc as usize, argv as *const _, out as *mut _);

Expand Down
4 changes: 2 additions & 2 deletions crates/neon-sys/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -206,14 +206,14 @@ extern "C" {
fun: Local,
this: Local,
argc: i32,
argv: *mut c_void,
argv: *const c_void,
) -> bool;
pub fn Neon_Fun_Construct(
out: &mut Local,
isolate: Isolate,
fun: Local,
argc: i32,
argv: *mut c_void,
argv: *const c_void,
) -> bool;

pub fn Neon_Mem_SameHandle(h1: Local, h2: Local) -> bool;
Expand Down
7 changes: 4 additions & 3 deletions src/context/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -94,9 +94,10 @@
//!
//! while !done {
//! done = cx.execute_scoped(|mut cx| { // temporary scope
//! let args: Vec<Handle<JsValue>> = vec![];
//! let obj = next.call(&mut cx, iterator, args)? // temporary object
//! .downcast_or_throw::<JsObject, _>(&mut cx)?;
//! let obj: Handle<JsObject> = next // temporary object
//! .call_with(&cx)
//! .this(iterator)
//! .apply(&mut cx)?;
//! let number = obj.get(&mut cx, "value")? // temporary number
//! .downcast_or_throw::<JsNumber, _>(&mut cx)?
//! .value(&mut cx);
Expand Down
2 changes: 1 addition & 1 deletion src/object/class/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ use crate::context::{Context, Lock};
use crate::handle::{Handle, Managed};
use crate::object::{Object, This};
use crate::result::{JsResult, NeonResult, Throw};
use crate::types::internal::{Callback, ValueInternal};
use crate::types::private::{Callback, ValueInternal};
use crate::types::{build, JsFunction, JsValue, Value};
use neon_runtime;
use neon_runtime::raw;
Expand Down
2 changes: 1 addition & 1 deletion src/types/binary.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ use crate::context::{Context, Lock};
use crate::handle::Handle;
use crate::handle::Managed;
use crate::result::JsResult;
use crate::types::internal::ValueInternal;
use crate::types::private::ValueInternal;
use crate::types::{build, Object, Value};
use neon_runtime;
use neon_runtime::raw;
Expand Down
2 changes: 1 addition & 1 deletion src/types/boxed.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ use crate::context::internal::Env;
use crate::context::{Context, FinalizeContext};
use crate::handle::{Handle, Managed};
use crate::object::Object;
use crate::types::internal::ValueInternal;
use crate::types::private::ValueInternal;
use crate::types::Value;

type BoxAny = Box<dyn Any + Send + 'static>;
Expand Down
3 changes: 2 additions & 1 deletion src/types/date.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
use super::{Value, ValueInternal};
use super::private::ValueInternal;
use super::Value;
use crate::context::internal::Env;
use crate::context::Context;
use crate::handle::{Handle, Managed};
Expand Down
2 changes: 1 addition & 1 deletion src/types/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ use neon_runtime::raw;
use crate::context::internal::Env;
use crate::context::Context;
use crate::result::{NeonResult, Throw};
use crate::types::internal::ValueInternal;
use crate::types::private::ValueInternal;
use crate::types::utf8::Utf8;
use crate::types::{build, Handle, Managed, Object, Value};

Expand Down
215 changes: 215 additions & 0 deletions src/types/function/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,215 @@
//! Types and traits for working with JavaScript functions.

use crate::context::Context;
use crate::handle::Handle;
use crate::result::{JsResult, NeonResult};
use crate::types::{JsFunction, JsObject, JsValue, Value};

pub(crate) mod private;

/// A builder for making a JavaScript function call like `parseInt("42")`.
///
/// The builder methods make it convenient to assemble the call from parts:
/// ```
/// # use neon::prelude::*;
/// # fn foo(mut cx: FunctionContext) -> JsResult<JsNumber> {
/// # let global = cx.global();
/// # let parse_int = global.get(&mut cx, "parseInt")?;
/// # let parse_int: Handle<JsFunction> = parse_int.downcast_or_throw(&mut cx)?;
/// let x: Handle<JsNumber> = parse_int
/// .call_with(&cx)
/// .arg(cx.string("42"))
/// .apply(&mut cx)?;
/// # Ok(x)
/// # }
/// ```
#[derive(Clone)]
pub struct CallOptions<'a> {
pub(crate) callee: Handle<'a, JsFunction>,
pub(crate) this: Option<Handle<'a, JsValue>>,
pub(crate) args: private::ArgsVec<'a>,
}

impl<'a> CallOptions<'a> {
/// Set the value of `this` for the function call.
pub fn this<V: Value>(&mut self, this: Handle<'a, V>) -> &mut Self {
self.this = Some(this.upcast());
self
}

/// Add an argument to the arguments list.
pub fn arg<V: Value>(&mut self, arg: Handle<'a, V>) -> &mut Self {
self.args.push(arg.upcast());
self
}

/// Add multiple arguments to the arguments list.
pub fn args<A: Arguments<'a>>(&mut self, args: A) -> &mut Self {
args.append(&mut self.args);
self
}

/// Make the function call. If the function returns without throwing, the result value
/// is downcast to the type `V`, throwing a `TypeError` if the downcast fails.
pub fn apply<'b, V: Value, C: Context<'b>>(&self, cx: &mut C) -> JsResult<'b, V> {
let this = self.this.unwrap_or_else(|| cx.null().upcast());
let v: Handle<JsValue> = self.callee.do_call(cx, this, &self.args)?;
v.downcast_or_throw(cx)
}

/// Make the function call for side effect, discarding the result value. This method is
/// preferable to [`apply()`](CallOptions::apply) when the result value isn't needed,
/// since it doesn't require specifying a result type.
pub fn exec<'b, C: Context<'b>>(&self, cx: &mut C) -> NeonResult<()> {
let this = self.this.unwrap_or_else(|| cx.null().upcast());
self.callee.do_call(cx, this, &self.args)?;
Ok(())
}
}

/// A builder for making a JavaScript constructor call like `new Array(16)`.
///
/// The builder methods make it convenient to assemble the call from parts:
/// ```
/// # use neon::prelude::*;
/// # fn foo(mut cx: FunctionContext) -> JsResult<JsObject> {
/// # let global = cx.global();
/// # let url = global.get(&mut cx, "URL")?;
/// # let url: Handle<JsFunction> = url.downcast_or_throw(&mut cx)?;
/// let obj = url
/// .construct_with(&cx)
/// .arg(cx.string("https://neon-bindings.com"))
/// .apply(&mut cx)?;
/// # Ok(obj)
/// # }
/// ```
#[derive(Clone)]
pub struct ConstructOptions<'a> {
pub(crate) callee: Handle<'a, JsFunction>,
pub(crate) args: private::ArgsVec<'a>,
}

impl<'a> ConstructOptions<'a> {
/// Add an argument to the arguments list.
pub fn arg<V: Value>(&mut self, arg: Handle<'a, V>) -> &mut Self {
self.args.push(arg.upcast());
self
}

/// Add multiple arguments to the arguments list.
pub fn args<A: Arguments<'a>>(&mut self, args: A) -> &mut Self {
args.append(&mut self.args);
self
}

/// Make the constructor call. If the function returns without throwing, returns
/// the resulting object.
pub fn apply<'b, C: Context<'b>>(&self, cx: &mut C) -> JsResult<'b, JsObject> {
self.callee.do_construct(cx, &self.args)
}
}

/// The trait for specifying arguments in a [`CallOptions`](CallOptions)
/// or [`ConstructOptions`](ConstructOptions). This trait is sealed and cannot
/// be implemented by types outside of the Neon crate.
///
/// **Note:** This trait is implemented for tuples of up to 32 JavaScript values,
/// but for the sake of brevity, only tuples up to size 8 are shown in this documentation.
pub trait Arguments<'a>: private::ArgumentsInternal<'a> {}

impl<'a> private::ArgumentsInternal<'a> for () {
fn append(self, _args: &mut private::ArgsVec<'a>) {}
}

impl<'a> Arguments<'a> for () {}

macro_rules! impl_arguments {
{
[ $(($tprefix:ident, $vprefix:ident), )* ];
[];
} => {};

{
[ $(($tprefix:ident, $vprefix:ident), )* ];
[ $(#[$attr1:meta])? ($tname1:ident, $vname1:ident), $($(#[$attrs:meta])? ($tnames:ident, $vnames:ident), )* ];
} => {
$(#[$attr1])?
impl<'a, $($tprefix: Value, )* $tname1: Value> private::ArgumentsInternal<'a> for ($(Handle<'a, $tprefix>, )* Handle<'a, $tname1>, ) {
fn append(self, args: &mut private::ArgsVec<'a>) {
let ($($vprefix, )* $vname1, ) = self;
$(args.push($vprefix.upcast());)*
args.push($vname1.upcast());
}
}

$(#[$attr1])?
impl<'a, $($tprefix: Value, )* $tname1: Value> Arguments<'a> for ($(Handle<'a, $tprefix>, )* Handle<'a, $tname1>, ) {}

impl_arguments! {
[ $(($tprefix, $vprefix), )* ($tname1, $vname1), ];
[ $($(#[$attrs])? ($tnames, $vnames), )* ];
}
};
}

impl_arguments! {
[];
[
(V1, v1),
(V2, v2),
(V3, v3),
(V4, v4),
(V5, v5),
(V6, v6),
(V7, v7),
(V8, v8),
#[doc(hidden)]
(V9, v9),
#[doc(hidden)]
(V10, v10),
#[doc(hidden)]
(V11, v11),
#[doc(hidden)]
(V12, v12),
#[doc(hidden)]
(V13, v13),
#[doc(hidden)]
(V14, v14),
#[doc(hidden)]
(V15, v15),
#[doc(hidden)]
(V16, v16),
#[doc(hidden)]
(V17, v17),
#[doc(hidden)]
(V18, v18),
#[doc(hidden)]
(V19, v19),
#[doc(hidden)]
(V20, v20),
#[doc(hidden)]
(V21, v21),
#[doc(hidden)]
(V22, v22),
#[doc(hidden)]
(V23, v23),
#[doc(hidden)]
(V24, v24),
#[doc(hidden)]
(V25, v25),
#[doc(hidden)]
(V26, v26),
#[doc(hidden)]
(V27, v27),
#[doc(hidden)]
(V28, v28),
#[doc(hidden)]
(V29, v29),
#[doc(hidden)]
(V30, v30),
#[doc(hidden)]
(V31, v31),
#[doc(hidden)]
(V32, v32),
];
}
11 changes: 11 additions & 0 deletions src/types/function/private.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
use crate::handle::Handle;
use crate::types::JsValue;

use smallvec::SmallVec;

pub type ArgsVec<'a> = SmallVec<[Handle<'a, JsValue>; 8]>;

/// This type marks the `Arguments` trait as sealed.
pub trait ArgumentsInternal<'a> {
fn append(self, args: &mut ArgsVec<'a>);
}
Loading