Module neon::context[][src]

Expand description

Provides runtime access to the JavaScript engine.

An execution context represents the current state of a thread of execution in the JavaScript engine. Internally, it tracks things like the set of pending function calls, whether the engine is currently throwing an exception or not, and whether the engine is in the process of shutting down. The context uses this internal state to manage what operations are safely available and when.

The Context trait provides an abstract interface to the JavaScript execution context. All interaction with the JavaScript engine in Neon code is mediated through instances of this trait.

One particularly useful context type is CallContext, which is passed to all Neon functions as their initial execution context (or FunctionContext, a convenient shorthand for CallContext<JsObject>):

fn hello(mut cx: FunctionContext) -> JsResult<JsString> {
    Ok(cx.string("hello Neon"))
}

Another important context type is ModuleContext, which is provided to a Neon module’s main function to enable sharing Neon functions back with JavaScript:

#[neon::main]
fn main(mut cx: ModuleContext) -> NeonResult<()> {
    cx.export_function("hello", hello)?;
    Ok(())
}

Memory Management

Because contexts represent the engine at a point in time, they are associated with a lifetime, which limits how long Rust code is allowed to access them. This is also used to determine the lifetime of Handles, which provide safe references to JavaScript memory managed by the engine’s garbage collector.

For example, we can write a simple string scanner that counts whitespace in a JavaScript string and returns a JsNumber:

fn count_whitespace(mut cx: FunctionContext) -> JsResult<JsNumber> {
    let s: Handle<JsString> = cx.argument(0)?;
    let contents = s.value(&mut cx);
    let count = contents
        .chars()                       // iterate over the characters
        .filter(|c| c.is_whitespace()) // select the whitespace chars
        .count();                      // count the resulting chars
    Ok(cx.number(count as f64))
}

In this example, s is assigned a handle to a string, which ensures that the string is kept alive (i.e., prevented from having its storage reclaimed by the JavaScript engine’s garbage collector) for the duration of the count_whitespace function. This is how Neon takes advantage of Rust’s type system to allow your Rust code to safely interact with JavaScript values.

Temporary Scopes

Sometimes it can be useful to limit the scope of a handle’s lifetime, to allow the engine to reclaim memory sooner. This can be important when, for example, an expensive inner loop generates temporary JavaScript values that are only needed inside the loop. In these cases, the execute_scoped and compute_scoped methods allow you to create temporary contexts in order to allocate temporary handles.

For example, to extract the elements of a JavaScript iterator from Rust, a Neon function has to work with several temporary handles on each pass through the loop:

    let iterator = cx.argument::<JsObject>(0)?;         // iterator object
    let next = iterator.get(&mut cx, "next")?           // iterator's `next` method
        .downcast_or_throw::<JsFunction, _>(&mut cx)?;
    let mut numbers = vec![];                           // results vector
    let mut done = false;                               // loop controller

    while !done {
        done = cx.execute_scoped(|mut cx| {                   // temporary scope
            let args: Vec<Handle<JsValue>> = vec![];
            let obj = next.call(&mut cx, iterator, args)?     // temporary object
                .downcast_or_throw::<JsObject, _>(&mut cx)?;
            let number = obj.get(&mut cx, "value")?           // temporary number
                .downcast_or_throw::<JsNumber, _>(&mut cx)?
                .value(&mut cx);
            numbers.push(number);
            Ok(obj.get(&mut cx, "done")?                      // temporary boolean
                .downcast_or_throw::<JsBoolean, _>(&mut cx)?
                .value(&mut cx))
        })?;
    }

The temporary scope ensures that the temporary values are only kept alive during a single pass through the loop, since the temporary context is discarded (and all of its handles released) on the inside of the loop.

Throwing Exceptions

When a Neon API causes a JavaScript exception to be thrown, it returns an Err result, indicating that the thread associated with the context is now throwing. This allows Rust code to perform any cleanup before returning, but with an important restriction:

While a JavaScript thread is throwing, its context cannot be used.

Unless otherwise documented, any Neon API that uses a context (as self or as a parameter) immediately panics if called while the context’s thread is throwing.

Typically, Neon code can manage JavaScript exceptions correctly and conveniently by using Rust’s question mark (?) operator. This ensures that Rust code “short-circuits” when an exception is thrown and returns back to JavaScript without calling any throwing APIs.

Alternatively, to invoke a Neon API and catch any JavaScript exceptions, use the Context::try_catch method, which catches any thrown exception and restores the context to non-throwing state.

See also

  1. Ecma International. Execution contexts, ECMAScript Language Specification.
  2. Madhavan Nagarajan. What is the Execution Context and Stack in JavaScript?
  3. Rupesh Mishra. Execution context, Scope chain and JavaScript internals.

Structs

An execution context of a function call.

An execution context of a scope created by Context::compute_scoped().

An execution context of a scope created by Context::execute_scoped().

A temporary lock of an execution context.

An execution context of module initialization.

An execution context of a task completion callback.

Enums

Indicates whether a function was called with new.

Traits

An execution context, which represents the current state of a thread of execution in the JavaScript engine.

Type Definitions

A shorthand for a CallContext with this-type JsObject.

An alias for CallContext, useful for indicating that the function is a method of a class.