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