neon/types_impl/function/
mod.rs

1//! Types and traits for working with JavaScript functions.
2
3use smallvec::smallvec;
4
5use crate::{
6    context::{Context, Cx},
7    handle::Handle,
8    object::Object,
9    result::{JsResult, NeonResult},
10    types::{
11        extract::{TryFromJs, TryIntoJs},
12        private::ValueInternal,
13        JsFunction, JsObject, JsValue, Value,
14    },
15};
16
17pub(crate) mod private;
18
19/// A builder for making a JavaScript function call like `parseInt("42")`.
20///
21/// The builder methods make it convenient to assemble the call from parts:
22/// ```
23/// # use neon::prelude::*;
24/// # fn foo(mut cx: FunctionContext) -> JsResult<JsNumber> {
25/// # let parse_int: Handle<JsFunction> = cx.global("parseInt")?;
26/// let x: f64 = parse_int
27///     .bind(&mut cx)
28///     .arg("42")?
29///     .call()?;
30/// # Ok(cx.number(x))
31/// # }
32/// ```
33pub struct BindOptions<'a, 'cx: 'a> {
34    pub(crate) cx: &'a mut Cx<'cx>,
35    pub(crate) callee: Handle<'cx, JsValue>,
36    pub(crate) this: Option<Handle<'cx, JsValue>>,
37    pub(crate) args: private::ArgsVec<'cx>,
38}
39
40impl<'a, 'cx: 'a> BindOptions<'a, 'cx> {
41    /// Set the value of `this` for the function call.
42    pub fn this<T: TryIntoJs<'cx>>(&mut self, this: T) -> NeonResult<&mut Self> {
43        let v = this.try_into_js(self.cx)?;
44        self.this = Some(v.upcast());
45        Ok(self)
46    }
47
48    /// Replaces the arguments list with the given arguments.
49    pub fn args<A: TryIntoArguments<'cx>>(&mut self, a: A) -> NeonResult<&mut Self> {
50        self.args = a.try_into_args_vec(self.cx)?;
51        Ok(self)
52    }
53
54    /// Replaces the arguments list with a list computed from a closure.
55    pub fn args_with<R, F>(&mut self, f: F) -> NeonResult<&mut Self>
56    where
57        R: TryIntoArguments<'cx>,
58        F: FnOnce(&mut Cx<'cx>) -> R,
59    {
60        self.args = f(self.cx).try_into_args_vec(self.cx)?;
61        Ok(self)
62    }
63
64    /// Add an argument to the arguments list.
65    pub fn arg<A: TryIntoJs<'cx>>(&mut self, a: A) -> NeonResult<&mut Self> {
66        let v = a.try_into_js(self.cx)?;
67        self.args.push(v.upcast());
68        Ok(self)
69    }
70
71    /// Add an argument to the arguments list, computed from a closure.
72    pub fn arg_with<R, F>(&mut self, f: F) -> NeonResult<&mut Self>
73    where
74        R: TryIntoJs<'cx>,
75        F: FnOnce(&mut Cx<'cx>) -> R,
76    {
77        let v = f(self.cx).try_into_js(self.cx)?;
78        self.args.push(v.upcast());
79        Ok(self)
80    }
81
82    /// Make the function call. If the function returns without throwing, the result value
83    /// is converted to a Rust value with `TryFromJs::from_js`.
84    pub fn call<R: TryFromJs<'cx>>(&mut self) -> NeonResult<R> {
85        let this = self.this.unwrap_or_else(|| self.cx.undefined().upcast());
86        let v: Handle<JsValue> = unsafe { self.callee.try_call(self.cx, this, &self.args)? };
87        R::from_js(self.cx, v)
88    }
89
90    /// Make the function call as a constructor. If the function returns without throwing, the
91    /// result value is converted to a Rust value with `TryFromJs::from_js`.
92    pub fn construct<R: TryFromJs<'cx>>(&mut self) -> NeonResult<R> {
93        let v: Handle<JsValue> = unsafe { self.callee.try_construct(self.cx, &self.args)? };
94        R::from_js(self.cx, v)
95    }
96
97    /// Make the function call for side effect, discarding the result value. This method is
98    /// preferable to [`call()`](BindOptions::call) when the result value isn't needed,
99    /// since it doesn't require specifying a result type.
100    pub fn exec(&mut self) -> NeonResult<()> {
101        let _ignore: Handle<JsValue> = self.call()?;
102        Ok(())
103    }
104}
105
106/// A builder for making a JavaScript function call like `parseInt("42")`.
107///
108/// The builder methods make it convenient to assemble the call from parts:
109/// ```
110/// # use neon::prelude::*;
111/// # fn foo(mut cx: FunctionContext) -> JsResult<JsNumber> {
112/// # let parse_int: Handle<JsFunction> = cx.global("parseInt")?;
113/// let x: Handle<JsNumber> = parse_int
114///     .call_with(&cx)
115///     .arg(cx.string("42"))
116///     .apply(&mut cx)?;
117/// # Ok(x)
118/// # }
119/// ```
120#[deprecated(since = "TBD", note = "use `JsFunction::bind()` instead")]
121#[derive(Clone)]
122pub struct CallOptions<'a> {
123    pub(crate) callee: Handle<'a, JsFunction>,
124    pub(crate) this: Option<Handle<'a, JsValue>>,
125    pub(crate) args: private::ArgsVec<'a>,
126}
127
128impl<'a> CallOptions<'a> {
129    /// Set the value of `this` for the function call.
130    pub fn this<V: Value>(&mut self, this: Handle<'a, V>) -> &mut Self {
131        self.this = Some(this.upcast());
132        self
133    }
134
135    /// Add an argument to the arguments list.
136    pub fn arg<V: Value>(&mut self, arg: Handle<'a, V>) -> &mut Self {
137        self.args.push(arg.upcast());
138        self
139    }
140
141    /// Replaces the arguments list with the given arguments.
142    pub fn args<A: Arguments<'a>>(&mut self, args: A) -> &mut Self {
143        self.args = args.into_args_vec();
144        self
145    }
146
147    /// Make the function call. If the function returns without throwing, the result value
148    /// is downcast to the type `V`, throwing a `TypeError` if the downcast fails.
149    pub fn apply<'b: 'a, V: Value, C: Context<'b>>(&self, cx: &mut C) -> JsResult<'b, V> {
150        let this = self.this.unwrap_or_else(|| cx.undefined().upcast());
151        let v: Handle<JsValue> = self.callee.call(cx, this, &self.args)?;
152        v.downcast_or_throw(cx)
153    }
154
155    /// Make the function call for side effect, discarding the result value. This method is
156    /// preferable to [`apply()`](CallOptions::apply) when the result value isn't needed,
157    /// since it doesn't require specifying a result type.
158    pub fn exec<'b: 'a, C: Context<'b>>(&self, cx: &mut C) -> NeonResult<()> {
159        let this = self.this.unwrap_or_else(|| cx.undefined().upcast());
160        self.callee.call(cx, this, &self.args)?;
161        Ok(())
162    }
163}
164
165/// A builder for making a JavaScript constructor call like `new Array(16)`.
166///
167/// The builder methods make it convenient to assemble the call from parts:
168/// ```
169/// # use neon::prelude::*;
170/// # fn foo(mut cx: FunctionContext) -> JsResult<JsObject> {
171/// # let url: Handle<JsFunction> = cx.global("URL")?;
172/// let obj = url
173///     .construct_with(&cx)
174///     .arg(cx.string("https://neon-bindings.com"))
175///     .apply(&mut cx)?;
176/// # Ok(obj)
177/// # }
178/// ```
179#[deprecated(since = "TBD", note = "use `JsFunction::bind()` instead")]
180#[derive(Clone)]
181pub struct ConstructOptions<'a> {
182    pub(crate) callee: Handle<'a, JsFunction>,
183    pub(crate) args: private::ArgsVec<'a>,
184}
185
186impl<'a> ConstructOptions<'a> {
187    /// Add an argument to the arguments list.
188    pub fn arg<V: Value>(&mut self, arg: Handle<'a, V>) -> &mut Self {
189        self.args.push(arg.upcast());
190        self
191    }
192
193    /// Replaces the arguments list with the given arguments.
194    pub fn args<A: Arguments<'a>>(&mut self, args: A) -> &mut Self {
195        self.args = args.into_args_vec();
196        self
197    }
198
199    /// Make the constructor call. If the function returns without throwing, returns
200    /// the resulting object.
201    pub fn apply<'b: 'a, O: Object, C: Context<'b>>(&self, cx: &mut C) -> JsResult<'b, O> {
202        let v: Handle<JsObject> = self.callee.construct(cx, &self.args)?;
203        v.downcast_or_throw(cx)
204    }
205}
206
207/// The trait for specifying values to be converted into arguments for a function call.
208/// This trait is sealed and cannot be implemented by types outside of the Neon crate.
209///
210/// **Note:** This trait is implemented for tuples of up to 32 JavaScript values,
211/// but for the sake of brevity, only tuples up to size 8 are shown in this documentation.
212pub trait TryIntoArguments<'cx>: private::TryIntoArgumentsInternal<'cx> {}
213
214impl<'cx> private::TryIntoArgumentsInternal<'cx> for () {
215    fn try_into_args_vec(self, _cx: &mut Cx<'cx>) -> NeonResult<private::ArgsVec<'cx>> {
216        Ok(smallvec![])
217    }
218}
219
220impl<'cx, T, E> private::TryIntoArgumentsInternal<'cx> for Result<T, E>
221where
222    T: private::TryIntoArgumentsInternal<'cx>,
223    E: TryIntoJs<'cx>,
224{
225    fn try_into_args_vec(self, cx: &mut Cx<'cx>) -> NeonResult<private::ArgsVec<'cx>> {
226        match self {
227            Ok(v) => v.try_into_args_vec(cx),
228            Err(err) => err.try_into_js(cx).and_then(|err| cx.throw(err)),
229        }
230    }
231}
232
233impl<'cx, T, E> TryIntoArguments<'cx> for Result<T, E>
234where
235    T: TryIntoArguments<'cx>,
236    E: TryIntoJs<'cx>,
237{
238}
239
240macro_rules! impl_into_arguments_expand {
241    {
242        $(#[$attrs:meta])?
243        [ $($prefix:ident ),* ];
244        [];
245    } => {};
246
247    {
248        $(#[$attrs:meta])?
249        [ $($prefix:ident),* ];
250        [ $head:ident $(, $tail:ident)* ];
251    } => {
252        $(#[$attrs])?
253        impl<'cx, $($prefix: TryIntoJs<'cx> + 'cx, )* $head: TryIntoJs<'cx> + 'cx> private::TryIntoArgumentsInternal<'cx> for ($($prefix, )* $head, ) {
254            #[allow(non_snake_case)]
255            fn try_into_args_vec(self, cx: &mut Cx<'cx>) -> NeonResult<private::ArgsVec<'cx>> {
256                let ($($prefix, )* $head, ) = self;
257                Ok(smallvec![ $($prefix.try_into_js(cx)?.upcast(),)* $head.try_into_js(cx)?.upcast() ])
258             }
259         }
260
261         $(#[$attrs])?
262         impl<'cx, $($prefix: TryIntoJs<'cx> + 'cx, )* $head: TryIntoJs<'cx> + 'cx> TryIntoArguments<'cx> for ($($prefix, )* $head, ) {}
263
264        impl_into_arguments_expand! {
265            $(#[$attrs])?
266            [ $($prefix, )* $head ];
267            [ $($tail),* ];
268        }
269   }
270}
271
272macro_rules! impl_into_arguments {
273    {
274        [ $($show:ident),* ];
275        [ $($hide:ident),* ];
276    } => {
277        impl_into_arguments_expand! { []; [ $($show),* ]; }
278        impl_into_arguments_expand! { #[doc(hidden)] [ $($show),* ]; [ $($hide),* ]; }
279    }
280}
281
282impl_into_arguments! {
283    // Tuples up to length 8 are included in the docs.
284    [V1, V2, V3, V4, V5, V6, V7, V8];
285
286    // Tuples up to length 32 are not included in the docs.
287    [
288        V9, V10, V11, V12, V13, V14, V15, V16,
289        V17, V18, V19, V20, V21, V22, V23, V24,
290        V25, V26, V27, V28, V29, V30, V31, V32
291    ];
292}
293
294/// The trait for specifying arguments for a function call. This trait is sealed and cannot
295/// be implemented by types outside of the Neon crate.
296///
297/// **Note:** This trait is implemented for tuples of up to 32 JavaScript values,
298/// but for the sake of brevity, only tuples up to size 8 are shown in this documentation.
299pub trait Arguments<'a>: private::ArgumentsInternal<'a> {}
300
301impl<'a> private::ArgumentsInternal<'a> for () {
302    fn into_args_vec(self) -> private::ArgsVec<'a> {
303        smallvec![]
304    }
305}
306
307impl<'a> Arguments<'a> for () {}
308
309macro_rules! impl_arguments_expand {
310    {
311        $(#[$attrs:meta])?
312        [ $($prefix:ident),* ];
313        [];
314    } => {};
315
316    {
317        $(#[$attrs:meta])?
318        [ $($prefix:ident),* ];
319        [ $head:ident $(, $tail:ident)* ];
320    } => {
321        $(#[$attrs])?
322        impl<'a, $($prefix: Value, )* $head: Value> private::ArgumentsInternal<'a> for ($(Handle<'a, $prefix>, )* Handle<'a, $head>, ) {
323            #[allow(non_snake_case)]
324            fn into_args_vec(self) -> private::ArgsVec<'a> {
325                let ($($prefix, )* $head, ) = self;
326                smallvec![$($prefix.upcast(),)* $head.upcast()]
327             }
328         }
329
330         $(#[$attrs])?
331         impl<'a, $($prefix: Value, )* $head: Value> Arguments<'a> for ($(Handle<'a, $prefix>, )* Handle<'a, $head>, ) {}
332
333         impl_arguments_expand! {
334            $(#[$attrs])?
335            [ $($prefix, )* $head ];
336            [ $($tail),* ];
337         }
338    };
339}
340
341macro_rules! impl_arguments {
342    {
343        [ $($show:ident),* ];
344        [ $($hide:ident),* ];
345    } => {
346        impl_arguments_expand! { []; [ $($show),* ]; }
347        impl_arguments_expand! { #[doc(hidden)] [ $($show),* ]; [ $($hide),* ]; }
348    }
349}
350
351impl_arguments! {
352    // Tuples up to length 8 are included in the docs.
353    [V1, V2, V3, V4, V5, V6, V7, V8];
354
355    // Tuples up to length 32 are not included in the docs.
356    [
357        V9, V10, V11, V12, V13, V14, V15, V16,
358        V17, V18, V19, V20, V21, V22, V23, V24,
359        V25, V26, V27, V28, V29, V30, V31, V32
360    ];
361}