use std::ptr; use super::Value; use crate::bindgen_runtime::TypeName; #[cfg(feature = "napi4")] use crate::threadsafe_function::{ThreadSafeCallContext, ThreadsafeFunction}; use crate::{check_status, ValueType}; use crate::{sys, Env, Error, JsObject, JsUnknown, NapiRaw, NapiValue, Result, Status}; pub struct JsFunction(pub(crate) Value); impl TypeName for JsFunction { fn type_name() -> &'static str { "Function" } fn value_type() -> crate::ValueType { ValueType::Function } } /// See [Working with JavaScript Functions](https://nodejs.org/api/n-api.html#n_api_working_with_javascript_functions). /// /// Example: /// ``` /// use napi::{JsFunction, CallContext, JsNull, Result}; /// /// #[js_function(1)] /// pub fn call_function(ctx: CallContext) -> Result { /// let js_func = ctx.get::(0)?; /// let js_string = ctx.env.create_string("hello".as_ref())?.into_unknown()?; /// js_func.call(None, &[js_string])?; /// Ok(ctx.env.get_null()?) /// } /// ``` impl JsFunction { /// [napi_call_function](https://nodejs.org/api/n-api.html#n_api_napi_call_function) pub fn call(&self, this: Option<&JsObject>, args: &[V]) -> Result where V: NapiRaw, { let raw_this = this .map(|v| unsafe { v.raw() }) .or_else(|| { unsafe { Env::from_raw(self.0.env) } .get_undefined() .ok() .map(|u| unsafe { u.raw() }) }) .ok_or_else(|| Error::new(Status::GenericFailure, "Get raw this failed".to_owned()))?; let raw_args = args .iter() .map(|arg| unsafe { arg.raw() }) .collect::>(); let mut return_value = ptr::null_mut(); check_status!(unsafe { sys::napi_call_function( self.0.env, raw_this, self.0.value, args.len(), raw_args.as_ptr(), &mut return_value, ) })?; unsafe { JsUnknown::from_raw(self.0.env, return_value) } } /// [napi_call_function](https://nodejs.org/api/n-api.html#n_api_napi_call_function) /// The same with `call`, but without arguments pub fn call_without_args(&self, this: Option<&JsObject>) -> Result { let raw_this = this .map(|v| unsafe { v.raw() }) .or_else(|| { unsafe { Env::from_raw(self.0.env) } .get_undefined() .ok() .map(|u| unsafe { u.raw() }) }) .ok_or_else(|| Error::new(Status::GenericFailure, "Get raw this failed".to_owned()))?; let mut return_value = ptr::null_mut(); check_status!(unsafe { sys::napi_call_function( self.0.env, raw_this, self.0.value, 0, ptr::null_mut(), &mut return_value, ) })?; unsafe { JsUnknown::from_raw(self.0.env, return_value) } } /// /// /// This method is used to instantiate a new `JavaScript` value using a given `JsFunction` that represents the constructor for the object. pub fn new_instance(&self, args: &[V]) -> Result where V: NapiRaw, { let mut js_instance = ptr::null_mut(); let length = args.len(); let raw_args = args .iter() .map(|arg| unsafe { arg.raw() }) .collect::>(); check_status!(unsafe { sys::napi_new_instance( self.0.env, self.0.value, length, raw_args.as_ptr(), &mut js_instance, ) })?; Ok(unsafe { JsObject::from_raw_unchecked(self.0.env, js_instance) }) } #[cfg(feature = "napi4")] pub fn create_threadsafe_function( &self, max_queue_size: usize, callback: F, ) -> Result> where T: 'static, V: NapiRaw, F: 'static + Send + FnMut(ThreadSafeCallContext) -> Result>, ES: crate::threadsafe_function::ErrorStrategy::T, { ThreadsafeFunction::create(self.0.env, self.0.value, max_queue_size, callback) } }