Compare commits
75 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f3a96aaa7d | ||
|
|
e0c25bfd75 | ||
|
|
c81d98f195 | ||
|
|
d401a32b78 | ||
|
|
d69768f567 | ||
|
|
2f93620146 | ||
|
|
8814886b41 | ||
|
|
e2cc8cc81d | ||
|
|
5c308aec22 | ||
|
|
d9eac77765 | ||
|
|
73bde85776 | ||
|
|
8758b7f416 | ||
|
|
73390414ee | ||
|
|
fc5a214389 | ||
|
|
c5c277e98b | ||
|
|
264a6a4ce0 | ||
|
|
0df7033978 | ||
|
|
3f6804c79f | ||
|
|
1e8d6261a4 | ||
|
|
56834b5afc | ||
|
|
b64f9203ab | ||
|
|
5b20370bee | ||
|
|
acd5ba6e2a | ||
|
|
d473ead705 | ||
|
|
01fbf284a4 | ||
|
|
ec3e057ec6 | ||
|
|
5fe99a8941 | ||
|
|
0ab3b6ee2e | ||
|
|
2f2bfca92a | ||
|
|
378dcc8e8a | ||
|
|
165dffdf4a | ||
|
|
77f2ac06de | ||
|
|
14bc6072ec | ||
|
|
a20636e548 | ||
|
|
0e259239d3 | ||
|
|
fbd09f0bff | ||
|
|
d7ac291d97 | ||
|
|
1e9bedb2d7 | ||
|
|
859d531fe8 | ||
|
|
671add6f37 | ||
|
|
0ab1a9d52f | ||
|
|
d3a296928f | ||
|
|
ad209e30da | ||
|
|
f4cd384ed5 | ||
|
|
be85d188fc | ||
|
|
830836167e | ||
|
|
50cb290278 | ||
|
|
3189ee00c6 | ||
|
|
e302ab9e31 | ||
|
|
17a0ea921c | ||
|
|
b8c8c2a1ae | ||
|
|
3a16627093 | ||
|
|
5078b1714f | ||
|
|
dd3ada4944 | ||
|
|
c2667bde11 | ||
|
|
54c35c52b5 | ||
|
|
01fe92123c | ||
|
|
ed3bb5392e | ||
|
|
687fd06042 | ||
|
|
534c49575a | ||
|
|
50827bee3d | ||
|
|
0e270d1c7c | ||
|
|
b7c26755c1 | ||
|
|
03c7e9e425 | ||
|
|
e860829dac | ||
|
|
f4ec6eaa29 | ||
|
|
96ff123914 | ||
|
|
3792dfd5c6 | ||
|
|
d5bfee3dac | ||
|
|
e6e92cf431 | ||
|
|
bf32f66e95 | ||
|
|
4c224560b6 | ||
|
|
194945ebc6 | ||
|
|
3ab690e8f8 | ||
|
|
1a4cecf9b0 |
@ -3,3 +3,4 @@
|
||||
# The following aliases simplify linting the entire workspace
|
||||
clippy-legacy = "clippy --all-targets --no-default-features -p neon -p neon-runtime -p neon-build -p neon-macros -p tests -p static_tests --features event-handler-api,proc-macros,try-catch-api,legacy-runtime -- -A clippy::missing_safety_doc"
|
||||
clippy-napi = "clippy --all-targets --no-default-features -p neon -p neon-runtime -p neon-build -p neon-macros -p electron-tests -p napi-tests --features proc-macros,try-catch-api,napi-experimental -- -A clippy::missing_safety_doc"
|
||||
neon-test = "test --no-default-features --features napi-experimental"
|
||||
|
||||
4
.github/workflows/linux.yml
vendored
4
.github/workflows/linux.yml
vendored
@ -16,7 +16,7 @@ jobs:
|
||||
|
||||
strategy:
|
||||
matrix:
|
||||
node-version: [10.x, 12.x, 14.x, 15.x]
|
||||
node-version: [12.x, 14.x, 16.x]
|
||||
rust-toolchain: [stable, beta, nightly]
|
||||
|
||||
steps:
|
||||
@ -32,7 +32,7 @@ jobs:
|
||||
- name: install build-essential
|
||||
run: sudo apt-get install -y build-essential
|
||||
- name: run cargo test
|
||||
run: xvfb-run --auto-servernum cargo test --release -- --nocapture
|
||||
run: xvfb-run --auto-servernum cargo neon-test -- --nocapture
|
||||
- name: run CLI test
|
||||
working-directory: ./create-neon
|
||||
run: npm test
|
||||
|
||||
4
.github/workflows/macos.yml
vendored
4
.github/workflows/macos.yml
vendored
@ -16,7 +16,7 @@ jobs:
|
||||
|
||||
strategy:
|
||||
matrix:
|
||||
node-version: [10.x, 12.x, 14.x, 15.x]
|
||||
node-version: [12.x, 14.x, 16.x]
|
||||
rust-toolchain: [stable, beta, nightly]
|
||||
|
||||
steps:
|
||||
@ -34,7 +34,7 @@ jobs:
|
||||
# # https://github.com/nodejs/node-gyp/issues/1933#issuecomment-586915535
|
||||
# run: npm install -g node-gyp@latest
|
||||
- name: run cargo test
|
||||
run: cargo test --release
|
||||
run: cargo neon-test
|
||||
- name: run CLI test
|
||||
working-directory: ./create-neon
|
||||
run: npm test
|
||||
|
||||
6
.github/workflows/windows.yml
vendored
6
.github/workflows/windows.yml
vendored
@ -16,7 +16,7 @@ jobs:
|
||||
|
||||
strategy:
|
||||
matrix:
|
||||
node-version: [10.x, 12.x, 14.x, 15.x]
|
||||
node-version: [12.x, 14.x, 16.x]
|
||||
rust-toolchain: [stable, beta, nightly]
|
||||
|
||||
steps:
|
||||
@ -31,7 +31,7 @@ jobs:
|
||||
with:
|
||||
node-version: ${{ matrix.node-version }}
|
||||
- name: Use npm v6
|
||||
if: ${{ matrix.node-version == '15.x' }}
|
||||
if: ${{ matrix.node-version == '16.x' }}
|
||||
run: npm install -g npm@6
|
||||
- name: Install libclang
|
||||
uses: KyleMayes/install-llvm-action@01144dc97b1e2693196c3056414a44f15180648b
|
||||
@ -43,7 +43,7 @@ jobs:
|
||||
# run: npm install -g node-gyp@latest
|
||||
- run: npm config set msvs_version 2019
|
||||
- name: run cargo test
|
||||
run: cargo test --release
|
||||
run: cargo neon-test
|
||||
env:
|
||||
LIBCLANG_PATH: ${{ runner.temp }}/llvm/bin
|
||||
- name: run CLI test
|
||||
|
||||
@ -17,6 +17,7 @@ Neon owes its existence to the contributions of these fine people.
|
||||
* [Nathaniel Daniel](https://github.com/adumbidiot)
|
||||
* [Joey Ezechiëls](https://github.com/jjpe)
|
||||
* [Cory Forsyth](https://github.com/bantic)
|
||||
* [Olivier Goffart](https://github.com/ogoffart)
|
||||
* [Dave Herman](https://github.com/dherman)
|
||||
* [Himself65](https://github.com/Himself65)
|
||||
* [Maciej Hirsz](https://github.com/maciejhirsz)
|
||||
@ -28,6 +29,7 @@ Neon owes its existence to the contributions of these fine people.
|
||||
* [Aleksey Kladov](https://github.com/matklad)
|
||||
* [Adam Kloboucnik](https://github.com/akloboucnik)
|
||||
* [Renée Kooi](https://github.com/goto-bus-stop)
|
||||
* [Anton Lazarev](https://github.com/antonok-edm)
|
||||
* [Simon Liang](https://github.com/lhr0909)
|
||||
* [Terence Lee](https://github.com/hone)
|
||||
* [Milan Loveless](https://github.com/MilanLoveless)
|
||||
@ -38,6 +40,7 @@ Neon owes its existence to the contributions of these fine people.
|
||||
* [Robbie Pitts](https://github.com/robbiepitts)
|
||||
* [Thiago Pontes](https://github.com/thiagopnts)
|
||||
* [Sean Prashad](https://github.com/SeanPrashad)
|
||||
* [Jordan Rose](https://github.com/jrose-signal)
|
||||
* [Antonio Scandurra](https://github.com/as-cii)
|
||||
* [Edward Shaw](https://github.com/EdShaw)
|
||||
* [Nathan Sobo](https://github.com/nathansobo)
|
||||
@ -53,6 +56,7 @@ Neon owes its existence to the contributions of these fine people.
|
||||
* [Roberto Vidal](https://github.com/jrvidal)
|
||||
* [Georg Vienna](https://github.com/geovie)
|
||||
* [Daijiro Wachi](https://github.com/watilde)
|
||||
* [Chi Wang](https://github.com/patr0nus)
|
||||
* [wangcong](https://github.com/king6cong)
|
||||
* [Amila Welihinda](https://github.com/amilajack)
|
||||
* [Felix Yan](https://github.com/felixonmars)
|
||||
|
||||
13
Cargo.toml
13
Cargo.toml
@ -1,29 +1,32 @@
|
||||
[package]
|
||||
name = "neon"
|
||||
version = "0.7.1"
|
||||
version = "0.8.2"
|
||||
authors = ["Dave Herman <david.herman@gmail.com>"]
|
||||
description = "A safe abstraction layer for Node.js."
|
||||
readme = "README.md"
|
||||
homepage = "https://www.neon-bindings.com"
|
||||
repository = "https://github.com/neon-bindings/neon"
|
||||
license = "MIT/Apache-2.0"
|
||||
exclude = ["neon.jpg"]
|
||||
exclude = ["neon.jpg", "doc/**/*"]
|
||||
build = "build.rs"
|
||||
edition = "2018"
|
||||
|
||||
[build-dependencies]
|
||||
neon-build = { version = "=0.7.1", path = "crates/neon-build" }
|
||||
neon-build = { version = "=0.8.2", path = "crates/neon-build" }
|
||||
|
||||
[dev-dependencies]
|
||||
lazy_static = "1.4.0"
|
||||
rustversion = "0.1.4"
|
||||
semver = "0.9"
|
||||
psd = "0.1.9" # used for a doc example
|
||||
failure = "0.1.5" # used for a doc example
|
||||
|
||||
[dependencies]
|
||||
cslice = "0.2"
|
||||
semver = "0.9.0"
|
||||
smallvec = "1.4.2"
|
||||
neon-runtime = { version = "=0.7.1", path = "crates/neon-runtime" }
|
||||
neon-macros = { version = "=0.7.1", path = "crates/neon-macros", optional = true }
|
||||
neon-runtime = { version = "=0.8.2", path = "crates/neon-runtime" }
|
||||
neon-macros = { version = "=0.8.2", path = "crates/neon-macros", optional = true }
|
||||
|
||||
[features]
|
||||
default = ["legacy-runtime"]
|
||||
|
||||
@ -33,14 +33,15 @@ The N-API backend of Neon requires a minimum Node version of 10.0.
|
||||
|
||||
To enable the N-API backend, you need to:
|
||||
|
||||
1. Disable the default features (for now, the default features select the legacy backend) by setting `default-features = false`; and
|
||||
2. Enable the appropriate feature flag in your `Cargo.toml` to select the N-API version you need support for (each N-API version N uses the feature flag `"napi-N"`, for example `"napi-4"` for N-API version 4).
|
||||
1. Remove `build.rs` from the project directory and `build = "build.rs"` from the `Cargo.toml`. The N-API backend does not require a Cargo build script.
|
||||
2. Disable the default features (for now, the default features select the legacy backend) by setting `default-features = false`; and
|
||||
3. Enable the appropriate feature flag in your `Cargo.toml` to select the N-API version you need support for (each N-API version N uses the feature flag `"napi-N"`, for example `"napi-4"` for N-API version 4).
|
||||
|
||||
As a rule, you should choose the **oldest version of N-API that has the APIs you need.** (We will be adding N-API version requirements to the Neon API docs to make this clearer in the future.) You can consult the [official N-API feature matrix](https://nodejs.org/api/n-api.html#n_api_node_api_version_matrix) to see which N-API versions come with various versions of Node.
|
||||
|
||||
```toml
|
||||
[dependencies.neon]
|
||||
version = "0.7.1"
|
||||
version = "0.8.2"
|
||||
default-features = false
|
||||
features = ["napi-4"]
|
||||
```
|
||||
@ -192,7 +193,7 @@ The supported mechanism for concurrency is the Event Queue API (`neon::event::Ev
|
||||
|
||||
```toml
|
||||
[dependencies.neon]
|
||||
version = "0.7.1"
|
||||
version = "0.8.1"
|
||||
default-features = false
|
||||
features = ["napi-4", "event-queue-api"]
|
||||
```
|
||||
|
||||
11
README.md
11
README.md
@ -13,19 +13,20 @@ Rust bindings for writing safe and fast native Node.js modules.
|
||||
Once you have the [platform dependencies](https://neon-bindings.com/docs/getting-started#install-node-build-tools/) installed, getting started is as simple as:
|
||||
|
||||
```
|
||||
$ npm install -g neon-cli
|
||||
$ neon new my-project
|
||||
$ npm init neon my-project
|
||||
```
|
||||
|
||||
Then see the [Hello World guide](https://neon-bindings.com/docs/hello-world/) for writing your first Hello World in Neon!
|
||||
|
||||
_**Note:** This will create a new project with the `napi-backend` and some documentation may not be up to date._
|
||||
|
||||
# Docs
|
||||
|
||||
See our [Neon fundamentals docs](https://neon-bindings.com/docs/intro) and our [API docs](https://docs.rs/neon/latest/neon).
|
||||
|
||||
# N-API Migration Guide
|
||||
|
||||
We are [hard at work](https://github.com/neon-bindings/neon/issues/444) porting Neon to a new backend based on [N-API](https://nodejs.org/api/n-api.html), which will be the basis for Neon 1.0.
|
||||
We've ported Neon to a new backend based on [N-API](https://nodejs.org/api/n-api.html), which will be the basis for Neon 1.0.
|
||||
|
||||
**Read the new [migration guide](https://github.com/neon-bindings/neon/blob/main/MIGRATION_GUIDE.md)** to learn how to port your Neon projects to N-API!
|
||||
|
||||
@ -39,11 +40,11 @@ We are [hard at work](https://github.com/neon-bindings/neon/issues/444) porting
|
||||
|
||||
### Node.js
|
||||
|
||||
| Node 10 | Node 12 | Node 14 |
|
||||
| Node 12 | Node 14 | Node 16 |
|
||||
| ------- | ------- | ------- |
|
||||
| ✓ | ✓ | ✓ |
|
||||
|
||||
Support for [LTS versions of Node](https://github.com/nodejs/LTS#lts-schedule) and current are expected. If you're using a different version of Node and believe it should be supported, let us know.
|
||||
Support for [LTS versions of Node](https://github.com/nodejs/LTS#release-schedule) and current are expected. If you're using a different version of Node and believe it should be supported, let us know.
|
||||
|
||||
### Rust
|
||||
|
||||
|
||||
34
RELEASES.md
34
RELEASES.md
@ -1,3 +1,37 @@
|
||||
# Version 0.8.2
|
||||
|
||||
* More docs improvements
|
||||
* Added a deprecation warning to `neon new` (https://github.com/neon-bindings/neon/pull/722)
|
||||
|
||||
# Version 0.8.1
|
||||
|
||||
* Fix `legacy-backend` for Node 16 (https://github.com/neon-bindings/neon/pull/715)
|
||||
* Various docs improvements
|
||||
|
||||
# Version 0.8.0
|
||||
|
||||
## Fixes
|
||||
|
||||
* `as_slice` and `as_mut_slice` properly handle a `null` pointer from an empty buffer (https://github.com/neon-bindings/neon/pull/681)
|
||||
* Global drop queue added to avoid panics on N-API 6+ when dropping a `Root` (https://github.com/neon-bindings/neon/pull/700)
|
||||
|
||||
## Features
|
||||
|
||||
* Added `neon::reflect::eval` (https://github.com/neon-bindings/neon/pull/692)
|
||||
* Added `create-neon` for creating an N-API project (https://github.com/neon-bindings/neon/pull/690)
|
||||
* Added details to the `README.md` generated by `create-neon` (https://github.com/neon-bindings/neon/pull/697)
|
||||
|
||||
## Improvements
|
||||
|
||||
* Switched N-API tests to `cargo-cp-artifact` (https://github.com/neon-bindings/neon/pull/687)
|
||||
* Added `impl<T: Finalize> Finalize for Option<T>` (https://github.com/neon-bindings/neon/pull/680)
|
||||
* Added a N-API migration guide (https://github.com/neon-bindings/neon/pull/685)
|
||||
|
||||
## Housekeeping
|
||||
|
||||
* Lint fixes (https://github.com/neon-bindings/neon/pull/609)
|
||||
* Lint CI enforcement and `cargo fmt` (https://github.com/neon-bindings/neon/pull/698)
|
||||
|
||||
# Version 0.7.1
|
||||
|
||||
### Features
|
||||
|
||||
26
cli/package-lock.json
generated
26
cli/package-lock.json
generated
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "neon-cli",
|
||||
"version": "0.7.1",
|
||||
"version": "0.8.2",
|
||||
"lockfileVersion": 1,
|
||||
"requires": true,
|
||||
"dependencies": {
|
||||
@ -616,9 +616,9 @@
|
||||
"dev": true
|
||||
},
|
||||
"handlebars": {
|
||||
"version": "4.7.6",
|
||||
"resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.7.6.tgz",
|
||||
"integrity": "sha512-1f2BACcBfiwAfStCKZNrUCgqNZkGsAT7UM3kkYtXuLo0KnaVfjKOyf7PRzB6++aK9STyT1Pd2ZCPe3EGOXleXA==",
|
||||
"version": "4.7.7",
|
||||
"resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.7.7.tgz",
|
||||
"integrity": "sha512-aAcXm5OAfE/8IXkcZvCepKU3VzW1/39Fb5ZuqMtgI/hT8X2YgoMvBY5dLhq/cpOvw7Lk1nK/UF71aLG/ZnVYRA==",
|
||||
"requires": {
|
||||
"minimist": "^1.2.5",
|
||||
"neo-async": "^2.6.0",
|
||||
@ -849,9 +849,9 @@
|
||||
}
|
||||
},
|
||||
"lodash": {
|
||||
"version": "4.17.19",
|
||||
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.19.tgz",
|
||||
"integrity": "sha512-JNvd8XER9GQX0v2qJgsaN/mzFCNA5BRe/j8JN9d+tWyGLSodKQHKFicdwNYzWwI3wjRnaKPsGj1XkBjx/F96DQ=="
|
||||
"version": "4.17.21",
|
||||
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz",
|
||||
"integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg=="
|
||||
},
|
||||
"lodash.camelcase": {
|
||||
"version": "4.3.0",
|
||||
@ -1365,9 +1365,9 @@
|
||||
"integrity": "sha512-VAH4IvQ7BDFYglMd7BPRDfLgxZZX4O4TFcRDA6EN5X7erNJJq+McIEp8np9aVtxrCJ6qx4GTYVfOWNjcqwZgRw=="
|
||||
},
|
||||
"uglify-js": {
|
||||
"version": "3.10.0",
|
||||
"resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.10.0.tgz",
|
||||
"integrity": "sha512-Esj5HG5WAyrLIdYU74Z3JdG2PxdIusvj6IWHMtlyESxc7kcDz7zYlYjpnSokn1UbpV0d/QX9fan7gkCNd/9BQA==",
|
||||
"version": "3.13.5",
|
||||
"resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.13.5.tgz",
|
||||
"integrity": "sha512-xtB8yEqIkn7zmOyS2zUNBsYCBRhDkvlNxMMY2smuJ/qA8NCHeQvKCF3i9Z4k8FJH4+PJvZRtMrPynfZ75+CSZw==",
|
||||
"optional": true
|
||||
},
|
||||
"validate-npm-package-license": {
|
||||
@ -1552,9 +1552,9 @@
|
||||
"integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8="
|
||||
},
|
||||
"y18n": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.0.tgz",
|
||||
"integrity": "sha512-r9S/ZyXu/Xu9q1tYlpsLIsa3EeLXXk0VwlxqTcFRfg9EhMW+17kbt9G0NrgCmhGb5vT2hyhJZLfDGx+7+5Uj/w==",
|
||||
"version": "4.0.1",
|
||||
"resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.1.tgz",
|
||||
"integrity": "sha512-wNcy4NvjMYL8gogWWYAO7ZFWFfHcbdbE57tZO8e4cbpj8tfUcwrwqSl3ad8HxpYWCdXcJUCeKKZS62Av1affwQ==",
|
||||
"dev": true
|
||||
},
|
||||
"yargs": {
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "neon-cli",
|
||||
"version": "0.7.1",
|
||||
"version": "0.8.2",
|
||||
"description": "Build and load native Rust/Neon modules.",
|
||||
"author": "Dave Herman <david.herman@gmail.com>",
|
||||
"repository": {
|
||||
|
||||
@ -99,6 +99,11 @@ interface Answers {
|
||||
}
|
||||
|
||||
export default async function wizard(pwd: string, name: string, neon: string | null, features: string | null, noDefaultFeatures: boolean) {
|
||||
let warning = "WARN: `neon new` is deprecated. To create a new project use `npm init neon my-project`.";
|
||||
let banner = "".padStart(warning.length + 4, "#");
|
||||
|
||||
console.warn(`${banner}\n# ${warning} #\n${banner}\n`);
|
||||
|
||||
let its = validateName(name);
|
||||
if (!its.validForNewPackages) {
|
||||
let errors = (its.errors || []).concat(its.warnings || []);
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "neon-build"
|
||||
version = "0.7.1"
|
||||
version = "0.8.2"
|
||||
authors = ["Dave Herman <david.herman@gmail.com>"]
|
||||
description = "Build logic required for Neon projects."
|
||||
repository = "https://github.com/neon-bindings/neon"
|
||||
@ -9,4 +9,4 @@ edition = "2018"
|
||||
build = "build.rs"
|
||||
|
||||
[dependencies]
|
||||
neon-sys = { version = "=0.7.1", path = "../neon-sys", optional = true }
|
||||
neon-sys = { version = "=0.8.2", path = "../neon-sys", optional = true }
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "neon-macros"
|
||||
version = "0.7.1"
|
||||
version = "0.8.2"
|
||||
authors = ["Dave Herman <david.herman@gmail.com>"]
|
||||
description = "Procedural macros supporting Neon"
|
||||
repository = "https://github.com/neon-bindings/neon"
|
||||
|
||||
@ -14,14 +14,15 @@ use legacy as macros;
|
||||
// Implementations are in the backend dependent module
|
||||
|
||||
#[proc_macro_attribute]
|
||||
/// Marks a method as the main entrypoint for initialization in a Neon
|
||||
/// module. This attribute should only be used _once_ in a module and will
|
||||
/// Marks a function as the main entry point for initialization in
|
||||
/// a Neon module.
|
||||
///
|
||||
/// This attribute should only be used _once_ in a module and will
|
||||
/// be called each time the module is initialized in a context.
|
||||
///
|
||||
/// ```ignore
|
||||
/// # use neon::prelude::*;
|
||||
/// #[neon::main]
|
||||
/// fn my_module(mut cx: ModuleContext) -> NeonResult<()> {
|
||||
/// fn main(mut cx: ModuleContext) -> NeonResult<()> {
|
||||
/// let version = cx.string("1.0.0");
|
||||
///
|
||||
/// cx.export_value("version", version)?;
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "neon-runtime"
|
||||
version = "0.7.1"
|
||||
version = "0.8.2"
|
||||
authors = ["Dave Herman <david.herman@gmail.com>"]
|
||||
description = "Bindings to the Node.js native addon API, used by the Neon implementation."
|
||||
repository = "https://github.com/neon-bindings/neon"
|
||||
@ -10,7 +10,7 @@ edition = "2018"
|
||||
[dependencies]
|
||||
cfg-if = "1.0.0"
|
||||
libloading = { version = "0.6.5", optional = true }
|
||||
neon-sys = { version = "=0.7.1", path = "../neon-sys", optional = true }
|
||||
neon-sys = { version = "=0.8.2", path = "../neon-sys", optional = true }
|
||||
smallvec = "1.4.2"
|
||||
|
||||
[dev-dependencies]
|
||||
|
||||
@ -257,6 +257,7 @@ mod napi5 {
|
||||
#[cfg(feature = "napi-6")]
|
||||
mod napi6 {
|
||||
use super::super::types::*;
|
||||
use std::os::raw::c_void;
|
||||
|
||||
generate!(
|
||||
extern "C" {
|
||||
@ -268,6 +269,15 @@ mod napi6 {
|
||||
key_conversion: KeyConversion,
|
||||
result: *mut Value,
|
||||
) -> Status;
|
||||
|
||||
fn set_instance_data(
|
||||
env: Env,
|
||||
data: *mut c_void,
|
||||
finalize_cb: Finalize,
|
||||
finalize_hint: *mut c_void,
|
||||
) -> Status;
|
||||
|
||||
fn get_instance_data(env: Env, data: *mut *mut c_void) -> Status;
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
49
crates/neon-runtime/src/napi/lifecycle.rs
Normal file
49
crates/neon-runtime/src/napi/lifecycle.rs
Normal file
@ -0,0 +1,49 @@
|
||||
//! # Environment life cycle APIs
|
||||
//!
|
||||
//! These APIs map to the life cycle of a specific "Agent" or self-contained
|
||||
//! environment. If a Neon module is loaded multiple times (Web Workers, worker
|
||||
//! threads), these API will be handle data associated with a specific instance.
|
||||
//!
|
||||
//! See the [N-API Lifecycle][npai-docs] documentation for more details.
|
||||
//!
|
||||
//! [napi-docs]: https://nodejs.org/api/n-api.html#n_api_environment_life_cycle_apis
|
||||
|
||||
use std::mem::MaybeUninit;
|
||||
use std::os::raw::c_void;
|
||||
use std::ptr;
|
||||
|
||||
use crate::napi::bindings as napi;
|
||||
use crate::raw::Env;
|
||||
|
||||
/// # Safety
|
||||
/// `env` must point to a valid `napi_env` for this thread
|
||||
pub unsafe fn set_instance_data<T: Send + 'static>(env: Env, data: T) -> *mut T {
|
||||
let data = Box::into_raw(Box::new(data));
|
||||
|
||||
assert_eq!(
|
||||
napi::set_instance_data(env, data.cast(), Some(drop_box::<T>), ptr::null_mut(),),
|
||||
napi::Status::Ok,
|
||||
);
|
||||
|
||||
data
|
||||
}
|
||||
|
||||
/// # Safety
|
||||
/// * `T` must be the same type used in `set_instance_data`
|
||||
/// * Caller must ensure reference does not outlive `Env`
|
||||
/// * Return value may be `null`
|
||||
/// * `env` must point to a valid `napi_env` for this thread
|
||||
pub unsafe fn get_instance_data<T: Send + 'static>(env: Env) -> *mut T {
|
||||
let mut data = MaybeUninit::uninit();
|
||||
|
||||
assert_eq!(
|
||||
napi::get_instance_data(env, data.as_mut_ptr(),),
|
||||
napi::Status::Ok,
|
||||
);
|
||||
|
||||
data.assume_init().cast()
|
||||
}
|
||||
|
||||
unsafe extern "C" fn drop_box<T>(_env: Env, data: *mut c_void, _hint: *mut c_void) {
|
||||
Box::<T>::from_raw(data.cast());
|
||||
}
|
||||
@ -8,6 +8,8 @@ pub mod date;
|
||||
pub mod error;
|
||||
pub mod external;
|
||||
pub mod fun;
|
||||
#[cfg(feature = "napi-6")]
|
||||
pub mod lifecycle;
|
||||
pub mod mem;
|
||||
pub mod object;
|
||||
pub mod primitive;
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "neon-sys"
|
||||
version = "0.7.1"
|
||||
version = "0.8.2"
|
||||
authors = ["David Herman <david.herman@gmail.com>"]
|
||||
description = "Exposes the low-level V8/NAN C/C++ APIs. Will be superseded by N-API."
|
||||
edition = "2018"
|
||||
|
||||
@ -205,6 +205,14 @@ mod build {
|
||||
.output()
|
||||
.expect("Failed to run \"node-gyp build\" for neon-sys!");
|
||||
|
||||
if !build_output.status.success() {
|
||||
panic!(
|
||||
"Failed to run \"node-gyp build\" for neon-sys!\n Out: {}\n Err: {}",
|
||||
String::from_utf8_lossy(&build_output.stdout),
|
||||
String::from_utf8_lossy(&build_output.stderr)
|
||||
);
|
||||
}
|
||||
|
||||
let node_gyp_build_output = String::from_utf8_lossy(&build_output.stderr);
|
||||
println!(
|
||||
"cargo:node_arch={}",
|
||||
|
||||
@ -332,7 +332,7 @@ extern "C" void Neon_Class_SetClassMap(v8::Isolate *isolate, void *map, Neon_Dro
|
||||
neon::ClassMapHolder *holder = new neon::ClassMapHolder(map, drop_map);
|
||||
isolate->SetData(NEON_ISOLATE_SLOT, holder);
|
||||
// ISSUE(#77): When workers land in node, this will need to be generalized to a per-worker version.
|
||||
node::AtExit(cleanup_class_map, holder);
|
||||
node::AtExit(node::GetCurrentEnvironment(isolate->GetCurrentContext()), cleanup_class_map, holder);
|
||||
}
|
||||
|
||||
extern "C" void *Neon_Class_GetCallKernel(void *wrapper) {
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
{
|
||||
"neon": "0.7",
|
||||
"neon": "0.8",
|
||||
"napi": "6",
|
||||
"cargo-cp-artifact": "0.1"
|
||||
}
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "create-neon",
|
||||
"version": "0.1.2",
|
||||
"version": "0.1.3",
|
||||
"description": "Create Neon projects with no build configuration.",
|
||||
"author": "Dave Herman <david.herman@gmail.com>",
|
||||
"license": "MIT",
|
||||
|
||||
BIN
doc/types.jpg
Normal file
BIN
doc/types.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 29 KiB |
BIN
doc/types.pptx
Normal file
BIN
doc/types.pptx
Normal file
Binary file not shown.
@ -1,4 +1,4 @@
|
||||
use borrow::LoanError;
|
||||
use crate::borrow::LoanError;
|
||||
use std;
|
||||
use std::collections::HashSet;
|
||||
use std::os::raw::c_void;
|
||||
|
||||
@ -1,4 +1,35 @@
|
||||
//! Types and traits for obtaining temporary access to the internals of JavaScript values.
|
||||
//! Provides temporary access to JavaScript typed arrays.
|
||||
//!
|
||||
//! ## Typed Arrays
|
||||
//!
|
||||
//! JavaScript's [typed arrays][typed-arrays] are objects that allow reading and writing
|
||||
//! raw binary data in memory.
|
||||
//!
|
||||
//! Typed arrays are managed with the [`ArrayBuffer`][ArrayBuffer] type, which controls
|
||||
//! the storage of the underlying data buffer, and several typed views for managing access
|
||||
//! to the buffer. Neon provides access to the `ArrayBuffer` class with the
|
||||
//! [`JsArrayBuffer`](crate::types::JsArrayBuffer) type.
|
||||
//!
|
||||
//! Node also provides a [`Buffer`][Buffer] type, which is built on top of `ArrayBuffer`
|
||||
//! and provides additional functionality. Neon provides access to the `Buffer` class
|
||||
//! with the [`JsBuffer`](crate::types::JsBuffer) type.
|
||||
//!
|
||||
//! Many of Node's I/O APIs work with these types, and they can also be used for
|
||||
//! compact in-memory data structures, which can be shared efficiently between
|
||||
//! JavaScript and Rust without copying.
|
||||
//!
|
||||
//! ## Borrowing
|
||||
//!
|
||||
//! Neon makes it possible to [borrow][borrow] temporary access to the internal memory
|
||||
//! of a typed array by pausing execution of JavaScript with a
|
||||
//! [`Lock`](crate::context::Lock) and returning a reference to a
|
||||
//! [`BinaryData`](crate::types::BinaryData) struct. The [`Borrow`](Borrow) and
|
||||
//! [`BorrowMut`](BorrowMut) traits provide the methods for borrowing this typed array data.
|
||||
//!
|
||||
//! [typed-arrays]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Typed_arrays
|
||||
//! [borrow]: https://doc.rust-lang.org/beta/rust-by-example/scope/borrow.html
|
||||
//! [ArrayBuffer]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/ArrayBuffer
|
||||
//! [Buffer]: https://nodejs.org/api/buffer.html
|
||||
|
||||
pub(crate) mod internal;
|
||||
|
||||
@ -7,7 +38,7 @@ use std::ops::{Deref, DerefMut, Drop};
|
||||
use std::os::raw::c_void;
|
||||
|
||||
use self::internal::Pointer;
|
||||
use context::Lock;
|
||||
use crate::context::Lock;
|
||||
|
||||
/// A trait for JS values whose internal contents can be borrowed immutably by Rust while the JS engine is locked.
|
||||
pub trait Borrow: Sized {
|
||||
|
||||
@ -1,14 +1,15 @@
|
||||
use super::ModuleContext;
|
||||
use handle::Handle;
|
||||
use crate::handle::Handle;
|
||||
#[cfg(feature = "legacy-runtime")]
|
||||
use crate::object::class::ClassMap;
|
||||
use crate::result::NeonResult;
|
||||
use crate::types::{JsObject, JsValue};
|
||||
use neon_runtime;
|
||||
use neon_runtime::raw;
|
||||
use neon_runtime::scope::Root;
|
||||
#[cfg(feature = "legacy-runtime")]
|
||||
use neon_runtime::try_catch::TryCatchControl;
|
||||
#[cfg(feature = "legacy-runtime")]
|
||||
use object::class::ClassMap;
|
||||
use result::NeonResult;
|
||||
#[cfg(feature = "legacy-runtime")]
|
||||
use std::any::Any;
|
||||
use std::cell::{Cell, RefCell};
|
||||
use std::mem::MaybeUninit;
|
||||
@ -16,7 +17,6 @@ use std::mem::MaybeUninit;
|
||||
use std::os::raw::c_void;
|
||||
#[cfg(feature = "legacy-runtime")]
|
||||
use std::panic::{catch_unwind, resume_unwind, AssertUnwindSafe};
|
||||
use types::{JsObject, JsValue};
|
||||
|
||||
#[cfg(feature = "legacy-runtime")]
|
||||
#[repr(C)]
|
||||
|
||||
@ -1,19 +1,175 @@
|
||||
//! Node _execution contexts_, which manage access to the JavaScript engine at various points in the Node.js runtime lifecycle.
|
||||
//! 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`](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`](CallContext), which is passed
|
||||
//! to all Neon functions as their initial execution context (or [`FunctionContext`](FunctionContext),
|
||||
//! a convenient shorthand for `CallContext<JsObject>`):
|
||||
//!
|
||||
//! ```
|
||||
//! # use neon::prelude::*;
|
||||
//! fn hello(mut cx: FunctionContext) -> JsResult<JsString> {
|
||||
//! Ok(cx.string("hello Neon"))
|
||||
//! }
|
||||
//! ```
|
||||
//!
|
||||
//! Another important context type is [`ModuleContext`](ModuleContext), which is provided
|
||||
//! to a Neon module's [`main`](crate::main) function to enable sharing Neon functions back
|
||||
//! with JavaScript:
|
||||
//!
|
||||
//! ```
|
||||
//! # #[cfg(feature = "neon-macros")] {
|
||||
//! # use neon::prelude::*;
|
||||
//! # fn hello(_: FunctionContext) -> JsResult<JsValue> { todo!() }
|
||||
//! #[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_][lifetime], which limits how long Rust code is allowed to access them. This
|
||||
//! is also used to determine the lifetime of [`Handle`](crate::handle::Handle)s, 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`](crate::types::JsNumber):
|
||||
//!
|
||||
//! ```
|
||||
//! # #[cfg(feature = "napi-1")] {
|
||||
//! # use neon::prelude::*;
|
||||
//! 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`](Context::execute_scoped) and [`compute_scoped`](Context::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][iterator] from Rust,
|
||||
//! a Neon function has to work with several temporary handles on each pass through
|
||||
//! the loop:
|
||||
//!
|
||||
//! ```
|
||||
//! # #[cfg(feature = "napi-1")] {
|
||||
//! # use neon::prelude::*;
|
||||
//! # fn iterate(mut cx: FunctionContext) -> JsResult<JsUndefined> {
|
||||
//! 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))
|
||||
//! })?;
|
||||
//! }
|
||||
//! # Ok(cx.undefined())
|
||||
//! # }
|
||||
//! # }
|
||||
//! ```
|
||||
//!
|
||||
//! 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`](std::result::Result::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 (`?`)][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`](Context::try_catch) method, which catches any thrown
|
||||
//! exception and restores the context to non-throwing state.
|
||||
//!
|
||||
//! ## See also
|
||||
//!
|
||||
//! 1. Ecma International. [Execution contexts](https://tc39.es/ecma262/#sec-execution-contexts), _ECMAScript Language Specification_.
|
||||
//! 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)
|
||||
//! 3. Rupesh Mishra. [Execution context, Scope chain and JavaScript internals](https://medium.com/@happymishra66/execution-context-in-javascript-319dd72e8e2c).
|
||||
//!
|
||||
//! [lifetime]: https://doc.rust-lang.org/book/ch10-00-generics.html
|
||||
//! [iterator]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Iterators_and_Generators
|
||||
//! [question-mark]: https://doc.rust-lang.org/edition-guide/rust-2018/error-handling-and-panics/the-question-mark-operator-for-easier-error-handling.html
|
||||
|
||||
pub(crate) mod internal;
|
||||
|
||||
use borrow::internal::Ledger;
|
||||
use borrow::{Borrow, BorrowMut, Ref, RefMut};
|
||||
use context::internal::Env;
|
||||
use crate::borrow::internal::Ledger;
|
||||
use crate::borrow::{Borrow, BorrowMut, Ref, RefMut};
|
||||
use crate::context::internal::Env;
|
||||
#[cfg(all(feature = "napi-4", feature = "event-queue-api"))]
|
||||
use event::EventQueue;
|
||||
use handle::{Handle, Managed};
|
||||
use crate::event::EventQueue;
|
||||
use crate::handle::{Handle, Managed};
|
||||
#[cfg(feature = "legacy-runtime")]
|
||||
use crate::object::class::Class;
|
||||
use crate::object::{Object, This};
|
||||
use crate::result::{JsResult, NeonResult, Throw};
|
||||
use crate::types::binary::{JsArrayBuffer, JsBuffer};
|
||||
#[cfg(feature = "napi-1")]
|
||||
use crate::types::boxed::{Finalize, JsBox};
|
||||
#[cfg(feature = "napi-5")]
|
||||
use crate::types::date::{DateError, JsDate};
|
||||
use crate::types::error::JsError;
|
||||
use crate::types::{
|
||||
JsArray, JsBoolean, JsFunction, JsNull, JsNumber, JsObject, JsString, JsUndefined, JsValue,
|
||||
StringResult, Value,
|
||||
};
|
||||
use neon_runtime;
|
||||
use neon_runtime::raw;
|
||||
#[cfg(feature = "legacy-runtime")]
|
||||
use object::class::Class;
|
||||
use object::{Object, This};
|
||||
use result::{JsResult, NeonResult, Throw};
|
||||
#[cfg(feature = "napi-1")]
|
||||
use smallvec::SmallVec;
|
||||
use std;
|
||||
@ -22,16 +178,6 @@ use std::convert::Into;
|
||||
use std::marker::PhantomData;
|
||||
use std::os::raw::c_void;
|
||||
use std::panic::UnwindSafe;
|
||||
use types::binary::{JsArrayBuffer, JsBuffer};
|
||||
#[cfg(feature = "napi-1")]
|
||||
use types::boxed::{Finalize, JsBox};
|
||||
#[cfg(feature = "napi-5")]
|
||||
use types::date::{DateError, JsDate};
|
||||
use types::error::JsError;
|
||||
use types::{
|
||||
JsArray, JsBoolean, JsFunction, JsNull, JsNumber, JsObject, JsString, JsUndefined, JsValue,
|
||||
StringResult, Value,
|
||||
};
|
||||
|
||||
use self::internal::{ContextInternal, Scope, ScopeMetadata};
|
||||
|
||||
@ -112,16 +258,18 @@ impl CallbackInfo<'_> {
|
||||
}
|
||||
}
|
||||
|
||||
/// Indicates whether a function call was called with JavaScript's `[[Call]]` or `[[Construct]]` semantics.
|
||||
/// Indicates whether a function was called with `new`.
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
pub enum CallKind {
|
||||
Construct,
|
||||
Call,
|
||||
}
|
||||
|
||||
/// An RAII implementation of a "scoped lock" of the JS engine. When this structure is dropped (falls out of scope), the engine will be unlocked.
|
||||
/// A temporary lock of an execution context.
|
||||
///
|
||||
/// Types of JS values that support the `Borrow` and `BorrowMut` traits can be inspected while the engine is locked by passing a reference to a `Lock` to their methods.
|
||||
/// While a lock is alive, no JavaScript code can be executed in the execution context.
|
||||
///
|
||||
/// Objects that support the `Borrow` and `BorrowMut` traits can be inspected while the context is locked by passing a reference to a `Lock` to their methods.
|
||||
pub struct Lock<'a> {
|
||||
pub(crate) ledger: RefCell<Ledger>,
|
||||
pub(crate) env: Env,
|
||||
@ -138,7 +286,9 @@ impl<'a> Lock<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
/// An _execution context_, which provides context-sensitive access to the JavaScript engine. Most operations that interact with the engine require passing a reference to a context.
|
||||
/// An _execution context_, which represents the current state of a thread of execution in the JavaScript engine.
|
||||
///
|
||||
/// All interaction with the JavaScript engine in Neon code is mediated through instances of this trait.
|
||||
///
|
||||
/// 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.
|
||||
pub trait Context<'a>: ContextInternal<'a> {
|
||||
@ -406,7 +556,7 @@ pub trait Context<'a>: ContextInternal<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
/// A view of the JS engine in the context of top-level initialization of a Neon module.
|
||||
/// An execution context of module initialization.
|
||||
pub struct ModuleContext<'a> {
|
||||
scope: Scope<'a, raw::HandleScope>,
|
||||
exports: Handle<'a, JsObject>,
|
||||
@ -474,7 +624,7 @@ impl<'a> ContextInternal<'a> for ModuleContext<'a> {
|
||||
|
||||
impl<'a> Context<'a> for ModuleContext<'a> {}
|
||||
|
||||
/// A view of the JS engine in the context of a scoped computation started by `Context::execute_scoped()`.
|
||||
/// An execution context of a scope created by [`Context::execute_scoped()`](Context::execute_scoped).
|
||||
pub struct ExecuteContext<'a> {
|
||||
scope: Scope<'a, raw::HandleScope>,
|
||||
}
|
||||
@ -496,7 +646,7 @@ impl<'a> ContextInternal<'a> for ExecuteContext<'a> {
|
||||
|
||||
impl<'a> Context<'a> for ExecuteContext<'a> {}
|
||||
|
||||
/// A view of the JS engine in the context of a scoped computation started by `Context::compute_scoped()`.
|
||||
/// An execution context of a scope created by [`Context::compute_scoped()`](Context::compute_scoped).
|
||||
pub struct ComputeContext<'a, 'outer> {
|
||||
scope: Scope<'a, raw::EscapableHandleScope>,
|
||||
phantom_inner: PhantomData<&'a ()>,
|
||||
@ -526,7 +676,7 @@ impl<'a, 'b> ContextInternal<'a> for ComputeContext<'a, 'b> {
|
||||
|
||||
impl<'a, 'b> Context<'a> for ComputeContext<'a, 'b> {}
|
||||
|
||||
/// A view of the JS engine in the context of a function call.
|
||||
/// An execution context of a function call.
|
||||
///
|
||||
/// The type parameter `T` is the type of the `this`-binding.
|
||||
pub struct CallContext<'a, T: This> {
|
||||
@ -540,7 +690,7 @@ pub struct CallContext<'a, T: This> {
|
||||
impl<'a, T: This> UnwindSafe for CallContext<'a, T> {}
|
||||
|
||||
impl<'a, T: This> CallContext<'a, T> {
|
||||
/// Indicates whether the function was called via the JavaScript `[[Call]]` or `[[Construct]]` semantics.
|
||||
/// Indicates whether the function was called with `new`.
|
||||
pub fn kind(&self) -> CallKind {
|
||||
#[cfg(feature = "legacy-runtime")]
|
||||
let kind = self.info.kind();
|
||||
@ -627,13 +777,13 @@ impl<'a, T: This> ContextInternal<'a> for CallContext<'a, T> {
|
||||
|
||||
impl<'a, T: This> Context<'a> for CallContext<'a, T> {}
|
||||
|
||||
/// A shorthand for a `CallContext` with `this`-type `JsObject`.
|
||||
/// A shorthand for a [`CallContext`](CallContext) with `this`-type [`JsObject`](crate::types::JsObject).
|
||||
pub type FunctionContext<'a> = CallContext<'a, JsObject>;
|
||||
|
||||
/// An alias for `CallContext`, useful for indicating that the function is a method of a class.
|
||||
/// An alias for [`CallContext`](CallContext), useful for indicating that the function is a method of a class.
|
||||
pub type MethodContext<'a, T> = CallContext<'a, T>;
|
||||
|
||||
/// A view of the JS engine in the context of a task completion callback.
|
||||
/// An execution context of a task completion callback.
|
||||
pub struct TaskContext<'a> {
|
||||
/// We use an "inherited HandleScope" here because the C++ `neon::Task::complete`
|
||||
/// method sets up and tears down a `HandleScope` for us.
|
||||
|
||||
@ -2,13 +2,13 @@
|
||||
|
||||
use std::os::raw::c_void;
|
||||
|
||||
use context::internal::ContextInternal;
|
||||
use context::Context;
|
||||
use handle::{Handle, Managed};
|
||||
use crate::context::internal::ContextInternal;
|
||||
use crate::context::Context;
|
||||
use crate::handle::{Handle, Managed};
|
||||
use crate::types::*;
|
||||
use neon_runtime;
|
||||
use neon_runtime::raw;
|
||||
use std::sync::Arc;
|
||||
use types::*;
|
||||
|
||||
type EventContext<'a> = crate::context::TaskContext<'a>;
|
||||
|
||||
|
||||
@ -1,12 +1,12 @@
|
||||
use neon_runtime::raw::Env;
|
||||
use neon_runtime::tsfn::ThreadsafeFunction;
|
||||
|
||||
use context::{Context, TaskContext};
|
||||
use result::NeonResult;
|
||||
use crate::context::{Context, TaskContext};
|
||||
use crate::result::NeonResult;
|
||||
|
||||
type Callback = Box<dyn FnOnce(Env) + Send + 'static>;
|
||||
|
||||
/// Queue for scheduling Rust closures to execute on tge JavaScript main thread
|
||||
/// Queue for scheduling Rust closures to execute on the JavaScript main thread.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
|
||||
125
src/event/mod.rs
125
src/event/mod.rs
@ -1,3 +1,128 @@
|
||||
//! Exposes the JavaScript event loop for scheduling asynchronous events.
|
||||
//!
|
||||
//! ## The Event Loop
|
||||
//!
|
||||
//! The [_event loop_][event-loop] is how Node.js provides JavaScript programs
|
||||
//! access to concurrent events such as completion of [file][fs] or
|
||||
//! [network][net] operations, notification of scheduled [timers][timer], or
|
||||
//! receiving of messages from other [processes][process].
|
||||
//!
|
||||
//! When an asynchronous operation is started from JavaScript, it registers
|
||||
//! a JavaScript callback function to wait for the operation to complete. When
|
||||
//! the operation completes, the callback and the result data are added to an
|
||||
//! internal _event queue_ in the Node.js runtime so that the event can be
|
||||
//! processed in order.
|
||||
//!
|
||||
//! The event loop processes completed events one at a time in the JavaScript
|
||||
//! execution thread by calling the registered callback function with its result
|
||||
//! value as an argument.
|
||||
//!
|
||||
//! ## Creating Custom Events
|
||||
//!
|
||||
//! This module allows Neon programs to create new types of concurrent events
|
||||
//! in Rust and expose them to JavaScript as asynchronous functions.
|
||||
//!
|
||||
//! A common use for custom events is to run expensive or long-lived
|
||||
//! computations in a background thread without blocking the JavaScript
|
||||
//! thread. For example, using the [`psd` crate][psd-crate], a Neon program could
|
||||
//! asynchronously parse (potentially large) [PSD files][psd-file] in a
|
||||
//! background thread:
|
||||
//!
|
||||
//! ```
|
||||
//! # #[cfg(feature = "napi-1")] {
|
||||
//! # use neon::prelude::*;
|
||||
//! #
|
||||
//! # fn parse(filename: String, callback: Root<JsFunction>, queue: EventQueue) { }
|
||||
//! #
|
||||
//! fn parse_async(mut cx: FunctionContext) -> JsResult<JsUndefined> {
|
||||
//! // The types `String`, `Root<JsFunction>`, and `EventQueue` can all be
|
||||
//! // sent across threads.
|
||||
//! let filename = cx.argument::<JsString>(0)?.value(&mut cx);
|
||||
//! let callback = cx.argument::<JsFunction>(1)?.root(&mut cx);
|
||||
//! let queue = cx.queue();
|
||||
//!
|
||||
//! // Spawn a thread to complete the execution. This will _not_ block the
|
||||
//! // JavaScript event loop.
|
||||
//! std::thread::spawn(move || {
|
||||
//! // Do the heavy lifting inside the background thread.
|
||||
//! parse(filename, callback, queue);
|
||||
//! });
|
||||
//!
|
||||
//! Ok(cx.undefined())
|
||||
//! }
|
||||
//! # }
|
||||
//! ```
|
||||
//!
|
||||
//! (Note that this usage of [`spawn`](std::thread::spawn) makes use of Rust's
|
||||
//! [`move`][move] syntax to transfer ownership of data to the background
|
||||
//! thread.)
|
||||
//!
|
||||
//! Upon completion of its task, the background thread can use the JavaScript
|
||||
//! callback and the event queue to notify the main thread of the result:
|
||||
//!
|
||||
//! ```
|
||||
//! # #[cfg(feature = "napi-1")] {
|
||||
//! # use neon::prelude::*;
|
||||
//! # use psd::Psd;
|
||||
//! # use failure::Error;
|
||||
//! #
|
||||
//! fn psd_from_filename(filename: String) -> Result<Psd, Error> {
|
||||
//! Psd::from_bytes(&std::fs::read(&filename)?)
|
||||
//! }
|
||||
//!
|
||||
//! fn parse(filename: String, callback: Root<JsFunction>, queue: EventQueue) {
|
||||
//! let result = psd_from_filename(filename);
|
||||
//!
|
||||
//! // Send a closure as a task to be executed by the JavaScript event
|
||||
//! // queue. This _will_ block the event queue while executing.
|
||||
//! queue.send(move |mut cx| {
|
||||
//! let callback = callback.into_inner(&mut cx);
|
||||
//! let this = cx.undefined();
|
||||
//! let null = cx.null();
|
||||
//! let args = match result {
|
||||
//! Ok(psd) => {
|
||||
//! // Extract data from the parsed file.
|
||||
//! let width = cx.number(psd.width());
|
||||
//! let height = cx.number(psd.height());
|
||||
//!
|
||||
//! // Save the data in a result object.
|
||||
//! let obj = cx.empty_object();
|
||||
//! obj.set(&mut cx, "width", width)?;
|
||||
//! obj.set(&mut cx, "height", height)?;
|
||||
//! vec![
|
||||
//! cx.null().upcast::<JsValue>(),
|
||||
//! obj.upcast(),
|
||||
//! ]
|
||||
//! }
|
||||
//! Err(err) => {
|
||||
//! let err = cx.string(err.to_string());
|
||||
//! vec![
|
||||
//! err.upcast::<JsValue>(),
|
||||
//! ]
|
||||
//! }
|
||||
//! };
|
||||
//!
|
||||
//! callback.call(&mut cx, this, args)?;
|
||||
//!
|
||||
//! Ok(())
|
||||
//! });
|
||||
//! }
|
||||
//! # }
|
||||
//! ```
|
||||
//!
|
||||
//! ## See also
|
||||
//!
|
||||
//! 1. Panu Pitkamaki. [Event loop from 10,000ft][event-loop].
|
||||
//!
|
||||
//! [event-loop]: https://bytearcher.com/articles/event-loop-10-000ft/
|
||||
//! [fs]: https://nodejs.org/dist/latest/docs/api/fs.html
|
||||
//! [net]: https://nodejs.org/dist/latest/docs/api/net.html
|
||||
//! [process]: https://nodejs.org/dist/latest/docs/api/process.html
|
||||
//! [timer]: https://nodejs.org/dist/latest/docs/api/timers.html
|
||||
//! [move]: https://doc.rust-lang.org/std/keyword.move.html
|
||||
//! [psd-crate]: https://crates.io/crates/psd
|
||||
//! [psd-file]: https://www.adobe.com/devnet-apps/photoshop/fileformatashtml/
|
||||
|
||||
#[cfg(all(feature = "napi-4", feature = "event-queue-api"))]
|
||||
mod event_queue;
|
||||
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
use types::Value;
|
||||
use crate::types::Value;
|
||||
|
||||
pub trait SuperType<T: Value> {
|
||||
fn upcast_internal(T) -> Self;
|
||||
fn upcast_internal(v: T) -> Self;
|
||||
}
|
||||
|
||||
@ -1,33 +1,87 @@
|
||||
//! Safe _handles_ to managed JavaScript memory.
|
||||
//! References to garbage-collected JavaScript values.
|
||||
//!
|
||||
//! A _handle_ is a safe reference to a JavaScript value that is owned and managed
|
||||
//! by the JavaScript engine's memory management system (the garbage collector).
|
||||
//!
|
||||
//! Neon APIs that accept and return JavaScript values never use raw pointer types
|
||||
//! ([`*T`](pointer)) or reference types ([`&T`](reference)). Instead they use the
|
||||
//! special Neon type [`Handle`](Handle), which encapsulates a JavaScript
|
||||
//! [`Value`](crate::types::Value) and ensures that Rust only maintains access to
|
||||
//! the value while it is guaranteed to be valid.
|
||||
//!
|
||||
//! ## Working with Handles
|
||||
//!
|
||||
//! The `Handle<T>` type automatically dereferences to `T` (via the standard
|
||||
//! [`Deref`](std::ops::Deref) trait), so you can call `T`'s methods on a value of
|
||||
//! type `Handle<T>`. For example, we can call
|
||||
//! [`JsNumber::value()`](crate::types::JsNumber::value) on a `Handle<JsNumber>`:
|
||||
//!
|
||||
//! ```
|
||||
//! # #[cfg(feature = "napi-1")] {
|
||||
//! # use neon::prelude::*;
|
||||
//! # fn run(mut cx: FunctionContext) -> JsResult<JsUndefined> {
|
||||
//! let n: Handle<JsNumber> = cx.argument(0)?;
|
||||
//! let v = n.value(&mut cx); // JsNumber::value()
|
||||
//! # Ok(cx.undefined())
|
||||
//! # }
|
||||
//! # }
|
||||
//! ```
|
||||
//!
|
||||
//! ## Example
|
||||
//!
|
||||
//! This Neon function takes an object as its argument, extracts two properties,
|
||||
//! `width` and `height`, and multiplies them together as numbers. Each JavaScript
|
||||
//! value in the calculation is stored locally in a `Handle`.
|
||||
//!
|
||||
//! ```
|
||||
//! # #[cfg(feature = "napi-1")] {
|
||||
//! # use neon::prelude::*;
|
||||
//! fn area(mut cx: FunctionContext) -> JsResult<JsNumber> {
|
||||
//! let rect: Handle<JsObject> = cx.argument(0)?;
|
||||
//!
|
||||
//! let width: Handle<JsNumber> = rect
|
||||
//! .get(&mut cx, "width")?
|
||||
//! .downcast_or_throw(&mut cx)?;
|
||||
//! let w: f64 = width.value(&mut cx);
|
||||
//!
|
||||
//! let height: Handle<JsNumber> = rect
|
||||
//! .get(&mut cx, "height")?
|
||||
//! .downcast_or_throw(&mut cx)?;
|
||||
//! let h: f64 = height.value(&mut cx);
|
||||
//!
|
||||
//! Ok(cx.number(w * h))
|
||||
//! }
|
||||
//! # }
|
||||
//! ```
|
||||
|
||||
pub(crate) mod internal;
|
||||
|
||||
#[cfg(feature = "napi-1")]
|
||||
mod root;
|
||||
pub(crate) mod root;
|
||||
|
||||
#[cfg(feature = "napi-1")]
|
||||
pub use self::root::Root;
|
||||
|
||||
use self::internal::SuperType;
|
||||
use context::internal::Env;
|
||||
use context::Context;
|
||||
use crate::context::internal::Env;
|
||||
use crate::context::Context;
|
||||
use crate::result::{JsResult, JsResultExt};
|
||||
use crate::types::Value;
|
||||
use neon_runtime;
|
||||
use neon_runtime::raw;
|
||||
use result::{JsResult, JsResultExt};
|
||||
use std::error::Error;
|
||||
use std::fmt::{self, Debug, Display};
|
||||
use std::marker::PhantomData;
|
||||
use std::ops::{Deref, DerefMut};
|
||||
use types::Value;
|
||||
|
||||
/// The trait of data that is managed by the JS garbage collector and can only be accessed via handles.
|
||||
/// The trait of data owned by the JavaScript engine and that can only be accessed via handles.
|
||||
pub trait Managed: Copy {
|
||||
fn to_raw(self) -> raw::Local;
|
||||
|
||||
fn from_raw(env: Env, h: raw::Local) -> Self;
|
||||
}
|
||||
|
||||
/// A safely rooted _handle_ to a JS value in memory that is managed by the garbage collector.
|
||||
/// A handle to a JavaScript value that is owned by the JavaScript engine.
|
||||
#[repr(C)]
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
pub struct Handle<'a, T: Managed + 'a> {
|
||||
@ -84,7 +138,7 @@ impl<F: Value, T: Value> Display for DowncastError<F, T> {
|
||||
|
||||
impl<F: Value, T: Value> Error for DowncastError<F, T> {}
|
||||
|
||||
/// The result of a call to `Handle::downcast()`.
|
||||
/// The result of a call to [`Handle::downcast()`](Handle::downcast).
|
||||
pub type DowncastResult<'a, F, T> = Result<Handle<'a, T>, DowncastError<F, T>>;
|
||||
|
||||
impl<'a, F: Value, T: Value> JsResultExt<'a, T> for DowncastResult<'a, F, T> {
|
||||
|
||||
@ -1,25 +1,40 @@
|
||||
use std::ffi::c_void;
|
||||
use std::marker::PhantomData;
|
||||
use std::mem::ManuallyDrop;
|
||||
use std::sync::Arc;
|
||||
|
||||
use neon_runtime::reference;
|
||||
#[cfg(feature = "napi-6")]
|
||||
use neon_runtime::tsfn::ThreadsafeFunction;
|
||||
|
||||
use context::Context;
|
||||
use handle::Handle;
|
||||
use object::Object;
|
||||
use types::boxed::Finalize;
|
||||
use crate::context::Context;
|
||||
use crate::handle::Handle;
|
||||
#[cfg(feature = "napi-6")]
|
||||
use crate::lifecycle::InstanceData;
|
||||
use crate::object::Object;
|
||||
use crate::types::boxed::Finalize;
|
||||
|
||||
#[repr(transparent)]
|
||||
#[derive(Clone)]
|
||||
struct NapiRef(*mut c_void);
|
||||
pub(crate) struct NapiRef(*mut c_void);
|
||||
|
||||
/// `Root<T>` holds a reference to a `JavaScript` object and prevents it from
|
||||
/// being garbage collected. `Root<T>` may be sent across threads, but the
|
||||
/// referenced objected may only be accessed on the JavaScript thread that
|
||||
/// created it.
|
||||
#[repr(transparent)]
|
||||
// # Safety
|
||||
// `NapiRef` are reference counted types that allow references to JavaScript objects
|
||||
// to outlive a `Context` (`napi_env`). Since access is serialized by obtaining a
|
||||
// `Context`, they are both `Send` and `Sync`.
|
||||
// https://nodejs.org/api/n-api.html#n_api_references_to_objects_with_a_lifespan_longer_than_that_of_the_native_method
|
||||
unsafe impl Send for NapiRef {}
|
||||
unsafe impl Sync for NapiRef {}
|
||||
|
||||
/// A thread-safe handle that holds a reference to a JavaScript object and
|
||||
/// prevents it from being garbage collected.
|
||||
///
|
||||
/// A `Root<T>` may be sent across threads, but the referenced object may
|
||||
/// only be accessed on the JavaScript thread that created it.
|
||||
pub struct Root<T> {
|
||||
internal: NapiRef,
|
||||
#[cfg(feature = "napi-6")]
|
||||
drop_queue: Arc<ThreadsafeFunction<NapiRef>>,
|
||||
_phantom: PhantomData<T>,
|
||||
}
|
||||
|
||||
@ -40,15 +55,19 @@ impl<T: Object> Root<T> {
|
||||
/// garbage collected until the `Root` is dropped. A `Root<T>` may only
|
||||
/// be dropped on the JavaScript thread that created it.
|
||||
///
|
||||
/// The caller _must_ ensure `Root::into_inner` or `Root::drop` is called
|
||||
/// The caller _should_ ensure `Root::into_inner` or `Root::drop` is called
|
||||
/// to properly dispose of the `Root<T>`. If the value is dropped without
|
||||
/// calling one of these methods, it will *panic*.
|
||||
/// calling one of these methods:
|
||||
/// * N-API < 6, Neon will `panic` to notify of the leak
|
||||
/// * N-API >= 6, Neon will drop from a global queue at a runtime cost
|
||||
pub fn new<'a, C: Context<'a>>(cx: &mut C, value: &T) -> Self {
|
||||
let env = cx.env().to_raw();
|
||||
let internal = unsafe { reference::new(env, value.to_raw()) };
|
||||
|
||||
Self {
|
||||
internal: NapiRef(internal as *mut _),
|
||||
#[cfg(feature = "napi-6")]
|
||||
drop_queue: InstanceData::drop_queue(cx),
|
||||
_phantom: PhantomData,
|
||||
}
|
||||
}
|
||||
@ -75,6 +94,8 @@ impl<T: Object> Root<T> {
|
||||
|
||||
Self {
|
||||
internal: self.internal.clone(),
|
||||
#[cfg(feature = "napi-6")]
|
||||
drop_queue: Arc::clone(&self.drop_queue),
|
||||
_phantom: PhantomData,
|
||||
}
|
||||
}
|
||||
@ -124,6 +145,7 @@ impl<T: Object> Finalize for Root<T> {
|
||||
}
|
||||
|
||||
impl<T> Drop for Root<T> {
|
||||
#[cfg(not(feature = "napi-6"))]
|
||||
fn drop(&mut self) {
|
||||
// Destructors are called during stack unwinding, prevent a double
|
||||
// panic and instead prefer to leak.
|
||||
@ -140,4 +162,9 @@ impl<T> Drop for Root<T> {
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "napi-6")]
|
||||
fn drop(&mut self) {
|
||||
let _ = self.drop_queue.call(self.internal.clone(), None);
|
||||
}
|
||||
}
|
||||
|
||||
133
src/lib.rs
133
src/lib.rs
@ -1,16 +1,83 @@
|
||||
//! The [Neon](https://www.neon-bindings.com/) crate provides bindings for writing Node.js plugins with a safe and fast Rust API.
|
||||
|
||||
extern crate cslice;
|
||||
extern crate neon_runtime;
|
||||
extern crate semver;
|
||||
extern crate smallvec;
|
||||
|
||||
#[cfg(feature = "proc-macros")]
|
||||
extern crate neon_macros;
|
||||
|
||||
#[cfg(test)]
|
||||
#[macro_use]
|
||||
extern crate lazy_static;
|
||||
//! The [Neon][neon] crate provides bindings for writing [Node.js addons][addons]
|
||||
//! (i.e., dynamically-loaded binary modules) with a safe and fast Rust API.
|
||||
//!
|
||||
//! ## Getting Started
|
||||
//!
|
||||
//! You can conveniently bootstrap a new Neon project with the Neon project
|
||||
//! generator. You don't need to install anything special on your machine as
|
||||
//! long as you have a [supported version of Node and Rust][supported] on
|
||||
//! your system.
|
||||
//!
|
||||
//! To start a new project, open a terminal in the directory where you would
|
||||
//! like to place the project, and run at the command prompt:
|
||||
//!
|
||||
//! ```text
|
||||
//! % npm init neon my-project
|
||||
//! ... answer the user prompts ...
|
||||
//! ✨ Created Neon project `my-project`. Happy 🦀 hacking! ✨
|
||||
//! ```
|
||||
//!
|
||||
//! where `my-project` can be any name you like for the project. This will
|
||||
//! run the Neon project generator, prompting you with a few questions and
|
||||
//! placing a simple but working Neon project in a subdirectory called
|
||||
//! `my-project` (or whatever name you chose).
|
||||
//!
|
||||
//! You can then install and build the project by changing into the project
|
||||
//! directory and running the standard Node installation command:
|
||||
//!
|
||||
//! ```text
|
||||
//! % cd my-project
|
||||
//! % npm install
|
||||
//! % node
|
||||
//! > require(".").hello()
|
||||
//! 'hello node'
|
||||
//! ```
|
||||
//!
|
||||
//! You can look in the project's generated `README.md` for more details on
|
||||
//! the project structure.
|
||||
//!
|
||||
//! ## Example
|
||||
//!
|
||||
//! The generated `src/lib.rs` contains a function annotated with the
|
||||
//! [`#[neon::main]`](main) attribute, marking it as the module's main entry
|
||||
//! point to be executed when the module is loaded. This function can have
|
||||
//! any name but is conventionally called `main`:
|
||||
//!
|
||||
//! ```no_run
|
||||
//! # #[cfg(feature = "neon-macros")] {
|
||||
//! # use neon::prelude::*;
|
||||
//! #
|
||||
//! # fn hello(mut cx: FunctionContext) -> JsResult<JsString> {
|
||||
//! # Ok(cx.string("hello node"))
|
||||
//! # }
|
||||
//! #
|
||||
//! #[neon::main]
|
||||
//! fn main(mut cx: ModuleContext) -> NeonResult<()> {
|
||||
//! cx.export_function("hello", hello)?;
|
||||
//! Ok(())
|
||||
//! }
|
||||
//! # }
|
||||
//! ```
|
||||
//!
|
||||
//! The example code generated by `npm init neon` exports a single
|
||||
//! function via [`ModuleContext::export_function`](context::ModuleContext::export_function).
|
||||
//! The `hello` function is defined just above `main` in `src/lib.rs`:
|
||||
//!
|
||||
//! ```
|
||||
//! # use neon::prelude::*;
|
||||
//! #
|
||||
//! fn hello(mut cx: FunctionContext) -> JsResult<JsString> {
|
||||
//! Ok(cx.string("hello node"))
|
||||
//! }
|
||||
//! ```
|
||||
//!
|
||||
//! The `hello` function takes a [`FunctionContext`](context::FunctionContext) and
|
||||
//! returns a JavaScript string. Because all Neon functions can potentially throw a
|
||||
//! JavaScript exception, the return type is wrapped in a [`JsResult`](result::JsResult).
|
||||
//!
|
||||
//! [neon]: https://www.neon-bindings.com/
|
||||
//! [addons]: https://nodejs.org/api/addons.html
|
||||
//! [supported]: https://github.com/neon-bindings/neon#platform-support
|
||||
|
||||
pub mod borrow;
|
||||
pub mod context;
|
||||
@ -23,6 +90,7 @@ pub mod handle;
|
||||
pub mod meta;
|
||||
pub mod object;
|
||||
pub mod prelude;
|
||||
#[cfg(feature = "napi-1")]
|
||||
pub mod reflect;
|
||||
pub mod result;
|
||||
#[cfg(feature = "legacy-runtime")]
|
||||
@ -35,27 +103,14 @@ pub mod macro_internal;
|
||||
#[cfg(feature = "proc-macros")]
|
||||
pub use neon_macros::*;
|
||||
|
||||
#[cfg(feature = "napi-6")]
|
||||
mod lifecycle;
|
||||
|
||||
#[cfg(all(feature = "legacy-runtime", feature = "napi-1"))]
|
||||
compile_error!("Cannot enable both `legacy-runtime` and `napi-*` features.\n\nTo use `napi-*`, disable `legacy-runtime` by setting `default-features` to `false` in Cargo.toml\nor with cargo's --no-default-features flag.");
|
||||
|
||||
#[cfg(all(feature = "napi-1", not(feature = "legacy-runtime")))]
|
||||
/// Register the current crate as a Node module, providing startup
|
||||
/// logic for initializing the module object at runtime.
|
||||
///
|
||||
/// The first argument is a pattern bound to a `neon::context::ModuleContext`. This
|
||||
/// is usually bound to a mutable variable `mut cx`, which can then be used to
|
||||
/// pass to Neon APIs that require mutable access to an execution context.
|
||||
///
|
||||
/// Example:
|
||||
///
|
||||
/// ```rust,ignore
|
||||
/// register_module!(mut cx, {
|
||||
/// cx.export_function("foo", foo)?;
|
||||
/// cx.export_function("bar", bar)?;
|
||||
/// cx.export_function("baz", baz)?;
|
||||
/// Ok(())
|
||||
/// });
|
||||
/// ```
|
||||
#[doc(hidden)]
|
||||
#[macro_export]
|
||||
macro_rules! register_module {
|
||||
($module:pat, $init:block) => {
|
||||
@ -96,13 +151,19 @@ macro_rules! register_module {
|
||||
///
|
||||
/// Example:
|
||||
///
|
||||
/// ```rust,ignore
|
||||
/// ```
|
||||
/// # #[cfg(feature = "n-api")] {
|
||||
/// # use neon::prelude::*;
|
||||
/// # fn foo(mut cx: FunctionContext) -> JsResult<JsUndefined> { Ok(cx.undefined()) }
|
||||
/// # fn bar(mut cx: FunctionContext) -> JsResult<JsUndefined> { Ok(cx.undefined()) }
|
||||
/// # fn baz(mut cx: FunctionContext) -> JsResult<JsUndefined> { Ok(cx.undefined()) }
|
||||
/// register_module!(mut cx, {
|
||||
/// cx.export_function("foo", foo)?;
|
||||
/// cx.export_function("bar", bar)?;
|
||||
/// cx.export_function("baz", baz)?;
|
||||
/// Ok(())
|
||||
/// });
|
||||
/// # }
|
||||
/// ```
|
||||
#[macro_export]
|
||||
macro_rules! register_module {
|
||||
@ -293,7 +354,6 @@ macro_rules! impl_managed {
|
||||
/// Example:
|
||||
///
|
||||
/// ```rust
|
||||
/// # #[macro_use] extern crate neon;
|
||||
/// # use neon::prelude::*;
|
||||
/// # fn main() {}
|
||||
/// pub struct Greeter {
|
||||
@ -381,7 +441,7 @@ macro_rules! neon_stringify {
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
extern crate rustversion;
|
||||
use lazy_static::lazy_static;
|
||||
use semver::Version;
|
||||
use std::path::{Path, PathBuf};
|
||||
use std::process::Command;
|
||||
@ -448,10 +508,7 @@ mod tests {
|
||||
|
||||
log("static_test");
|
||||
|
||||
run(
|
||||
"cargo test --release",
|
||||
&project_root().join("test").join("static"),
|
||||
);
|
||||
run("cargo test", &project_root().join("test").join("static"));
|
||||
}
|
||||
|
||||
// Only run the static tests in Beta. This will catch changes to error reporting
|
||||
@ -505,7 +562,7 @@ mod tests {
|
||||
log("dynamic_cargo_test");
|
||||
|
||||
let test_dynamic_cargo = project_root().join("test").join("dynamic").join("native");
|
||||
run("cargo test --release", &test_dynamic_cargo);
|
||||
run("cargo test", &test_dynamic_cargo);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
||||
76
src/lifecycle.rs
Normal file
76
src/lifecycle.rs
Normal file
@ -0,0 +1,76 @@
|
||||
//! # Environment life cycle APIs
|
||||
//!
|
||||
//! These APIs map to the life cycle of a specific "Agent" or self-contained
|
||||
//! environment. If a Neon module is loaded multiple times (Web Workers, worker
|
||||
//! threads), these API will be handle data associated with a specific instance.
|
||||
//!
|
||||
//! See the [N-API Lifecycle][npai-docs] documentation for more details.
|
||||
//!
|
||||
//! [napi-docs]: https://nodejs.org/api/n-api.html#n_api_environment_life_cycle_apis
|
||||
|
||||
use std::mem;
|
||||
use std::sync::Arc;
|
||||
|
||||
use neon_runtime::raw::Env;
|
||||
use neon_runtime::reference;
|
||||
use neon_runtime::tsfn::ThreadsafeFunction;
|
||||
|
||||
use crate::context::Context;
|
||||
use crate::handle::root::NapiRef;
|
||||
|
||||
/// `InstanceData` holds Neon data associated with a particular instance of a
|
||||
/// native module. If a module is loaded multiple times (e.g., worker threads), this
|
||||
/// data will be unique per instance.
|
||||
pub(crate) struct InstanceData {
|
||||
/// Used to free `Root` in the same JavaScript environment that created it
|
||||
///
|
||||
/// _Design Note_: An `Arc` ensures the `ThreadsafeFunction` outlives the unloading
|
||||
/// of a module. Since it is unlikely that modules will be re-loaded frequently, this
|
||||
/// could be replaced with a leaked `&'static ThreadsafeFunction<NapiRef>`. However,
|
||||
/// given the cost of FFI, this optimization is omitted until the cost of an
|
||||
/// `Arc` is demonstrated as significant.
|
||||
drop_queue: Arc<ThreadsafeFunction<NapiRef>>,
|
||||
}
|
||||
|
||||
fn drop_napi_ref(env: Option<Env>, data: NapiRef) {
|
||||
if let Some(env) = env {
|
||||
unsafe {
|
||||
reference::unreference(env, mem::transmute(data));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl InstanceData {
|
||||
/// Return the data associated with this module instance, lazily initializing if
|
||||
/// necessary.
|
||||
///
|
||||
/// # Safety
|
||||
/// No additional locking (e.g., `Mutex`) is necessary because holding a
|
||||
/// `Context` reference ensures serialized access.
|
||||
pub(crate) fn get<'a, C: Context<'a>>(cx: &mut C) -> &'a mut InstanceData {
|
||||
let env = cx.env().to_raw();
|
||||
let data =
|
||||
unsafe { neon_runtime::lifecycle::get_instance_data::<InstanceData>(env).as_mut() };
|
||||
|
||||
if let Some(data) = data {
|
||||
return data;
|
||||
}
|
||||
|
||||
let drop_queue = unsafe {
|
||||
let mut queue = ThreadsafeFunction::new(env, drop_napi_ref);
|
||||
queue.unref(env);
|
||||
queue
|
||||
};
|
||||
|
||||
let data = InstanceData {
|
||||
drop_queue: Arc::new(drop_queue),
|
||||
};
|
||||
|
||||
unsafe { &mut *neon_runtime::lifecycle::set_instance_data(env, data) }
|
||||
}
|
||||
|
||||
/// Helper to return a reference to the `drop_queue` field of `InstanceData`
|
||||
pub(crate) fn drop_queue<'a, C: Context<'a>>(cx: &mut C) -> Arc<ThreadsafeFunction<NapiRef>> {
|
||||
Arc::clone(&InstanceData::get(cx).drop_queue)
|
||||
}
|
||||
}
|
||||
@ -1,10 +1,10 @@
|
||||
//! Internals needed by macros. These have to be exported for the macros to work
|
||||
pub use context::internal::{initialize_module, Env};
|
||||
pub use crate::context::internal::{initialize_module, Env};
|
||||
/// but are subject to change and should never be explicitly used.
|
||||
|
||||
#[cfg(feature = "legacy-runtime")]
|
||||
// Used by the class macro.
|
||||
pub use object::class::internal::{
|
||||
pub use crate::object::class::internal::{
|
||||
AllocateCallback, ConstructCallback, ConstructorCallCallback, MethodCallback,
|
||||
};
|
||||
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
//! Utilities exposing metadata about the Neon version and build.
|
||||
//! Metadata about the Neon version and build.
|
||||
|
||||
use semver::Version;
|
||||
|
||||
@ -11,7 +11,7 @@ pub const MAJOR: &str = env!("CARGO_PKG_VERSION_MAJOR");
|
||||
/// The Neon minor version.
|
||||
pub const MINOR: &str = env!("CARGO_PKG_VERSION_MINOR");
|
||||
|
||||
/// The neon patch version.
|
||||
/// The Neon patch version.
|
||||
pub const PATCH: &str = env!("CARGO_PKG_VERSION_PATCH");
|
||||
|
||||
/// Produces a `semver::Version` data structure representing the Neon version.
|
||||
|
||||
@ -1,15 +1,15 @@
|
||||
use super::{Callback, Class, ClassInternal};
|
||||
use context::internal::{ContextInternal, Env};
|
||||
use context::{CallContext, CallbackInfo, Context};
|
||||
use handle::{Handle, Managed};
|
||||
use crate::context::internal::{ContextInternal, Env};
|
||||
use crate::context::{CallContext, CallbackInfo, Context};
|
||||
use crate::handle::{Handle, Managed};
|
||||
use crate::result::{JsResult, NeonResult, Throw};
|
||||
use crate::types::error::convert_panics;
|
||||
use crate::types::{build, JsFunction, JsObject, JsUndefined, JsValue};
|
||||
use neon_runtime;
|
||||
use neon_runtime::raw;
|
||||
use result::{JsResult, NeonResult, Throw};
|
||||
use std::mem;
|
||||
use std::os::raw::c_void;
|
||||
use std::ptr::null_mut;
|
||||
use types::error::convert_panics;
|
||||
use types::{build, JsFunction, JsObject, JsUndefined, JsValue};
|
||||
|
||||
#[repr(C)]
|
||||
pub struct MethodCallback<T: Class>(pub fn(CallContext<T>) -> JsResult<JsValue>);
|
||||
|
||||
@ -5,21 +5,21 @@ pub(crate) mod internal;
|
||||
use self::internal::{
|
||||
AllocateCallback, ClassMetadata, ConstructCallback, ConstructorCallCallback, MethodCallback,
|
||||
};
|
||||
use borrow::{Borrow, BorrowMut, LoanError, Ref, RefMut};
|
||||
use context::internal::Env;
|
||||
use context::{Context, Lock};
|
||||
use handle::{Handle, Managed};
|
||||
use crate::borrow::{Borrow, BorrowMut, LoanError, Ref, RefMut};
|
||||
use crate::context::internal::Env;
|
||||
use crate::context::{Context, Lock};
|
||||
use crate::handle::{Handle, Managed};
|
||||
use crate::object::{Object, This};
|
||||
use crate::result::{JsResult, NeonResult, Throw};
|
||||
use crate::types::internal::{Callback, ValueInternal};
|
||||
use crate::types::{build, JsFunction, JsValue, Value};
|
||||
use neon_runtime;
|
||||
use neon_runtime::raw;
|
||||
use object::{Object, This};
|
||||
use result::{JsResult, NeonResult, Throw};
|
||||
use std::any::{Any, TypeId};
|
||||
use std::collections::HashMap;
|
||||
use std::mem;
|
||||
use std::os::raw::c_void;
|
||||
use std::slice;
|
||||
use types::internal::{Callback, ValueInternal};
|
||||
use types::{build, JsFunction, JsValue, Value};
|
||||
|
||||
pub(crate) struct ClassMap {
|
||||
map: HashMap<TypeId, ClassMetadata>,
|
||||
|
||||
@ -9,12 +9,12 @@ pub use self::traits::*;
|
||||
|
||||
#[cfg(feature = "legacy-runtime")]
|
||||
mod traits {
|
||||
use context::Context;
|
||||
use handle::{Handle, Managed};
|
||||
use crate::context::Context;
|
||||
use crate::handle::{Handle, Managed};
|
||||
use crate::result::{JsResult, NeonResult, Throw};
|
||||
use crate::types::utf8::Utf8;
|
||||
use crate::types::{build, JsArray, JsValue, Value};
|
||||
use neon_runtime::raw;
|
||||
use result::{JsResult, NeonResult, Throw};
|
||||
use types::utf8::Utf8;
|
||||
use types::{build, JsArray, JsValue, Value};
|
||||
|
||||
/// A property key in a JavaScript object.
|
||||
pub trait PropertyKey {
|
||||
@ -95,18 +95,18 @@ mod traits {
|
||||
|
||||
#[cfg(feature = "napi-1")]
|
||||
mod traits {
|
||||
use context::internal::Env;
|
||||
use context::Context;
|
||||
use handle::{Handle, Managed, Root};
|
||||
use crate::context::internal::Env;
|
||||
use crate::context::Context;
|
||||
use crate::handle::{Handle, Managed, Root};
|
||||
use crate::result::{NeonResult, Throw};
|
||||
use crate::types::utf8::Utf8;
|
||||
use crate::types::{build, JsValue, Value};
|
||||
use neon_runtime::raw;
|
||||
use result::{NeonResult, Throw};
|
||||
use types::utf8::Utf8;
|
||||
use types::{build, JsValue, Value};
|
||||
|
||||
#[cfg(feature = "napi-6")]
|
||||
use result::JsResult;
|
||||
use crate::result::JsResult;
|
||||
#[cfg(feature = "napi-6")]
|
||||
use types::JsArray;
|
||||
use crate::types::JsArray;
|
||||
|
||||
/// A property key in a JavaScript object.
|
||||
pub trait PropertyKey {
|
||||
|
||||
@ -1,30 +1,30 @@
|
||||
//! A convenience module that re-exports the most commonly-used Neon APIs.
|
||||
//! Convenience module for the most common Neon imports.
|
||||
|
||||
pub use crate::borrow::{Borrow, BorrowMut};
|
||||
pub use crate::context::{
|
||||
CallContext, CallKind, ComputeContext, Context, ExecuteContext, FunctionContext, MethodContext,
|
||||
ModuleContext, TaskContext,
|
||||
};
|
||||
#[cfg(feature = "legacy-runtime")]
|
||||
pub use crate::declare_types;
|
||||
#[cfg(all(not(feature = "napi-1"), feature = "event-handler-api"))]
|
||||
pub use crate::event::EventHandler;
|
||||
#[cfg(all(feature = "napi-4", feature = "event-queue-api"))]
|
||||
pub use crate::event::{EventQueue, EventQueueError};
|
||||
pub use crate::handle::Handle;
|
||||
#[cfg(feature = "legacy-runtime")]
|
||||
pub use crate::object::Class;
|
||||
pub use crate::object::Object;
|
||||
pub use crate::register_module;
|
||||
pub use crate::result::{JsResult, JsResultExt, NeonResult};
|
||||
#[cfg(feature = "legacy-runtime")]
|
||||
pub use crate::task::Task;
|
||||
pub use crate::types::{
|
||||
BinaryData, JsArray, JsArrayBuffer, JsBoolean, JsBuffer, JsError, JsFunction, JsNull, JsNumber,
|
||||
JsObject, JsString, JsUndefined, JsValue, Value,
|
||||
};
|
||||
#[cfg(feature = "napi-1")]
|
||||
pub use crate::{
|
||||
handle::Root,
|
||||
types::boxed::{Finalize, JsBox},
|
||||
};
|
||||
pub use borrow::{Borrow, BorrowMut};
|
||||
pub use context::{
|
||||
CallContext, CallKind, ComputeContext, Context, ExecuteContext, FunctionContext, MethodContext,
|
||||
ModuleContext, TaskContext,
|
||||
};
|
||||
#[cfg(all(not(feature = "napi-1"), feature = "event-handler-api"))]
|
||||
pub use event::EventHandler;
|
||||
pub use handle::Handle;
|
||||
#[cfg(feature = "legacy-runtime")]
|
||||
pub use object::Class;
|
||||
pub use object::Object;
|
||||
pub use result::{JsResult, JsResultExt, NeonResult};
|
||||
#[cfg(feature = "legacy-runtime")]
|
||||
pub use task::Task;
|
||||
pub use types::{
|
||||
BinaryData, JsArray, JsArrayBuffer, JsBoolean, JsBuffer, JsError, JsFunction, JsNull, JsNumber,
|
||||
JsObject, JsString, JsUndefined, JsValue, Value,
|
||||
};
|
||||
|
||||
@ -1,9 +1,10 @@
|
||||
use context::Context;
|
||||
use handle::{Handle, Managed};
|
||||
use result::JsResult;
|
||||
use types::{build, JsString, JsValue};
|
||||
//! Exposes JavaScript's reflection API to Rust.
|
||||
|
||||
use crate::context::Context;
|
||||
use crate::handle::{Handle, Managed};
|
||||
use crate::result::JsResult;
|
||||
use crate::types::{build, JsString, JsValue};
|
||||
|
||||
#[cfg(feature = "napi-1")]
|
||||
pub fn eval<'a, 'b, C: Context<'a>>(
|
||||
cx: &mut C,
|
||||
script: Handle<'b, JsString>,
|
||||
|
||||
@ -1,16 +1,51 @@
|
||||
//! Types and traits for working with JavaScript exceptions.
|
||||
//! Represents JavaScript exceptions as a Rust [`Result`](std::result) type.
|
||||
//!
|
||||
//! Most interactions with the JavaScript engine can throw a JavaScript exception. Neon APIs
|
||||
//! that can throw an exception are called _throwing APIs_ and return the type
|
||||
//! [`NeonResult`](NeonResult) (or its shorthand [`JsResult`](JsResult)).
|
||||
//!
|
||||
//! When a throwing API triggers a JavaScript exception, it returns an [Err](std::result::Result::Err)
|
||||
//! result. This indicates that the thread associated with the [`Context`](crate::context::Context)
|
||||
//! is now throwing, and allows Rust code to perform any cleanup. See the
|
||||
//! [`neon::context`](crate::context) module documentation for more about
|
||||
//! [contexts and exceptions](crate::context#throwing-exceptions).
|
||||
//!
|
||||
//! Typically, Neon code can manage JavaScript exceptions correctly and conveniently by
|
||||
//! using Rust's [question mark (`?`)][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.
|
||||
//!
|
||||
//! ## Example
|
||||
//!
|
||||
//! Neon functions typically use [`JsResult`](JsResult) for their return type. This
|
||||
//! example defines a function that extracts a property called `"message"` from an object,
|
||||
//! throwing an exception if the argument is not of the right type or extracting the property
|
||||
//! fails:
|
||||
//!
|
||||
//! ```
|
||||
//! # use neon::prelude::*;
|
||||
//! fn get_message(mut cx: FunctionContext) -> JsResult<JsValue> {
|
||||
//! let obj: Handle<JsObject> = cx.argument(0)?;
|
||||
//! let prop: Handle<JsValue> = obj.get(&mut cx, "message")?;
|
||||
//! Ok(prop)
|
||||
//! }
|
||||
//! ```
|
||||
//!
|
||||
//! [question-mark]: https://doc.rust-lang.org/edition-guide/rust-2018/error-handling-and-panics/the-question-mark-operator-for-easier-error-handling.html
|
||||
|
||||
use context::Context;
|
||||
use handle::Handle;
|
||||
use crate::context::Context;
|
||||
use crate::handle::Handle;
|
||||
use crate::types::Value;
|
||||
use std::fmt::{Display, Formatter, Result as FmtResult};
|
||||
use types::Value;
|
||||
|
||||
/// An error sentinel type used by `NeonResult` (and `JsResult`) to indicate that the JavaScript engine
|
||||
/// has entered into a throwing state.
|
||||
/// A [unit type][unit] indicating that the JavaScript thread is throwing an exception.
|
||||
///
|
||||
/// `Throw` deliberately does not implement `std::error::Error`, because it's generally not a good idea
|
||||
/// to chain JavaScript exceptions with other kinds of Rust errors, since entering into the throwing
|
||||
/// state means that the JavaScript engine is unavailable until the exception is handled.
|
||||
/// `Throw` deliberately does not implement [`std::error::Error`](std::error::Error). It's
|
||||
/// not recommended to chain JavaScript exceptions with other kinds of Rust errors,
|
||||
/// since throwing means that the JavaScript thread is unavailable until the exception
|
||||
/// is handled.
|
||||
///
|
||||
/// [unit]: https://doc.rust-lang.org/book/ch05-01-defining-structs.html#unit-like-structs-without-any-fields
|
||||
#[derive(Debug)]
|
||||
pub struct Throw;
|
||||
|
||||
@ -20,14 +55,14 @@ impl Display for Throw {
|
||||
}
|
||||
}
|
||||
|
||||
/// The result of a computation that might send the JS engine into a throwing state.
|
||||
/// The result type for throwing APIs.
|
||||
pub type NeonResult<T> = Result<T, Throw>;
|
||||
|
||||
/// The result of a computation that produces a JavaScript value and might send the JS engine into a throwing state.
|
||||
/// Shorthand for a [`NeonResult`](NeonResult) that produces JavaScript values.
|
||||
pub type JsResult<'b, T> = NeonResult<Handle<'b, T>>;
|
||||
|
||||
/// An extension trait for `Result` values that can be converted into `JsResult` values by throwing a JavaScript
|
||||
/// exception in the error case.
|
||||
/// Extension trait for converting Rust [`Result`](std::result::Result) values
|
||||
/// into [`JsResult`](JsResult) values by throwing JavaScript exceptions.
|
||||
pub trait JsResultExt<'a, V: Value> {
|
||||
fn or_throw<'b, C: Context<'b>>(self, cx: &mut C) -> JsResult<'a, V>;
|
||||
}
|
||||
|
||||
@ -3,12 +3,12 @@
|
||||
use std::marker::{Send, Sized};
|
||||
use std::os::raw::c_void;
|
||||
|
||||
use context::TaskContext;
|
||||
use handle::{Handle, Managed};
|
||||
use crate::context::TaskContext;
|
||||
use crate::handle::{Handle, Managed};
|
||||
use crate::result::JsResult;
|
||||
use crate::types::{JsFunction, Value};
|
||||
use neon_runtime;
|
||||
use neon_runtime::raw;
|
||||
use result::JsResult;
|
||||
use types::{JsFunction, Value};
|
||||
|
||||
/// A Rust task that can be executed in the background on the Node thread pool.
|
||||
pub trait Task: Send + Sized + 'static {
|
||||
|
||||
@ -1,21 +1,21 @@
|
||||
//! Types and traits representing binary JavaScript data.
|
||||
|
||||
use borrow::internal::Pointer;
|
||||
use borrow::{Borrow, BorrowMut, LoanError, Ref, RefMut};
|
||||
use context::internal::Env;
|
||||
use context::{Context, Lock};
|
||||
use crate::borrow::internal::Pointer;
|
||||
use crate::borrow::{Borrow, BorrowMut, LoanError, Ref, RefMut};
|
||||
use crate::context::internal::Env;
|
||||
use crate::context::{Context, Lock};
|
||||
#[cfg(feature = "napi-1")]
|
||||
use handle::Handle;
|
||||
use handle::Managed;
|
||||
use crate::handle::Handle;
|
||||
use crate::handle::Managed;
|
||||
use crate::result::JsResult;
|
||||
use crate::types::internal::ValueInternal;
|
||||
use crate::types::{build, Object, Value};
|
||||
use neon_runtime;
|
||||
use neon_runtime::raw;
|
||||
use result::JsResult;
|
||||
use std::marker::PhantomData;
|
||||
use std::mem::{self, MaybeUninit};
|
||||
use std::os::raw::c_void;
|
||||
use std::slice;
|
||||
use types::internal::ValueInternal;
|
||||
use types::{build, Object, Value};
|
||||
|
||||
/// The Node [`Buffer`](https://nodejs.org/api/buffer.html) type.
|
||||
#[repr(C)]
|
||||
|
||||
@ -7,6 +7,7 @@ use neon_runtime::raw;
|
||||
use crate::context::internal::Env;
|
||||
use crate::context::{Context, FinalizeContext};
|
||||
use crate::handle::{Handle, Managed};
|
||||
use crate::object::Object;
|
||||
use crate::types::internal::ValueInternal;
|
||||
use crate::types::Value;
|
||||
|
||||
@ -159,6 +160,8 @@ impl<T: Send + 'static> Clone for JsBox<T> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Send + 'static> Object for JsBox<T> {}
|
||||
|
||||
impl<T: Send + 'static> Copy for JsBox<T> {}
|
||||
|
||||
impl<T: Send + 'static> Value for JsBox<T> {}
|
||||
|
||||
@ -1,11 +1,11 @@
|
||||
use super::{Value, ValueInternal};
|
||||
use context::internal::Env;
|
||||
use context::Context;
|
||||
use handle::{Handle, Managed};
|
||||
use crate::context::internal::Env;
|
||||
use crate::context::Context;
|
||||
use crate::handle::{Handle, Managed};
|
||||
use crate::object::Object;
|
||||
use crate::result::{JsResult, JsResultExt};
|
||||
use neon_runtime;
|
||||
use neon_runtime::raw;
|
||||
use object::Object;
|
||||
use result::{JsResult, JsResultExt};
|
||||
use std::error::Error;
|
||||
use std::fmt;
|
||||
use std::fmt::Debug;
|
||||
|
||||
@ -5,12 +5,12 @@ use std::panic::{catch_unwind, UnwindSafe};
|
||||
use neon_runtime;
|
||||
use neon_runtime::raw;
|
||||
|
||||
use context::internal::Env;
|
||||
use context::Context;
|
||||
use result::{NeonResult, Throw};
|
||||
use types::internal::ValueInternal;
|
||||
use types::utf8::Utf8;
|
||||
use types::{build, Handle, Managed, Object, Value};
|
||||
use crate::context::internal::Env;
|
||||
use crate::context::Context;
|
||||
use crate::result::{NeonResult, Throw};
|
||||
use crate::types::internal::ValueInternal;
|
||||
use crate::types::utf8::Utf8;
|
||||
use crate::types::{build, Handle, Managed, Object, Value};
|
||||
|
||||
/// A JS `Error` object.
|
||||
#[repr(C)]
|
||||
|
||||
@ -1,14 +1,14 @@
|
||||
use super::Value;
|
||||
use context::internal::Env;
|
||||
use context::{CallbackInfo, FunctionContext};
|
||||
use crate::context::internal::Env;
|
||||
use crate::context::{CallbackInfo, FunctionContext};
|
||||
use crate::result::JsResult;
|
||||
use crate::types::error::convert_panics;
|
||||
use crate::types::{Handle, JsObject, Managed};
|
||||
use neon_runtime;
|
||||
use neon_runtime::call::CCallback;
|
||||
use neon_runtime::raw;
|
||||
use result::JsResult;
|
||||
use std::mem;
|
||||
use std::os::raw::c_void;
|
||||
use types::error::convert_panics;
|
||||
use types::{Handle, JsObject, Managed};
|
||||
|
||||
pub trait ValueInternal: Managed + 'static {
|
||||
fn name() -> String;
|
||||
|
||||
@ -1,4 +1,76 @@
|
||||
//! Representations of JavaScript's core builtin types.
|
||||
//!
|
||||
//! ## Modeling JavaScript Types
|
||||
//!
|
||||
//! All JavaScript values in Neon implement the abstract [`Value`] trait, which
|
||||
//! is the most generic way to work with JavaScript values. Neon provides a
|
||||
//! number of types that implement this trait, each representing a particular
|
||||
//! type of JavaScript value.
|
||||
//!
|
||||
//! By convention, JavaScript types in Neon have the prefix `Js` in their name,
|
||||
//! such as [`JsNumber`](crate::types::JsNumber) (for the JavaScript `number`
|
||||
//! type) or [`JsFunction`](crate::types::JsFunction) (for the JavaScript
|
||||
//! `function` type).
|
||||
//!
|
||||
//! ### Handles and Casts
|
||||
//!
|
||||
//! Access to JavaScript values in Neon works through [handles](crate::handle),
|
||||
//! which ensure the safe interoperation between Rust and the JavaScript garbage
|
||||
//! collector. This means, for example, a Rust variable that stores a JavaScript string
|
||||
//! will have the type `Handle<JsString>` rather than [`JsString`](crate::types::JsString).
|
||||
//!
|
||||
//! Neon types model the JavaScript type hierarchy through the use of *casts*.
|
||||
//! The [`Handle::upcast()`](crate::handle::Handle::upcast) method safely converts
|
||||
//! a handle to a JavaScript value of one type into a handle to a value of its
|
||||
//! supertype. For example, it's safe to treat a [`JsArray`](crate::types::JsArray)
|
||||
//! as a [`JsObject`](crate::types::JsObject), so you can do an "upcast" and it will
|
||||
//! never fail:
|
||||
//!
|
||||
//! ```
|
||||
//! # use neon::prelude::*;
|
||||
//! fn as_object(array: Handle<JsArray>) -> Handle<JsObject> {
|
||||
//! let object: Handle<JsObject> = array.upcast();
|
||||
//! object
|
||||
//! }
|
||||
//! ```
|
||||
//!
|
||||
//! Unlike upcasts, the [`Handle::downcast()`](crate::handle::Handle::downcast) method
|
||||
//! requires a runtime check to test a value's type at runtime, so it can fail with
|
||||
//! a [`DowncastError`](crate::handle::DowncastError):
|
||||
//!
|
||||
//! ```
|
||||
//! # use neon::prelude::*;
|
||||
//! fn as_array<'a>(
|
||||
//! cx: &mut impl Context<'a>,
|
||||
//! object: Handle<'a, JsObject>
|
||||
//! ) -> JsResult<'a, JsArray> {
|
||||
//! object.downcast(cx).or_throw(cx)
|
||||
//! }
|
||||
//! ```
|
||||
//!
|
||||
//! ### The JavaScript Type Hierarchy
|
||||
//!
|
||||
//! ![The Neon type hierarchy, described in detail below.][types]
|
||||
//!
|
||||
//! The JavaScript type hierarchy includes:
|
||||
//!
|
||||
//! - [`JsValue`](JsValue): This is the top of the type hierarchy, and can refer to
|
||||
//! any JavaScript value. (For TypeScript programmers, this can be thought of as
|
||||
//! similar to TypeScript's [`unknown`][unknown] type.)
|
||||
//! - [`JsObject`](JsObject): This is the top of the object type hierarchy. Object
|
||||
//! types all implement the [`Object`](crate::object::Object) trait, which allows
|
||||
//! getting and setting properties.
|
||||
//! - **Standard object types:** [`JsFunction`](JsFunction), [`JsArray`](JsArray),
|
||||
//! [`JsDate`](JsDate), and [`JsError`](JsError).
|
||||
//! - **Typed arrays:** [`JsBuffer`](JsBuffer) and [`JsArrayBuffer`](JsArrayBuffer).
|
||||
//! - **Custom types:** [`JsBox`](JsBox), a special Neon type that allows the creation
|
||||
//! of custom objects that own Rust data structures.
|
||||
//! - **Primitive types:** These are the built-in JavaScript datatypes that are not
|
||||
//! object types: [`JsNumber`](JsNumber), [`JsBoolean`](JsBoolean),
|
||||
//! [`JsString`](JsString), [`JsNull`](JsNull), and [`JsUndefined`](JsUndefined).
|
||||
//!
|
||||
//! [types]: https://raw.githubusercontent.com/neon-bindings/neon/main/doc/types.jpg
|
||||
//! [unknown]: https://mariusschulz.com/blog/the-unknown-type-in-typescript#the-unknown-type
|
||||
|
||||
pub(crate) mod binary;
|
||||
#[cfg(feature = "napi-1")]
|
||||
@ -12,20 +84,20 @@ pub(crate) mod utf8;
|
||||
|
||||
use self::internal::{FunctionCallback, ValueInternal};
|
||||
use self::utf8::Utf8;
|
||||
use context::internal::Env;
|
||||
use context::{Context, FunctionContext};
|
||||
use handle::internal::SuperType;
|
||||
use handle::{Handle, Managed};
|
||||
use crate::context::internal::Env;
|
||||
use crate::context::{Context, FunctionContext};
|
||||
use crate::handle::internal::SuperType;
|
||||
use crate::handle::{Handle, Managed};
|
||||
use crate::object::{Object, This};
|
||||
use crate::result::{JsResult, JsResultExt, NeonResult, Throw};
|
||||
use crate::types::internal::Callback;
|
||||
use neon_runtime;
|
||||
use neon_runtime::raw;
|
||||
use object::{Object, This};
|
||||
use result::{JsResult, JsResultExt, NeonResult, Throw};
|
||||
use smallvec::SmallVec;
|
||||
use std::fmt;
|
||||
use std::fmt::Debug;
|
||||
use std::marker::PhantomData;
|
||||
use std::os::raw::c_void;
|
||||
use types::internal::Callback;
|
||||
|
||||
pub use self::binary::{BinaryData, BinaryViewType, JsArrayBuffer, JsBuffer};
|
||||
#[cfg(feature = "napi-1")]
|
||||
|
||||
44
test/cli/package-lock.json
generated
44
test/cli/package-lock.json
generated
@ -687,14 +687,15 @@
|
||||
"dev": true
|
||||
},
|
||||
"handlebars": {
|
||||
"version": "4.5.3",
|
||||
"resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.5.3.tgz",
|
||||
"integrity": "sha512-3yPecJoJHK/4c6aZhSvxOyG4vJKDshV36VHp0iVCDVh7o9w2vwi3NSnL2MMPj3YdduqaBcu7cGbggJQM0br9xA==",
|
||||
"version": "4.7.7",
|
||||
"resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.7.7.tgz",
|
||||
"integrity": "sha512-aAcXm5OAfE/8IXkcZvCepKU3VzW1/39Fb5ZuqMtgI/hT8X2YgoMvBY5dLhq/cpOvw7Lk1nK/UF71aLG/ZnVYRA==",
|
||||
"requires": {
|
||||
"minimist": "^1.2.5",
|
||||
"neo-async": "^2.6.0",
|
||||
"optimist": "^0.6.1",
|
||||
"source-map": "^0.6.1",
|
||||
"uglify-js": "^3.1.4"
|
||||
"uglify-js": "^3.1.4",
|
||||
"wordwrap": "^1.0.0"
|
||||
}
|
||||
},
|
||||
"has-flag": {
|
||||
@ -837,9 +838,9 @@
|
||||
}
|
||||
},
|
||||
"lodash": {
|
||||
"version": "4.17.19",
|
||||
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.19.tgz",
|
||||
"integrity": "sha512-JNvd8XER9GQX0v2qJgsaN/mzFCNA5BRe/j8JN9d+tWyGLSodKQHKFicdwNYzWwI3wjRnaKPsGj1XkBjx/F96DQ=="
|
||||
"version": "4.17.21",
|
||||
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz",
|
||||
"integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg=="
|
||||
},
|
||||
"lodash.padend": {
|
||||
"version": "4.6.1",
|
||||
@ -926,9 +927,9 @@
|
||||
}
|
||||
},
|
||||
"minimist": {
|
||||
"version": "0.0.10",
|
||||
"resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.10.tgz",
|
||||
"integrity": "sha1-3j+YVD2/lggr5IrRoMfNqDYwHc8="
|
||||
"version": "1.2.5",
|
||||
"resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz",
|
||||
"integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw=="
|
||||
},
|
||||
"mkdirp": {
|
||||
"version": "0.5.1",
|
||||
@ -1071,15 +1072,6 @@
|
||||
"mimic-fn": "^1.0.0"
|
||||
}
|
||||
},
|
||||
"optimist": {
|
||||
"version": "0.6.1",
|
||||
"resolved": "https://registry.npmjs.org/optimist/-/optimist-0.6.1.tgz",
|
||||
"integrity": "sha1-2j6nRob6IaGaERwybpDrFaAZZoY=",
|
||||
"requires": {
|
||||
"minimist": "~0.0.1",
|
||||
"wordwrap": "~0.0.2"
|
||||
}
|
||||
},
|
||||
"os-tmpdir": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz",
|
||||
@ -1497,9 +1489,9 @@
|
||||
"integrity": "sha1-XAgOXWYcu+OCWdLnCjxyU+hziB0="
|
||||
},
|
||||
"uglify-js": {
|
||||
"version": "3.10.3",
|
||||
"resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.10.3.tgz",
|
||||
"integrity": "sha512-Lh00i69Uf6G74mvYpHCI9KVVXLcHW/xu79YTvH7Mkc9zyKUeSPz0owW0dguj0Scavns3ZOh3wY63J0Zb97Za2g==",
|
||||
"version": "3.13.5",
|
||||
"resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.13.5.tgz",
|
||||
"integrity": "sha512-xtB8yEqIkn7zmOyS2zUNBsYCBRhDkvlNxMMY2smuJ/qA8NCHeQvKCF3i9Z4k8FJH4+PJvZRtMrPynfZ75+CSZw==",
|
||||
"optional": true
|
||||
},
|
||||
"v8flags": {
|
||||
@ -1553,9 +1545,9 @@
|
||||
}
|
||||
},
|
||||
"wordwrap": {
|
||||
"version": "0.0.3",
|
||||
"resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.3.tgz",
|
||||
"integrity": "sha1-o9XabNXAvAAI03I0u68b7WMFkQc="
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz",
|
||||
"integrity": "sha1-J1hIEIkUVqQXHI0CJkQa3pDLyus="
|
||||
},
|
||||
"wordwrapjs": {
|
||||
"version": "3.0.0",
|
||||
|
||||
@ -14,7 +14,7 @@
|
||||
"command-line-commands": "^2.0.0",
|
||||
"command-line-usage": "^4.0.0",
|
||||
"git-config": "0.0.7",
|
||||
"handlebars": "^4.5.3",
|
||||
"handlebars": "^4.7.7",
|
||||
"inquirer": "^3.0.6",
|
||||
"mkdirp": "^0.5.1",
|
||||
"quickly-copy-file": "^1.0.0",
|
||||
|
||||
@ -6,7 +6,7 @@
|
||||
"author": "The Neon Community",
|
||||
"license": "MIT",
|
||||
"scripts": {
|
||||
"install": "node ../../cli/bin/cli.js build --release",
|
||||
"install": "node ../../cli/bin/cli.js build",
|
||||
"test": "mocha --timeout 5000 --recursive lib"
|
||||
},
|
||||
"devDependencies": {
|
||||
|
||||
18
test/electron/package-lock.json
generated
18
test/electron/package-lock.json
generated
@ -810,9 +810,9 @@
|
||||
"dev": true
|
||||
},
|
||||
"electron": {
|
||||
"version": "11.0.4",
|
||||
"resolved": "https://registry.npmjs.org/electron/-/electron-11.0.4.tgz",
|
||||
"integrity": "sha512-ipfQ28Km52iuDSe9VK0G5uuyxi8qy8szg+01kQTRXZFCLlpgsgU+vQxWkld2tkhXWdu+H3dmgYHvWtoijOvhjw==",
|
||||
"version": "11.1.0",
|
||||
"resolved": "https://registry.npmjs.org/electron/-/electron-11.1.0.tgz",
|
||||
"integrity": "sha512-RFAhR/852VMaRd9NSe7jprwSoG9dLc6u1GwnqRWg+/3cy/8Zrwt1Betw1lXiZH7hGuB9K2cqju83Xv5Pq5ZSGA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@electron/get": "^1.0.1",
|
||||
@ -1342,9 +1342,9 @@
|
||||
}
|
||||
},
|
||||
"lodash": {
|
||||
"version": "4.17.20",
|
||||
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.20.tgz",
|
||||
"integrity": "sha512-PlhdFcillOINfeV7Ni6oF1TAEayyZBoZ8bcshTHqOYJYlrqzRK5hagpagky5o4HfCzzd1TRkXPMFq6cKk9rGmA==",
|
||||
"version": "4.17.21",
|
||||
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz",
|
||||
"integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==",
|
||||
"dev": true,
|
||||
"optional": true
|
||||
},
|
||||
@ -2085,9 +2085,9 @@
|
||||
"dev": true
|
||||
},
|
||||
"ua-parser-js": {
|
||||
"version": "0.7.22",
|
||||
"resolved": "https://registry.npmjs.org/ua-parser-js/-/ua-parser-js-0.7.22.tgz",
|
||||
"integrity": "sha512-YUxzMjJ5T71w6a8WWVcMGM6YWOTX27rCoIQgLXiWaxqXSx9D7DNjiGWn1aJIRSQ5qr0xuhra77bSIh6voR/46Q==",
|
||||
"version": "0.7.28",
|
||||
"resolved": "https://registry.npmjs.org/ua-parser-js/-/ua-parser-js-0.7.28.tgz",
|
||||
"integrity": "sha512-6Gurc1n//gjp9eQNXjD9O3M/sMwVtN5S8Lv9bvOYBfKfDNiIIhqiyi01vMBO45u4zkDE420w/e0se7Vs+sIg+g==",
|
||||
"dev": true
|
||||
},
|
||||
"unbzip2-stream": {
|
||||
|
||||
@ -13,7 +13,7 @@
|
||||
"repository": "https://github.com/electron/electron-quick-start",
|
||||
"devDependencies": {
|
||||
"cargo-cp-artifact": "^0.1.0 ",
|
||||
"electron": "^11.0.3",
|
||||
"electron": "^11.1.0",
|
||||
"spectron": "^13.0.0"
|
||||
}
|
||||
}
|
||||
|
||||
@ -64,4 +64,11 @@ const assert = require('chai').assert;
|
||||
// If the EventQueue is not unreferenced, the test runner will not cleanly exit
|
||||
addon.leak_event_queue();
|
||||
});
|
||||
|
||||
it('should drop leaked Root from the global queue', function (cb) {
|
||||
addon.drop_global_queue(cb);
|
||||
|
||||
// Asynchronously GC to give the task queue a chance to execute
|
||||
setTimeout(() => global.gc(), 10);
|
||||
});
|
||||
});
|
||||
|
||||
@ -144,3 +144,44 @@ pub fn leak_event_queue(mut cx: FunctionContext) -> JsResult<JsUndefined> {
|
||||
|
||||
Ok(cx.undefined())
|
||||
}
|
||||
|
||||
pub fn drop_global_queue(mut cx: FunctionContext) -> JsResult<JsUndefined> {
|
||||
struct Wrapper {
|
||||
callback: Option<Root<JsFunction>>,
|
||||
queue: EventQueue,
|
||||
}
|
||||
|
||||
impl Finalize for Wrapper {}
|
||||
|
||||
// To verify that the type is dropped on the global drop queue, the callback
|
||||
// is called from the `Drop` impl on `Wrapper`
|
||||
impl Drop for Wrapper {
|
||||
fn drop(&mut self) {
|
||||
if let Some(callback) = self.callback.take() {
|
||||
self.queue.send(|mut cx| {
|
||||
let callback = callback.into_inner(&mut cx);
|
||||
let this = cx.undefined();
|
||||
let args = vec![cx.undefined()];
|
||||
|
||||
callback.call(&mut cx, this, args)?;
|
||||
|
||||
Ok(())
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let callback = cx.argument::<JsFunction>(0)?.root(&mut cx);
|
||||
let queue = cx.queue();
|
||||
|
||||
let wrapper = cx.boxed(Wrapper {
|
||||
callback: Some(callback),
|
||||
queue,
|
||||
});
|
||||
|
||||
// Put the `Wrapper` instance in a `Root` and drop it
|
||||
// Without the global drop queue, this will panic
|
||||
let _ = wrapper.root(&mut cx);
|
||||
|
||||
Ok(cx.undefined())
|
||||
}
|
||||
|
||||
@ -256,6 +256,7 @@ fn main(mut cx: ModuleContext) -> NeonResult<()> {
|
||||
cx.export_function("greeter_new", greeter_new)?;
|
||||
cx.export_function("greeter_greet", greeter_greet)?;
|
||||
cx.export_function("leak_event_queue", leak_event_queue)?;
|
||||
cx.export_function("drop_global_queue", drop_global_queue)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user