neon/context/
mod.rs

1//! Provides runtime access to the JavaScript engine.
2//!
3//! An _execution context_ represents the current state of a thread of execution in the
4//! JavaScript engine. Internally, it tracks things like the set of pending function calls,
5//! whether the engine is currently throwing an exception or not, and whether the engine is
6//! in the process of shutting down. The context uses this internal state to manage what
7//! operations are safely available and when.
8//!
9//! The [`Context`] trait provides an abstract interface to the JavaScript
10//! execution context. All interaction with the JavaScript engine in Neon code is mediated
11//! through instances of this trait.
12//!
13//! One particularly useful context type is [`FunctionContext`], which is passed
14//! to all Neon functions as their initial execution context.
15//!
16//! ```
17//! # use neon::prelude::*;
18//! fn hello(mut cx: FunctionContext) -> JsResult<JsString> {
19//!     Ok(cx.string("hello Neon"))
20//! }
21//! ```
22//!
23//! Another important context type is [`ModuleContext`], which is provided
24//! to a Neon module's [`main`](crate::main) function to enable sharing Neon functions back
25//! with JavaScript:
26//!
27//! ```
28//! # use neon::prelude::*;
29//! # fn hello(_: FunctionContext) -> JsResult<JsValue> { todo!() }
30//! #[neon::main]
31//! fn lib(mut cx: ModuleContext) -> NeonResult<()> {
32//!     cx.export_function("hello", hello)?;
33//!     Ok(())
34//! }
35//! ```
36//!
37//! ## Writing Generic Helpers
38//!
39//! Depending on the entrypoint, a user may have a [`FunctionContext`], [`ModuleContext`], or
40//! generic [`Cx`]. While it is possible to write a helper that is generic over the [`Context`]
41//! trait, it is often simpler to accept a [`Cx`] argument. Due to deref coercion, other contexts
42//! may be passed into a function that accepts a reference to [`Cx`].
43//!
44//! ```
45//! # use neon::prelude::*;
46//! fn log(cx: &mut Cx, msg: &str) -> NeonResult<()> {
47//!     cx.global::<JsObject>("console")?
48//!         .method(cx, "log")?
49//!         .arg(msg)?
50//!         .exec()?;
51//!     Ok(())
52//! }
53//!
54//! fn print(mut cx: FunctionContext) -> JsResult<JsUndefined> {
55//!     let msg = cx.argument::<JsString>(0)?.value(&mut cx);
56//!     log(&mut cx, &msg)?;
57//!     Ok(cx.undefined())
58//! }
59//! ```
60//!
61//! ## Memory Management
62//!
63//! Because contexts represent the engine at a point in time, they are associated with a
64//! [_lifetime_][lifetime], which limits how long Rust code is allowed to access them. This
65//! is also used to determine the lifetime of [`Handle`]s, which
66//! provide safe references to JavaScript memory managed by the engine's garbage collector.
67//!
68//! For example, we can
69//! write a simple string scanner that counts whitespace in a JavaScript string and
70//! returns a [`JsNumber`]:
71//!
72//! ```
73//! # use neon::prelude::*;
74//! fn count_whitespace(mut cx: FunctionContext) -> JsResult<JsNumber> {
75//!     let s: Handle<JsString> = cx.argument(0)?;
76//!     let contents = s.value(&mut cx);
77//!     let count = contents
78//!         .chars()                       // iterate over the characters
79//!         .filter(|c| c.is_whitespace()) // select the whitespace chars
80//!         .count();                      // count the resulting chars
81//!     Ok(cx.number(count as f64))
82//! }
83//! ```
84//!
85//! In this example, `s` is assigned a handle to a string, which ensures that the string
86//! is _kept alive_ (i.e., prevented from having its storage reclaimed by the JavaScript
87//! engine's garbage collector) for the duration of the `count_whitespace` function. This
88//! is how Neon takes advantage of Rust's type system to allow your Rust code to safely
89//! interact with JavaScript values.
90//!
91//! ### Temporary Scopes
92//!
93//! Sometimes it can be useful to limit the scope of a handle's lifetime, to allow the
94//! engine to reclaim memory sooner. This can be important when, for example, an expensive inner loop generates
95//! temporary JavaScript values that are only needed inside the loop. In these cases,
96//! the [`execute_scoped`](Context::execute_scoped) and [`compute_scoped`](Context::compute_scoped)
97//! methods allow you to create temporary contexts in order to allocate temporary
98//! handles.
99//!
100//! For example, to extract the elements of a JavaScript [iterator][iterator] from Rust,
101//! a Neon function has to work with several temporary handles on each pass through
102//! the loop:
103//!
104//! ```
105//! # use neon::prelude::*;
106//! # fn iterate(mut cx: FunctionContext) -> JsResult<JsUndefined> {
107//!     let iterator = cx.argument::<JsObject>(0)?;         // iterator object
108//!     let next: Handle<JsFunction> =                      // iterator's `next` method
109//!         iterator.prop(&mut cx, "next").get()?;
110//!     let mut numbers = vec![];                           // results vector
111//!     let mut done = false;                               // loop controller
112//!
113//!     while !done {
114//!         done = cx.execute_scoped(|mut cx| {                   // temporary scope
115//!             let obj: Handle<JsObject> = next                  // temporary object
116//!                 .bind(&mut cx)
117//!                 .this(iterator)?
118//!                 .call()?;
119//!             let num: Handle<JsNumber> =                       // temporary number
120//!                 obj.prop(&mut cx, "value").get()?;
121//!             numbers.push(num);
122//!             obj.prop(&mut cx, "done").get()                   // temporary boolean
123//!         })?;
124//!     }
125//! #   Ok(cx.undefined())
126//! # }
127//! ```
128//!
129//! The temporary scope ensures that the temporary values are only kept alive
130//! during a single pass through the loop, since the temporary context is
131//! discarded (and all of its handles released) on the inside of the loop.
132//!
133//! ## Throwing Exceptions
134//!
135//! When a Neon API causes a JavaScript exception to be thrown, it returns an
136//! [`Err`] result, indicating that the thread associated
137//! with the context is now throwing. This allows Rust code to perform any
138//! cleanup before returning, but with an important restriction:
139//!
140//! > **While a JavaScript thread is throwing, its context cannot be used.**
141//!
142//! Unless otherwise documented, any Neon API that uses a context (as `self` or as
143//! a parameter) immediately panics if called while the context's thread is throwing.
144//!
145//! Typically, Neon code can manage JavaScript exceptions correctly and conveniently
146//! by using Rust's [question mark (`?`)][question-mark] operator. This ensures that
147//! Rust code "short-circuits" when an exception is thrown and returns back to
148//! JavaScript without calling any throwing APIs.
149//!
150//! Alternatively, to invoke a Neon API and catch any JavaScript exceptions, use the
151//! [`Context::try_catch`] method, which catches any thrown
152//! exception and restores the context to non-throwing state.
153//!
154//! ## See also
155//!
156//! 1. Ecma International. [Execution contexts](https://tc39.es/ecma262/#sec-execution-contexts), _ECMAScript Language Specification_.
157//! 2. Madhavan Nagarajan. [What is the Execution Context and Stack in JavaScript?](https://medium.com/@itIsMadhavan/what-is-the-execution-context-stack-in-javascript-e169812e851a)
158//! 3. Rupesh Mishra. [Execution context, Scope chain and JavaScript internals](https://medium.com/@happymishra66/execution-context-in-javascript-319dd72e8e2c).
159//!
160//! [lifetime]: https://doc.rust-lang.org/book/ch10-00-generics.html
161//! [iterator]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Iterators_and_Generators
162//! [question-mark]: https://doc.rust-lang.org/edition-guide/rust-2018/error-handling-and-panics/the-question-mark-operator-for-easier-error-handling.html
163
164pub(crate) mod internal;
165
166use std::{
167    convert::Into,
168    marker::PhantomData,
169    ops::{Deref, DerefMut},
170    panic::UnwindSafe,
171};
172
173pub use crate::types::buffer::lock::Lock;
174
175use crate::{
176    event::TaskBuilder,
177    handle::Handle,
178    object::Object,
179    result::{JsResult, NeonResult, Throw},
180    sys::{
181        self, raw,
182        scope::{EscapableHandleScope, HandleScope},
183    },
184    types::{
185        Deferred, JsArray, JsArrayBuffer, JsBoolean, JsBuffer, JsFunction, JsNull, JsNumber,
186        JsObject, JsPromise, JsString, JsUndefined, JsValue, StringResult, Value,
187        boxed::{Finalize, JsBox},
188        error::JsError,
189        extract::{FromArgs, TryFromJs},
190        private::ValueInternal,
191    },
192};
193
194use self::internal::{ContextInternal, Env};
195
196#[cfg(feature = "napi-4")]
197use crate::event::Channel;
198
199#[cfg(feature = "napi-5")]
200use crate::types::date::{DateError, JsDate};
201
202#[cfg(feature = "napi-6")]
203use crate::lifecycle::InstanceData;
204
205#[doc(hidden)]
206/// An execution context of a task completion callback.
207pub type TaskContext<'cx> = Cx<'cx>;
208
209#[doc(hidden)]
210/// An execution context of a scope created by [`Context::execute_scoped()`](Context::execute_scoped).
211pub type ExecuteContext<'cx> = Cx<'cx>;
212
213#[doc(hidden)]
214/// An execution context of a scope created by [`Context::compute_scoped()`](Context::compute_scoped).
215pub type ComputeContext<'cx> = Cx<'cx>;
216
217#[doc(hidden)]
218/// A view of the JS engine in the context of a finalize method on garbage collection
219pub type FinalizeContext<'cx> = Cx<'cx>;
220
221/// An execution context constructed from a raw [`Env`](crate::sys::bindings::Env).
222#[cfg(feature = "sys")]
223#[cfg_attr(docsrs, doc(cfg(feature = "sys")))]
224#[doc(hidden)]
225pub type SysContext<'cx> = Cx<'cx>;
226
227/// Context representing access to the JavaScript runtime
228pub struct Cx<'cx> {
229    env: Env,
230    _phantom_inner: PhantomData<&'cx ()>,
231}
232
233impl<'cx> Cx<'cx> {
234    /// Creates a context from a raw `Env`.
235    ///
236    /// # Safety
237    ///
238    /// Once a [`Cx`] has been created, it is unsafe to use
239    /// the `Env`. The handle scope for the `Env` must be valid for
240    /// the lifetime `'cx`.
241    #[cfg(feature = "sys")]
242    #[cfg_attr(docsrs, doc(cfg(feature = "sys")))]
243    pub unsafe fn from_raw(env: sys::Env) -> Self {
244        unsafe {
245            Self {
246                env: env.into(),
247                _phantom_inner: PhantomData,
248            }
249        }
250    }
251
252    fn new(env: Env) -> Self {
253        Self {
254            env,
255            _phantom_inner: PhantomData,
256        }
257    }
258
259    pub(crate) fn with_context<T, F: for<'b> FnOnce(Cx<'b>) -> T>(env: Env, f: F) -> T {
260        f(Self {
261            env,
262            _phantom_inner: PhantomData,
263        })
264    }
265}
266
267impl<'cx> ContextInternal<'cx> for Cx<'cx> {
268    fn cx(&self) -> &Cx<'cx> {
269        self
270    }
271
272    fn cx_mut(&mut self) -> &mut Cx<'cx> {
273        self
274    }
275}
276
277impl<'cx> Context<'cx> for Cx<'cx> {}
278
279impl<'cx> From<FunctionContext<'cx>> for Cx<'cx> {
280    fn from(cx: FunctionContext<'cx>) -> Self {
281        cx.cx
282    }
283}
284
285impl<'cx> From<ModuleContext<'cx>> for Cx<'cx> {
286    fn from(cx: ModuleContext<'cx>) -> Self {
287        cx.cx
288    }
289}
290
291#[repr(C)]
292pub(crate) struct CallbackInfo<'cx> {
293    info: raw::FunctionCallbackInfo,
294    _lifetime: PhantomData<&'cx raw::FunctionCallbackInfo>,
295}
296
297impl CallbackInfo<'_> {
298    pub unsafe fn new(info: raw::FunctionCallbackInfo) -> Self {
299        Self {
300            info,
301            _lifetime: PhantomData,
302        }
303    }
304
305    fn kind<'b, C: Context<'b>>(&self, cx: &C) -> CallKind {
306        if unsafe { sys::call::is_construct(cx.env().to_raw(), self.info) } {
307            CallKind::Construct
308        } else {
309            CallKind::Call
310        }
311    }
312
313    pub fn len<'b, C: Context<'b>>(&self, cx: &C) -> usize {
314        unsafe { sys::call::len(cx.env().to_raw(), self.info) }
315    }
316
317    pub fn argv<'b, C: Context<'b>>(&self, cx: &mut C) -> sys::call::Arguments {
318        unsafe { sys::call::argv(cx.env().to_raw(), self.info) }
319    }
320
321    pub fn this<'b, C: Context<'b>>(&self, cx: &mut C) -> raw::Local {
322        let env = cx.env();
323        unsafe {
324            let mut local: raw::Local = std::mem::zeroed();
325            sys::call::this(env.to_raw(), self.info, &mut local);
326            local
327        }
328    }
329
330    pub(crate) fn argv_exact<'b, C: Context<'b>, const N: usize>(
331        &self,
332        cx: &mut C,
333    ) -> [Handle<'b, JsValue>; N] {
334        use std::ptr;
335
336        let mut argv = [JsValue::new_internal(ptr::null_mut()); N];
337        let mut argc = argv.len();
338
339        // # Safety
340        // * Node-API fills empty slots with `undefined`
341        // * `Handle` and `JsValue` are transparent wrappers around a raw pointer
342        unsafe {
343            sys::get_cb_info(
344                cx.env().to_raw(),
345                self.info,
346                &mut argc,
347                argv.as_mut_ptr().cast(),
348                ptr::null_mut(),
349                ptr::null_mut(),
350            )
351            .unwrap();
352        }
353
354        // Empty values will be filled with `undefined`
355        argv
356    }
357}
358
359/// Indicates whether a function was called with `new`.
360#[derive(Clone, Copy, Debug)]
361pub enum CallKind {
362    Construct,
363    Call,
364}
365
366/// An _execution context_, which represents the current state of a thread of execution in the JavaScript engine.
367///
368/// All interaction with the JavaScript engine in Neon code is mediated through instances of this trait.
369///
370/// A context has a lifetime `'a`, which ensures the safety of handles managed by the JS garbage collector. All handles created during the lifetime of a context are kept alive for that duration and cannot outlive the context.
371pub trait Context<'a>: ContextInternal<'a> {
372    /// Lock the JavaScript engine, returning an RAII guard that keeps the lock active as long as the guard is alive.
373    ///
374    /// If this is not the currently active context (for example, if it was used to spawn a scoped context with `execute_scoped` or `compute_scoped`), this method will panic.
375    fn lock<'b>(&'b mut self) -> Lock<'b, Self>
376    where
377        'a: 'b,
378    {
379        Lock::new(self)
380    }
381
382    /// Executes a computation in a new memory management scope.
383    ///
384    /// Handles created in the new scope are kept alive only for the duration of the computation and cannot escape.
385    ///
386    /// This method can be useful for limiting the life of temporary values created during long-running computations, to prevent leaks.
387    fn execute_scoped<'b, T, F>(&mut self, f: F) -> T
388    where
389        'a: 'b,
390        F: FnOnce(Cx<'b>) -> T,
391    {
392        let env = self.env();
393        let scope = unsafe { HandleScope::new(env.to_raw()) };
394        let result = f(Cx::new(env));
395
396        drop(scope);
397
398        result
399    }
400
401    /// Executes a computation in a new memory management scope and computes a single result value that outlives the computation.
402    ///
403    /// Handles created in the new scope are kept alive only for the duration of the computation and cannot escape, with the exception of the result value, which is rooted in the outer context.
404    ///
405    /// This method can be useful for limiting the life of temporary values created during long-running computations, to prevent leaks.
406    fn compute_scoped<'b, V, F>(&mut self, f: F) -> JsResult<'a, V>
407    where
408        'a: 'b,
409        V: Value,
410        F: FnOnce(Cx<'b>) -> JsResult<'b, V>,
411    {
412        let env = self.env();
413        let scope = unsafe { EscapableHandleScope::new(env.to_raw()) };
414        let cx = Cx::new(env);
415
416        let escapee = unsafe { scope.escape(f(cx)?.to_local()) };
417
418        Ok(unsafe { Handle::new_internal(V::from_local(self.env(), escapee)) })
419    }
420
421    fn try_catch<T, F>(&mut self, f: F) -> Result<T, Handle<'a, JsValue>>
422    where
423        F: FnOnce(&mut Self) -> NeonResult<T>,
424    {
425        unsafe {
426            self.env()
427                .try_catch(move || f(self))
428                .map_err(JsValue::new_internal)
429        }
430    }
431
432    /// Convenience method for creating a `JsBoolean` value.
433    fn boolean(&mut self, b: bool) -> Handle<'a, JsBoolean> {
434        JsBoolean::new(self, b)
435    }
436
437    /// Convenience method for creating a `JsNumber` value.
438    fn number<T: Into<f64>>(&mut self, x: T) -> Handle<'a, JsNumber> {
439        JsNumber::new(self, x.into())
440    }
441
442    /// Convenience method for creating a `JsString` value.
443    ///
444    /// If the string exceeds the limits of the JS engine, this method panics.
445    fn string<S: AsRef<str>>(&mut self, s: S) -> Handle<'a, JsString> {
446        JsString::new(self, s)
447    }
448
449    /// Convenience method for creating a `JsString` value.
450    ///
451    /// If the string exceeds the limits of the JS engine, this method returns an `Err` value.
452    fn try_string<S: AsRef<str>>(&mut self, s: S) -> StringResult<'a> {
453        JsString::try_new(self, s)
454    }
455
456    /// Convenience method for creating a `JsNull` value.
457    fn null(&mut self) -> Handle<'a, JsNull> {
458        JsNull::new(self)
459    }
460
461    /// Convenience method for creating a `JsUndefined` value.
462    fn undefined(&mut self) -> Handle<'a, JsUndefined> {
463        JsUndefined::new(self)
464    }
465
466    /// Convenience method for creating an empty `JsObject` value.
467    fn empty_object(&mut self) -> Handle<'a, JsObject> {
468        JsObject::new(self)
469    }
470
471    /// Convenience method for creating an empty `JsArray` value.
472    fn empty_array(&mut self) -> Handle<'a, JsArray> {
473        JsArray::new(self, 0)
474    }
475
476    /// Convenience method for creating an empty `JsArrayBuffer` value.
477    fn array_buffer(&mut self, size: usize) -> JsResult<'a, JsArrayBuffer> {
478        JsArrayBuffer::new(self, size)
479    }
480
481    /// Convenience method for creating an empty `JsBuffer` value.
482    fn buffer(&mut self, size: usize) -> JsResult<'a, JsBuffer> {
483        JsBuffer::new(self, size)
484    }
485    /// Convenience method for creating a `JsDate` value.
486    #[cfg(feature = "napi-5")]
487    #[cfg_attr(docsrs, doc(cfg(feature = "napi-5")))]
488    fn date(&mut self, value: impl Into<f64>) -> Result<Handle<'a, JsDate>, DateError> {
489        JsDate::new(self, value)
490    }
491
492    /// Convenience method for looking up a global property by name.
493    ///
494    /// Equivalent to:
495    ///
496    /// ```
497    /// # use neon::prelude::*;
498    /// # fn get_array_global<'cx>(cx: &mut Cx<'cx>) -> JsResult<'cx, JsFunction> {
499    /// #     let name = "Array";
500    /// #     let v: Handle<JsFunction> =
501    /// {
502    ///     let global = cx.global_object();
503    ///     global.prop(cx, name).get()
504    /// }
505    /// #     ?;
506    /// #     Ok(v)
507    /// # }
508    /// ```
509    fn global<T: Value>(&mut self, name: &str) -> JsResult<'a, T> {
510        let global = self.global_object();
511        global.get(self, name)
512    }
513
514    /// Produces a handle to the JavaScript global object.
515    fn global_object(&mut self) -> Handle<'a, JsObject> {
516        JsObject::build(|out| unsafe {
517            sys::scope::get_global(self.env().to_raw(), out);
518        })
519    }
520
521    /// Throws a JS value.
522    fn throw<T: Value, U>(&mut self, v: Handle<T>) -> NeonResult<U> {
523        unsafe {
524            sys::error::throw(self.env().to_raw(), v.to_local());
525            Err(Throw::new())
526        }
527    }
528
529    /// Creates a direct instance of the [`Error`](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Error) class.
530    fn error<S: AsRef<str>>(&mut self, msg: S) -> JsResult<'a, JsError> {
531        JsError::error(self, msg)
532    }
533
534    /// Creates an instance of the [`TypeError`](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/TypeError) class.
535    fn type_error<S: AsRef<str>>(&mut self, msg: S) -> JsResult<'a, JsError> {
536        JsError::type_error(self, msg)
537    }
538
539    /// Creates an instance of the [`RangeError`](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/RangeError) class.
540    fn range_error<S: AsRef<str>>(&mut self, msg: S) -> JsResult<'a, JsError> {
541        JsError::range_error(self, msg)
542    }
543
544    /// Throws a direct instance of the [`Error`](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Error) class.
545    fn throw_error<S: AsRef<str>, T>(&mut self, msg: S) -> NeonResult<T> {
546        let err = JsError::error(self, msg)?;
547        self.throw(err)
548    }
549
550    /// Throws an instance of the [`TypeError`](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/TypeError) class.
551    fn throw_type_error<S: AsRef<str>, T>(&mut self, msg: S) -> NeonResult<T> {
552        let err = JsError::type_error(self, msg)?;
553        self.throw(err)
554    }
555
556    /// Throws an instance of the [`RangeError`](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/RangeError) class.
557    fn throw_range_error<S: AsRef<str>, T>(&mut self, msg: S) -> NeonResult<T> {
558        let err = JsError::range_error(self, msg)?;
559        self.throw(err)
560    }
561
562    /// Convenience method for wrapping a value in a `JsBox`.
563    ///
564    /// # Example:
565    ///
566    /// ```rust
567    /// # use neon::prelude::*;
568    /// struct Point(usize, usize);
569    ///
570    /// impl Finalize for Point {}
571    ///
572    /// fn my_neon_function(mut cx: FunctionContext) -> JsResult<JsBox<Point>> {
573    ///     let point = cx.boxed(Point(0, 1));
574    ///
575    ///     Ok(point)
576    /// }
577    /// ```
578    fn boxed<U: Finalize + 'static>(&mut self, v: U) -> Handle<'a, JsBox<U>> {
579        JsBox::new(self, v)
580    }
581
582    #[cfg(feature = "napi-4")]
583    #[deprecated(since = "0.9.0", note = "Please use the channel() method instead")]
584    #[doc(hidden)]
585    fn queue(&mut self) -> Channel {
586        self.channel()
587    }
588
589    #[cfg(feature = "napi-4")]
590    #[cfg_attr(docsrs, doc(cfg(feature = "napi-4")))]
591    /// Returns an unbounded channel for scheduling events to be executed on the JavaScript thread.
592    ///
593    /// When using N-API >= 6,the channel returned by this method is backed by a shared queue.
594    /// To create a channel backed by a _new_ queue see [`Channel`].
595    fn channel(&mut self) -> Channel {
596        #[cfg(feature = "napi-6")]
597        let channel = InstanceData::channel(self);
598
599        #[cfg(not(feature = "napi-6"))]
600        let channel = Channel::new(self);
601
602        channel
603    }
604
605    /// Creates a [`Deferred`] and [`JsPromise`] pair. The [`Deferred`] handle can be
606    /// used to resolve or reject the [`JsPromise`].
607    ///
608    /// ```
609    /// # use neon::prelude::*;
610    /// fn resolve_promise(mut cx: FunctionContext) -> JsResult<JsPromise> {
611    ///     let (deferred, promise) = cx.promise();
612    ///     let msg = cx.string("Hello, World!");
613    ///
614    ///     deferred.resolve(&mut cx, msg);
615    ///
616    ///     Ok(promise)
617    /// }
618    /// ```
619    fn promise(&mut self) -> (Deferred, Handle<'a, JsPromise>) {
620        JsPromise::new(self)
621    }
622
623    /// Creates a [`TaskBuilder`] which can be used to schedule the `execute`
624    /// callback to asynchronously execute on the
625    /// [Node worker pool](https://nodejs.org/en/docs/guides/dont-block-the-event-loop/).
626    ///
627    /// ```
628    /// # use neon::prelude::*;
629    /// fn greet(mut cx: FunctionContext) -> JsResult<JsPromise> {
630    ///     let name = cx.argument::<JsString>(0)?.value(&mut cx);
631    ///
632    ///     let promise = cx
633    ///         .task(move || format!("Hello, {}!", name))
634    ///         .promise(move |mut cx, greeting| Ok(cx.string(greeting)));
635    ///
636    ///     Ok(promise)
637    /// }
638    /// ```
639    fn task<'cx, O, E>(&'cx mut self, execute: E) -> TaskBuilder<'cx, Self, E>
640    where
641        'a: 'cx,
642        O: Send + 'static,
643        E: FnOnce() -> O + Send + 'static,
644    {
645        TaskBuilder::new(self, execute)
646    }
647
648    #[cfg(feature = "sys")]
649    #[cfg_attr(docsrs, doc(cfg(feature = "sys")))]
650    /// Gets the raw `sys::Env` for usage with Node-API.
651    fn to_raw(&self) -> sys::Env {
652        self.env().to_raw()
653    }
654}
655
656/// An execution context of module initialization.
657pub struct ModuleContext<'cx> {
658    cx: Cx<'cx>,
659    exports: Handle<'cx, JsObject>,
660}
661
662impl<'cx> Deref for ModuleContext<'cx> {
663    type Target = Cx<'cx>;
664
665    fn deref(&self) -> &Self::Target {
666        self.cx()
667    }
668}
669
670impl<'cx> DerefMut for ModuleContext<'cx> {
671    fn deref_mut(&mut self) -> &mut Self::Target {
672        self.cx_mut()
673    }
674}
675
676impl<'cx> UnwindSafe for ModuleContext<'cx> {}
677
678impl<'cx> ModuleContext<'cx> {
679    pub(crate) fn with<T, F: for<'b> FnOnce(ModuleContext<'b>) -> T>(
680        env: Env,
681        exports: Handle<'cx, JsObject>,
682        f: F,
683    ) -> T {
684        f(ModuleContext {
685            cx: Cx::new(env),
686            exports,
687        })
688    }
689
690    #[cfg(not(feature = "napi-5"))]
691    /// Convenience method for exporting a Neon function from a module.
692    pub fn export_function<T: Value>(
693        &mut self,
694        key: &str,
695        f: fn(FunctionContext) -> JsResult<T>,
696    ) -> NeonResult<()> {
697        let value = JsFunction::new(self, f)?.upcast::<JsValue>();
698        self.exports.clone().set(self, key, value)?;
699        Ok(())
700    }
701
702    #[cfg(feature = "napi-5")]
703    /// Convenience method for exporting a Neon function from a module.
704    pub fn export_function<F, V>(&mut self, key: &str, f: F) -> NeonResult<()>
705    where
706        F: Fn(FunctionContext) -> JsResult<V> + 'static,
707        V: Value,
708    {
709        let value = JsFunction::new(self, f)?.upcast::<JsValue>();
710        // Note: Cloning `exports` is necessary to avoid holding a shared reference to
711        // `self` while attempting to use it mutably in `set`.
712        self.exports.clone().set(self, key, value)?;
713        Ok(())
714    }
715
716    /// Exports a JavaScript value from a Neon module.
717    pub fn export_value<T: Value>(&mut self, key: &str, val: Handle<T>) -> NeonResult<()> {
718        self.exports.clone().set(self, key, val)?;
719        Ok(())
720    }
721
722    /// Produces a handle to a module's exports object.
723    pub fn exports_object(&mut self) -> JsResult<'cx, JsObject> {
724        Ok(self.exports)
725    }
726}
727
728impl<'cx> ContextInternal<'cx> for ModuleContext<'cx> {
729    fn cx(&self) -> &Cx<'cx> {
730        &self.cx
731    }
732
733    fn cx_mut(&mut self) -> &mut Cx<'cx> {
734        &mut self.cx
735    }
736}
737
738impl<'cx> Context<'cx> for ModuleContext<'cx> {}
739
740/// An execution context of a function call.
741///
742/// The type parameter `T` is the type of the `this`-binding.
743pub struct FunctionContext<'cx> {
744    cx: Cx<'cx>,
745    info: &'cx CallbackInfo<'cx>,
746
747    arguments: Option<sys::call::Arguments>,
748}
749
750impl<'cx> Deref for FunctionContext<'cx> {
751    type Target = Cx<'cx>;
752
753    fn deref(&self) -> &Self::Target {
754        &self.cx
755    }
756}
757
758impl<'cx> DerefMut for FunctionContext<'cx> {
759    fn deref_mut(&mut self) -> &mut Self::Target {
760        &mut self.cx
761    }
762}
763
764impl<'cx> UnwindSafe for FunctionContext<'cx> {}
765
766impl<'cx> FunctionContext<'cx> {
767    /// Indicates whether the function was called with `new`.
768    pub fn kind(&self) -> CallKind {
769        self.info.kind(self)
770    }
771
772    pub(crate) fn with<U, F: for<'b> FnOnce(FunctionContext<'b>) -> U>(
773        env: Env,
774        info: &'cx CallbackInfo<'cx>,
775        f: F,
776    ) -> U {
777        f(FunctionContext {
778            cx: Cx::new(env),
779            info,
780            arguments: None,
781        })
782    }
783
784    /// Indicates the number of arguments that were passed to the function.
785    pub fn len(&self) -> usize {
786        self.info.len(self)
787    }
788
789    /// Indicates if no arguments were passed to the function.
790    pub fn is_empty(&self) -> bool {
791        self.len() == 0
792    }
793
794    /// Produces the `i`th argument, or `None` if `i` is greater than or equal to `self.len()`.
795    pub fn argument_opt(&mut self, i: usize) -> Option<Handle<'cx, JsValue>> {
796        let argv = if let Some(argv) = self.arguments.as_ref() {
797            argv
798        } else {
799            let argv = self.info.argv(self);
800            self.arguments.insert(argv)
801        };
802
803        argv.get(i)
804            .map(|v| unsafe { Handle::new_internal(JsValue::from_local(self.env(), v)) })
805    }
806
807    /// Produces the `i`th argument and casts it to the type `V`, or throws an exception if `i` is greater than or equal to `self.len()` or cannot be cast to `V`.
808    pub fn argument<V: Value>(&mut self, i: usize) -> JsResult<'cx, V> {
809        match self.argument_opt(i) {
810            Some(v) => v.downcast_or_throw(self),
811            None => self.throw_type_error("not enough arguments"),
812        }
813    }
814
815    /// Produces a handle to the `this`-binding and attempts to downcast as a specific type.
816    /// Equivalent to calling `cx.this_value().downcast_or_throw(&mut cx)`.
817    ///
818    /// Throws an exception if the value is a different type.
819    pub fn this<T: Value>(&mut self) -> JsResult<'cx, T> {
820        self.this_value().downcast_or_throw(self)
821    }
822
823    /// Produces a handle to the function's [`this`-binding](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/this#function_context).
824    pub fn this_value(&mut self) -> Handle<'cx, JsValue> {
825        JsValue::new_internal(self.info.this(self))
826    }
827
828    /// Extract Rust data from the JavaScript arguments.
829    ///
830    /// This is frequently more efficient and ergonomic than getting arguments
831    /// individually. See the [`extract`](crate::types::extract) module documentation
832    /// for more examples.
833    ///
834    /// ```
835    /// # use neon::{prelude::*, types::extract::*};
836    /// fn add(mut cx: FunctionContext) -> JsResult<JsNumber> {
837    ///     let (a, b): (f64, f64) = cx.args()?;
838    ///
839    ///     Ok(cx.number(a + b))
840    /// }
841    /// ```
842    pub fn args<T>(&mut self) -> NeonResult<T>
843    where
844        T: FromArgs<'cx>,
845    {
846        T::from_args(self)
847    }
848
849    /// Extract a single argument from a unary function. See [`Context::args`] for more details.
850    pub fn arg<T>(&mut self) -> NeonResult<T>
851    where
852        T: TryFromJs<'cx>,
853    {
854        self.args::<(T,)>().map(|(v,)| v)
855    }
856
857    /// Extract Rust data from the JavaScript arguments.
858    ///
859    /// Similar to [`FunctionContext::args`], but does not throw a JavaScript exception on errors. Useful
860    /// for function overloading.
861    ///
862    /// ```
863    /// # use neon::{prelude::*, types::extract::*};
864    /// fn combine(mut cx: FunctionContext) -> JsResult<JsValue> {
865    ///     if let Some((a, b)) = cx.args_opt::<(f64, f64)>()? {
866    ///         return Ok(cx.number(a + b).upcast());
867    ///     }
868    ///
869    ///     let (a, b): (String, String) = cx.args()?;
870    ///
871    ///     Ok(cx.string(a + &b).upcast())
872    /// }
873    /// ```
874    pub fn args_opt<T>(&mut self) -> NeonResult<Option<T>>
875    where
876        T: FromArgs<'cx>,
877    {
878        T::from_args_opt(self)
879    }
880
881    /// Extract a single optional argument from a unary function. See [`Context::args_opt`] for more details.
882    pub fn arg_opt<T>(&mut self) -> NeonResult<Option<T>>
883    where
884        T: TryFromJs<'cx>,
885    {
886        self.args_opt::<(T,)>().map(|v| v.map(|(v,)| v))
887    }
888
889    pub(crate) fn argv<const N: usize>(&mut self) -> [Handle<'cx, JsValue>; N] {
890        self.info.argv_exact(self)
891    }
892}
893
894impl<'cx> ContextInternal<'cx> for FunctionContext<'cx> {
895    fn cx(&self) -> &Cx<'cx> {
896        &self.cx
897    }
898
899    fn cx_mut(&mut self) -> &mut Cx<'cx> {
900        &mut self.cx
901    }
902}
903
904impl<'cx> Context<'cx> for FunctionContext<'cx> {}