use smallvec::smallvec;
use crate::{
context::{Context, Cx},
handle::Handle,
object::Object,
result::{JsResult, NeonResult},
types::{
extract::{TryFromJs, TryIntoJs, With},
private::ValueInternal,
JsFunction, JsObject, JsValue, Value,
},
};
pub(crate) mod private;
pub struct BindOptions<'a, 'cx: 'a> {
pub(crate) cx: &'a mut Cx<'cx>,
pub(crate) callee: Handle<'cx, JsValue>,
pub(crate) this: Option<Handle<'cx, JsValue>>,
pub(crate) args: private::ArgsVec<'cx>,
}
impl<'a, 'cx: 'a> BindOptions<'a, 'cx> {
pub fn this<T: TryIntoJs<'cx>>(&mut self, this: T) -> NeonResult<&mut Self> {
let v = this.try_into_js(self.cx)?;
self.this = Some(v.upcast());
Ok(self)
}
pub fn args<A: TryIntoArguments<'cx>>(&mut self, a: A) -> NeonResult<&mut Self> {
self.args = a.try_into_args_vec(self.cx)?;
Ok(self)
}
pub fn args_with<R, F>(&mut self, f: F) -> NeonResult<&mut Self>
where
R: TryIntoArguments<'cx>,
F: FnOnce(&mut Cx<'cx>) -> R,
{
self.args = f(self.cx).try_into_args_vec(self.cx)?;
Ok(self)
}
pub fn arg<A: TryIntoJs<'cx>>(&mut self, a: A) -> NeonResult<&mut Self> {
let v = a.try_into_js(self.cx)?;
self.args.push(v.upcast());
Ok(self)
}
pub fn arg_with<R, F>(&mut self, f: F) -> NeonResult<&mut Self>
where
R: TryIntoJs<'cx>,
F: FnOnce(&mut Cx<'cx>) -> R,
{
let v = f(self.cx).try_into_js(self.cx)?;
self.args.push(v.upcast());
Ok(self)
}
pub fn call<R: TryFromJs<'cx>>(&mut self) -> NeonResult<R> {
let this = self.this.unwrap_or_else(|| self.cx.undefined().upcast());
let v: Handle<JsValue> = unsafe { self.callee.try_call(self.cx, this, &self.args)? };
R::from_js(self.cx, v)
}
pub fn construct<R: TryFromJs<'cx>>(&mut self) -> NeonResult<R> {
let v: Handle<JsValue> = unsafe { self.callee.try_construct(self.cx, &self.args)? };
R::from_js(self.cx, v)
}
pub fn exec(&mut self) -> NeonResult<()> {
let _ignore: Handle<JsValue> = self.call()?;
Ok(())
}
}
#[deprecated(since = "TBD", note = "use `JsFunction::bind()` instead")]
#[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> {
pub fn this<V: Value>(&mut self, this: Handle<'a, V>) -> &mut Self {
self.this = Some(this.upcast());
self
}
pub fn arg<V: Value>(&mut self, arg: Handle<'a, V>) -> &mut Self {
self.args.push(arg.upcast());
self
}
pub fn args<A: Arguments<'a>>(&mut self, args: A) -> &mut Self {
self.args = args.into_args_vec();
self
}
pub fn apply<'b: 'a, V: Value, C: Context<'b>>(&self, cx: &mut C) -> JsResult<'b, V> {
let this = self.this.unwrap_or_else(|| cx.undefined().upcast());
let v: Handle<JsValue> = self.callee.call(cx, this, &self.args)?;
v.downcast_or_throw(cx)
}
pub fn exec<'b: 'a, C: Context<'b>>(&self, cx: &mut C) -> NeonResult<()> {
let this = self.this.unwrap_or_else(|| cx.undefined().upcast());
self.callee.call(cx, this, &self.args)?;
Ok(())
}
}
#[deprecated(since = "TBD", note = "use `JsFunction::bind()` instead")]
#[derive(Clone)]
pub struct ConstructOptions<'a> {
pub(crate) callee: Handle<'a, JsFunction>,
pub(crate) args: private::ArgsVec<'a>,
}
impl<'a> ConstructOptions<'a> {
pub fn arg<V: Value>(&mut self, arg: Handle<'a, V>) -> &mut Self {
self.args.push(arg.upcast());
self
}
pub fn args<A: Arguments<'a>>(&mut self, args: A) -> &mut Self {
self.args = args.into_args_vec();
self
}
pub fn apply<'b: 'a, O: Object, C: Context<'b>>(&self, cx: &mut C) -> JsResult<'b, O> {
let v: Handle<JsObject> = self.callee.construct(cx, &self.args)?;
v.downcast_or_throw(cx)
}
}
pub trait TryIntoArguments<'cx>: private::TryIntoArgumentsInternal<'cx> {}
impl<'cx> private::TryIntoArgumentsInternal<'cx> for () {
fn try_into_args_vec(self, _cx: &mut Cx<'cx>) -> NeonResult<private::ArgsVec<'cx>> {
Ok(smallvec![])
}
}
impl<'cx, F, O> private::TryIntoArgumentsInternal<'cx> for With<F, O>
where
F: FnOnce(&mut Cx) -> O,
O: private::TryIntoArgumentsInternal<'cx>,
{
fn try_into_args_vec(self, cx: &mut Cx<'cx>) -> NeonResult<private::ArgsVec<'cx>> {
(self.0)(cx).try_into_args_vec(cx)
}
}
impl<'cx, F, O> TryIntoArguments<'cx> for With<F, O>
where
F: FnOnce(&mut Cx) -> O,
O: TryIntoArguments<'cx>,
{
}
impl<'cx, T, E> private::TryIntoArgumentsInternal<'cx> for Result<T, E>
where
T: private::TryIntoArgumentsInternal<'cx>,
E: TryIntoJs<'cx>,
{
fn try_into_args_vec(self, cx: &mut Cx<'cx>) -> NeonResult<private::ArgsVec<'cx>> {
match self {
Ok(v) => v.try_into_args_vec(cx),
Err(err) => err.try_into_js(cx).and_then(|err| cx.throw(err)),
}
}
}
impl<'cx, T, E> TryIntoArguments<'cx> for Result<T, E>
where
T: TryIntoArguments<'cx>,
E: TryIntoJs<'cx>,
{
}
macro_rules! impl_into_arguments_expand {
{
$(#[$attrs:meta])?
[ $($prefix:ident ),* ];
[];
} => {};
{
$(#[$attrs:meta])?
[ $($prefix:ident),* ];
[ $head:ident $(, $tail:ident)* ];
} => {
$(#[$attrs])?
impl<'cx, $($prefix: TryIntoJs<'cx> + 'cx, )* $head: TryIntoJs<'cx> + 'cx> private::TryIntoArgumentsInternal<'cx> for ($($prefix, )* $head, ) {
#[allow(non_snake_case)]
fn try_into_args_vec(self, cx: &mut Cx<'cx>) -> NeonResult<private::ArgsVec<'cx>> {
let ($($prefix, )* $head, ) = self;
Ok(smallvec![ $($prefix.try_into_js(cx)?.upcast(),)* $head.try_into_js(cx)?.upcast() ])
}
}
$(#[$attrs])?
impl<'cx, $($prefix: TryIntoJs<'cx> + 'cx, )* $head: TryIntoJs<'cx> + 'cx> TryIntoArguments<'cx> for ($($prefix, )* $head, ) {}
impl_into_arguments_expand! {
$(#[$attrs])?
[ $($prefix, )* $head ];
[ $($tail),* ];
}
}
}
macro_rules! impl_into_arguments {
{
[ $($show:ident),* ];
[ $($hide:ident),* ];
} => {
impl_into_arguments_expand! { []; [ $($show),* ]; }
impl_into_arguments_expand! { #[doc(hidden)] [ $($show),* ]; [ $($hide),* ]; }
}
}
impl_into_arguments! {
[V1, V2, V3, V4, V5, V6, V7, V8];
[
V9, V10, V11, V12, V13, V14, V15, V16,
V17, V18, V19, V20, V21, V22, V23, V24,
V25, V26, V27, V28, V29, V30, V31, V32
];
}
pub trait Arguments<'a>: private::ArgumentsInternal<'a> {}
impl<'a> private::ArgumentsInternal<'a> for () {
fn into_args_vec(self) -> private::ArgsVec<'a> {
smallvec![]
}
}
impl<'a> Arguments<'a> for () {}
macro_rules! impl_arguments_expand {
{
$(#[$attrs:meta])?
[ $($prefix:ident),* ];
[];
} => {};
{
$(#[$attrs:meta])?
[ $($prefix:ident),* ];
[ $head:ident $(, $tail:ident)* ];
} => {
$(#[$attrs])?
impl<'a, $($prefix: Value, )* $head: Value> private::ArgumentsInternal<'a> for ($(Handle<'a, $prefix>, )* Handle<'a, $head>, ) {
#[allow(non_snake_case)]
fn into_args_vec(self) -> private::ArgsVec<'a> {
let ($($prefix, )* $head, ) = self;
smallvec![$($prefix.upcast(),)* $head.upcast()]
}
}
$(#[$attrs])?
impl<'a, $($prefix: Value, )* $head: Value> Arguments<'a> for ($(Handle<'a, $prefix>, )* Handle<'a, $head>, ) {}
impl_arguments_expand! {
$(#[$attrs])?
[ $($prefix, )* $head ];
[ $($tail),* ];
}
};
}
macro_rules! impl_arguments {
{
[ $($show:ident),* ];
[ $($hide:ident),* ];
} => {
impl_arguments_expand! { []; [ $($show),* ]; }
impl_arguments_expand! { #[doc(hidden)] [ $($show),* ]; [ $($hide),* ]; }
}
}
impl_arguments! {
[V1, V2, V3, V4, V5, V6, V7, V8];
[
V9, V10, V11, V12, V13, V14, V15, V16,
V17, V18, V19, V20, V21, V22, V23, V24,
V25, V26, V27, V28, V29, V30, V31, V32
];
}