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