napi/js_values/
function.rs

1use std::ptr;
2
3use super::Value;
4#[cfg(feature = "napi4")]
5use crate::{
6  bindgen_runtime::JsValuesTupleIntoVec,
7  threadsafe_function::{ThreadsafeCallContext, ThreadsafeFunction},
8};
9use crate::{
10  bindgen_runtime::{FromNapiValue, ToNapiValue, TypeName, ValidateNapiValue},
11  check_pending_exception, sys, Error, JsObject, JsString, NapiRaw, NapiValue, Result, Status,
12  Unknown, ValueType,
13};
14
15#[deprecated(since = "2.17.0", note = "Please use `Function` instead")]
16pub struct JsFunction(pub(crate) Value);
17
18impl ValidateNapiValue for JsFunction {}
19
20impl TypeName for JsFunction {
21  fn type_name() -> &'static str {
22    "Function"
23  }
24
25  fn value_type() -> crate::ValueType {
26    ValueType::Function
27  }
28}
29
30/// See [Working with JavaScript Functions](https://nodejs.org/api/n-api.html#n_api_working_with_javascript_functions).
31///
32/// Example:
33/// ```
34/// use napi::{JsFunction, CallContext, JsNull, Result};
35///
36/// #[js_function(1)]
37/// pub fn call_function(ctx: CallContext) -> Result<JsNull> {
38///     let js_func = ctx.get::<JsFunction>(0)?;
39///     let js_string = ctx.env.create_string("hello".as_ref())?.into_unknown()?;
40///     js_func.call(None, &[js_string])?;
41///     Ok(ctx.env.get_null()?)
42/// }
43/// ```
44impl JsFunction {
45  /// [napi_call_function](https://nodejs.org/api/n-api.html#n_api_napi_call_function)
46  pub fn call<V>(&self, this: Option<&JsObject>, args: &[V]) -> Result<Unknown<'_>>
47  where
48    V: NapiRaw,
49  {
50    let raw_this = this
51      .map(|v| unsafe { v.raw() })
52      .or_else(|| unsafe { ToNapiValue::to_napi_value(self.0.env, ()) }.ok())
53      .ok_or_else(|| Error::new(Status::GenericFailure, "Get raw this failed".to_owned()))?;
54    let raw_args = args
55      .iter()
56      .map(|arg| unsafe { arg.raw() })
57      .collect::<Vec<sys::napi_value>>();
58    let mut return_value = ptr::null_mut();
59    check_pending_exception!(self.0.env, unsafe {
60      sys::napi_call_function(
61        self.0.env,
62        raw_this,
63        self.0.value,
64        args.len(),
65        raw_args.as_ptr(),
66        &mut return_value,
67      )
68    })?;
69
70    Ok(unsafe { Unknown::from_raw_unchecked(self.0.env, return_value) })
71  }
72
73  /// [napi_call_function](https://nodejs.org/api/n-api.html#n_api_napi_call_function)
74  /// The same with `call`, but without arguments
75  pub fn call_without_args(&self, this: Option<&JsObject>) -> Result<Unknown<'_>> {
76    let raw_this = this
77      .map(|v| unsafe { v.raw() })
78      .or_else(|| unsafe { ToNapiValue::to_napi_value(self.0.env, ()) }.ok())
79      .ok_or_else(|| Error::new(Status::GenericFailure, "Get raw this failed".to_owned()))?;
80    let mut return_value = ptr::null_mut();
81    check_pending_exception!(self.0.env, unsafe {
82      sys::napi_call_function(
83        self.0.env,
84        raw_this,
85        self.0.value,
86        0,
87        ptr::null_mut(),
88        &mut return_value,
89      )
90    })?;
91
92    Ok(unsafe { Unknown::from_raw_unchecked(self.0.env, return_value) })
93  }
94
95  /// <https://nodejs.org/api/n-api.html#n_api_napi_new_instance>
96  ///
97  /// This method is used to instantiate a new `JavaScript` value using a given `JsFunction` that represents the constructor for the object.
98  pub fn new_instance<V>(&self, args: &[V]) -> Result<JsObject>
99  where
100    V: NapiRaw,
101  {
102    let mut js_instance = ptr::null_mut();
103    let length = args.len();
104    let raw_args = args
105      .iter()
106      .map(|arg| unsafe { arg.raw() })
107      .collect::<Vec<sys::napi_value>>();
108    check_pending_exception!(self.0.env, unsafe {
109      sys::napi_new_instance(
110        self.0.env,
111        self.0.value,
112        length,
113        raw_args.as_ptr(),
114        &mut js_instance,
115      )
116    })?;
117    Ok(unsafe { JsObject::from_raw_unchecked(self.0.env, js_instance) })
118  }
119
120  /// function name
121  pub fn name(&self) -> Result<String> {
122    let mut name = ptr::null_mut();
123    check_pending_exception!(self.0.env, unsafe {
124      sys::napi_get_named_property(self.0.env, self.0.value, c"name".as_ptr().cast(), &mut name)
125    })?;
126    let name_value = unsafe { JsString::from_napi_value(self.0.env, name) }?;
127    Ok(name_value.into_utf8()?.as_str()?.to_owned())
128  }
129
130  #[cfg(feature = "napi4")]
131  pub fn create_threadsafe_function<
132    T,
133    NewArgs,
134    Return,
135    ErrorStatus,
136    F,
137    const ES: bool,
138    const Weak: bool,
139    const MaxQueueSize: usize,
140  >(
141    &self,
142    callback: F,
143  ) -> Result<ThreadsafeFunction<T, Return, NewArgs, ErrorStatus, ES, Weak, MaxQueueSize>>
144  where
145    T: 'static,
146    NewArgs: 'static + JsValuesTupleIntoVec,
147    Return: crate::bindgen_runtime::FromNapiValue,
148    F: 'static + Send + FnMut(ThreadsafeCallContext<T>) -> Result<NewArgs>,
149    ErrorStatus: AsRef<str> + From<Status>,
150  {
151    ThreadsafeFunction::<T, Return, NewArgs, ErrorStatus, ES, Weak, MaxQueueSize>::create(
152      self.0.env,
153      self.0.value,
154      callback,
155    )
156  }
157}