-
Notifications
You must be signed in to change notification settings - Fork 285
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Refined .call()
and .construct()
API
#817
Conversation
…elpers, respectively.
…f `IntoIterator`.
…sult is ignored.
f.call(&mut cx, null, args)? | ||
.downcast::<JsNumber, _>(&mut cx) | ||
.or_throw(&mut cx) | ||
f.call::<JsNumber, _, _, _>(&mut cx, null, [arg]) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
f.call::<JsNumber, _, _, _>(&mut cx, null, [arg]) | |
f.call(&mut cx, null, [arg]) |
.call(&mut cx, o.upcast::<JsValue>(), args)? | ||
.downcast::<JsNumber, _>(&mut cx) | ||
.or_throw(&mut cx) | ||
get_utc_full_year_method.call::<JsNumber, _, _, _>(&mut cx, o, ()) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
get_utc_full_year_method.call::<JsNumber, _, _, _>(&mut cx, o, ()) | |
get_utc_full_year_method.call(&mut cx, o, ()) |
f.call(&mut cx, null, args)? | ||
.downcast::<JsNumber>() | ||
.or_throw(&mut cx) | ||
f.call::<JsNumber, _, _, _>(&mut cx, null, [arg]) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
f.call::<JsNumber, _, _, _>(&mut cx, null, [arg]) | |
f.call(&mut cx, null, [arg]) |
.call(&mut cx, o.upcast::<JsValue>(), args)? | ||
.downcast::<JsNumber>() | ||
.or_throw(&mut cx) | ||
get_utc_full_year_method.call::<JsNumber, _, _, _>(&mut cx, o, ()) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
get_utc_full_year_method.call::<JsNumber, _, _, _>(&mut cx, o, ()) | |
get_utc_full_year_method.call(&mut cx, o, ()) |
let mut args = smallvec![]; | ||
for arg in self { | ||
args.push(arg.upcast()); | ||
} | ||
args |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Rust is sometimes able to optimize iterators a little better. SmallVec
implements from_iter
, so it can be used with collect
.
let mut args = smallvec![]; | |
for arg in self { | |
args.push(arg.upcast()); | |
} | |
args | |
self.into_iter().map(|v| v.upcast()).collect() |
let mut args = smallvec![]; | ||
for arg in self { | ||
args.push(arg.upcast()); | ||
} | ||
args |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
let mut args = smallvec![]; | |
for arg in self { | |
args.push(arg.upcast()); | |
} | |
args | |
self.iter().map(|v| v.upcast()).collect() |
|
||
impl<'a, T: Value> Arguments<'a> for Vec<Handle<'a, T>> {} | ||
|
||
impl<'a, T: Value, const N: usize> private::ArgumentsInternal<'a> for [Handle<'a, T>; N] { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
const
generics will require a fairly recent version of Rust (1.51, released in March). Given that we're copying anyway, maybe this only needs to be implemented over slices?
I think this and Vec
could be deleted and only leave an implementation for &[Handle<'a, T>]
.
@dherman One thing that doesn't feel super great about this is that we're always copying all of the elements, even though for slices, we could be using it directly without allocations. |
$(#[$attr1])? | ||
impl<'a, $($tprefix: Value, )* $tname1: Value> private::ArgumentsInternal<'a> for ($(Handle<'a, $tprefix>, )* Handle<'a, $tname1>, ) { | ||
fn into_args_vec(self) -> private::ArgsVec<'a> { | ||
let mut args = smallvec![]; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this would result in better performance if the items were expanded in the smallvec
macro instead of pushing one by one.
I chatted with @kjvalencik and it seems like So a conservative plan for now is:
We can explore a lower-level, zero-copy primitive that takes a reference to an array of values and passes that directly to N-API, and we can decide later if we want to call that |
This PR experiments with a refined
.call()
and.construct()
API forJsFunction
, based on the ideas we came up with in #796 as well as the idea of overloading result types to make downcasting more concise and ergonomic. The changes include:Arguments
trait instead ofIntoIterator
, which still works forVec
and arrays but also heterogeneous tuples.exec()
method for discarding the result when it's not neededThis generally leads to more concise and readable code. But it has a few downsides:
[]
) tend to lead to inference errors where empty tuples (()
) usually work, could both be confusing especially to newer Rust programmers.cx
, whereas the method chaining approach in Arguments builder API #796 circumvents this issue._
) to be passed after the result type.JsValue
, may not be able to be made zero cost. (But this is probably most often needed for discarding the result, in which case.exec()
avoids the downcast overhead.)I wanted to implement this before we finalize the builder APIs, so that we can consider the complete set of function call APIs holistically.