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> {}