Compare commits
4 Commits
main
...
rename-eve
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f75368a2d2 | ||
|
|
6221ee21a8 | ||
|
|
280fdbd42a | ||
|
|
f2d3703ab9 |
10
Cargo.toml
10
Cargo.toml
@ -1,18 +1,18 @@
|
||||
[package]
|
||||
name = "neon"
|
||||
version = "0.8.2"
|
||||
version = "0.8.1"
|
||||
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", "doc/**/*"]
|
||||
exclude = ["neon.jpg"]
|
||||
build = "build.rs"
|
||||
edition = "2018"
|
||||
|
||||
[build-dependencies]
|
||||
neon-build = { version = "=0.8.2", path = "crates/neon-build" }
|
||||
neon-build = { version = "=0.8.1", path = "crates/neon-build" }
|
||||
|
||||
[dev-dependencies]
|
||||
lazy_static = "1.4.0"
|
||||
@ -25,8 +25,8 @@ failure = "0.1.5" # used for a doc example
|
||||
cslice = "0.2"
|
||||
semver = "0.9.0"
|
||||
smallvec = "1.4.2"
|
||||
neon-runtime = { version = "=0.8.2", path = "crates/neon-runtime" }
|
||||
neon-macros = { version = "=0.8.2", path = "crates/neon-macros", optional = true }
|
||||
neon-runtime = { version = "=0.8.1", path = "crates/neon-runtime" }
|
||||
neon-macros = { version = "=0.8.1", path = "crates/neon-macros", optional = true }
|
||||
|
||||
[features]
|
||||
default = ["legacy-runtime"]
|
||||
|
||||
@ -33,15 +33,14 @@ The N-API backend of Neon requires a minimum Node version of 10.0.
|
||||
|
||||
To enable the N-API backend, you need to:
|
||||
|
||||
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).
|
||||
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).
|
||||
|
||||
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.8.2"
|
||||
version = "0.8.1"
|
||||
default-features = false
|
||||
features = ["napi-4"]
|
||||
```
|
||||
|
||||
@ -1,8 +1,3 @@
|
||||
# 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)
|
||||
|
||||
20
cli/package-lock.json
generated
20
cli/package-lock.json
generated
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "neon-cli",
|
||||
"version": "0.8.2",
|
||||
"version": "0.8.1",
|
||||
"lockfileVersion": 1,
|
||||
"requires": true,
|
||||
"dependencies": {
|
||||
@ -616,9 +616,9 @@
|
||||
"dev": true
|
||||
},
|
||||
"handlebars": {
|
||||
"version": "4.7.7",
|
||||
"resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.7.7.tgz",
|
||||
"integrity": "sha512-aAcXm5OAfE/8IXkcZvCepKU3VzW1/39Fb5ZuqMtgI/hT8X2YgoMvBY5dLhq/cpOvw7Lk1nK/UF71aLG/ZnVYRA==",
|
||||
"version": "4.7.6",
|
||||
"resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.7.6.tgz",
|
||||
"integrity": "sha512-1f2BACcBfiwAfStCKZNrUCgqNZkGsAT7UM3kkYtXuLo0KnaVfjKOyf7PRzB6++aK9STyT1Pd2ZCPe3EGOXleXA==",
|
||||
"requires": {
|
||||
"minimist": "^1.2.5",
|
||||
"neo-async": "^2.6.0",
|
||||
@ -849,9 +849,9 @@
|
||||
}
|
||||
},
|
||||
"lodash": {
|
||||
"version": "4.17.21",
|
||||
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz",
|
||||
"integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg=="
|
||||
"version": "4.17.19",
|
||||
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.19.tgz",
|
||||
"integrity": "sha512-JNvd8XER9GQX0v2qJgsaN/mzFCNA5BRe/j8JN9d+tWyGLSodKQHKFicdwNYzWwI3wjRnaKPsGj1XkBjx/F96DQ=="
|
||||
},
|
||||
"lodash.camelcase": {
|
||||
"version": "4.3.0",
|
||||
@ -1365,9 +1365,9 @@
|
||||
"integrity": "sha512-VAH4IvQ7BDFYglMd7BPRDfLgxZZX4O4TFcRDA6EN5X7erNJJq+McIEp8np9aVtxrCJ6qx4GTYVfOWNjcqwZgRw=="
|
||||
},
|
||||
"uglify-js": {
|
||||
"version": "3.13.5",
|
||||
"resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.13.5.tgz",
|
||||
"integrity": "sha512-xtB8yEqIkn7zmOyS2zUNBsYCBRhDkvlNxMMY2smuJ/qA8NCHeQvKCF3i9Z4k8FJH4+PJvZRtMrPynfZ75+CSZw==",
|
||||
"version": "3.10.0",
|
||||
"resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.10.0.tgz",
|
||||
"integrity": "sha512-Esj5HG5WAyrLIdYU74Z3JdG2PxdIusvj6IWHMtlyESxc7kcDz7zYlYjpnSokn1UbpV0d/QX9fan7gkCNd/9BQA==",
|
||||
"optional": true
|
||||
},
|
||||
"validate-npm-package-license": {
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "neon-cli",
|
||||
"version": "0.8.2",
|
||||
"version": "0.8.1",
|
||||
"description": "Build and load native Rust/Neon modules.",
|
||||
"author": "Dave Herman <david.herman@gmail.com>",
|
||||
"repository": {
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "neon-build"
|
||||
version = "0.8.2"
|
||||
version = "0.8.1"
|
||||
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.8.2", path = "../neon-sys", optional = true }
|
||||
neon-sys = { version = "=0.8.1", path = "../neon-sys", optional = true }
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "neon-macros"
|
||||
version = "0.8.2"
|
||||
version = "0.8.1"
|
||||
authors = ["Dave Herman <david.herman@gmail.com>"]
|
||||
description = "Procedural macros supporting Neon"
|
||||
repository = "https://github.com/neon-bindings/neon"
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "neon-runtime"
|
||||
version = "0.8.2"
|
||||
version = "0.8.1"
|
||||
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.8.2", path = "../neon-sys", optional = true }
|
||||
neon-sys = { version = "=0.8.1", path = "../neon-sys", optional = true }
|
||||
smallvec = "1.4.2"
|
||||
|
||||
[dev-dependencies]
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "neon-sys"
|
||||
version = "0.8.2"
|
||||
version = "0.8.1"
|
||||
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"
|
||||
|
||||
BIN
doc/types.jpg
BIN
doc/types.jpg
Binary file not shown.
|
Before Width: | Height: | Size: 29 KiB |
BIN
doc/types.pptx
BIN
doc/types.pptx
Binary file not shown.
@ -152,7 +152,7 @@ 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 crate::event::EventQueue;
|
||||
use crate::event::Channel;
|
||||
use crate::handle::{Handle, Managed};
|
||||
#[cfg(feature = "legacy-runtime")]
|
||||
use crate::object::class::Class;
|
||||
@ -550,9 +550,16 @@ pub trait Context<'a>: ContextInternal<'a> {
|
||||
}
|
||||
|
||||
#[cfg(all(feature = "napi-4", feature = "event-queue-api"))]
|
||||
/// Creates an unbounded queue of events to be executed on a JavaScript thread
|
||||
fn queue(&mut self) -> EventQueue {
|
||||
EventQueue::new(self)
|
||||
/// Creates an unbounded channel for scheduling events to be executed on the JavaScript thread.
|
||||
fn channel(&mut self) -> Channel {
|
||||
Channel::new(self)
|
||||
}
|
||||
|
||||
#[cfg(all(feature = "napi-4", feature = "event-queue-api"))]
|
||||
#[deprecated(since = "0.9.0", note = "Please use the channel() method instead")]
|
||||
#[doc(hidden)]
|
||||
fn queue(&mut self) -> Channel {
|
||||
self.channel()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -6,7 +6,7 @@ use crate::result::NeonResult;
|
||||
|
||||
type Callback = Box<dyn FnOnce(Env) + Send + 'static>;
|
||||
|
||||
/// Queue for scheduling Rust closures to execute on the JavaScript main thread.
|
||||
/// Channel for scheduling Rust closures to execute on the JavaScript main thread.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
@ -17,11 +17,11 @@ type Callback = Box<dyn FnOnce(Env) + Send + 'static>;
|
||||
/// # use neon::prelude::*;
|
||||
/// # fn fibonacci(_: f64) -> f64 { todo!() }
|
||||
/// fn async_fibonacci(mut cx: FunctionContext) -> JsResult<JsUndefined> {
|
||||
/// // These types (`f64`, `Root<JsFunction>`, `EventQueue`) may all be sent
|
||||
/// // These types (`f64`, `Root<JsFunction>`, `Channel`) may all be sent
|
||||
/// // across threads.
|
||||
/// let n = cx.argument::<JsNumber>(0)?.value(&mut cx);
|
||||
/// let callback = cx.argument::<JsFunction>(1)?.root(&mut cx);
|
||||
/// let queue = cx.queue();
|
||||
/// let channel = cx.channel();
|
||||
///
|
||||
/// // Spawn a thread to complete the execution. This will _not_ block the
|
||||
/// // JavaScript event loop.
|
||||
@ -29,8 +29,8 @@ type Callback = Box<dyn FnOnce(Env) + Send + 'static>;
|
||||
/// let result = fibonacci(n);
|
||||
///
|
||||
/// // 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| {
|
||||
/// // loop. This _will_ block the event loop while executing.
|
||||
/// channel.send(move |mut cx| {
|
||||
/// let callback = callback.into_inner(&mut cx);
|
||||
/// let this = cx.undefined();
|
||||
/// let null = cx.null();
|
||||
@ -49,19 +49,19 @@ type Callback = Box<dyn FnOnce(Env) + Send + 'static>;
|
||||
/// }
|
||||
/// ```
|
||||
|
||||
pub struct EventQueue {
|
||||
pub struct Channel {
|
||||
tsfn: ThreadsafeFunction<Callback>,
|
||||
has_ref: bool,
|
||||
}
|
||||
|
||||
impl std::fmt::Debug for EventQueue {
|
||||
impl std::fmt::Debug for Channel {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
f.write_str("EventQueue")
|
||||
f.write_str("Channel")
|
||||
}
|
||||
}
|
||||
|
||||
impl EventQueue {
|
||||
/// Creates an unbounded queue for scheduling closures on the JavaScript
|
||||
impl Channel {
|
||||
/// Creates an unbounded channel for scheduling closures on the JavaScript
|
||||
/// main thread
|
||||
pub fn new<'a, C: Context<'a>>(cx: &mut C) -> Self {
|
||||
let tsfn = unsafe { ThreadsafeFunction::new(cx.env().to_raw(), Self::callback) };
|
||||
@ -72,7 +72,7 @@ impl EventQueue {
|
||||
}
|
||||
}
|
||||
|
||||
/// Allow the Node event loop to exit while this `EventQueue` exists.
|
||||
/// Allow the Node event loop to exit while this `Channel` exists.
|
||||
/// _Idempotent_
|
||||
pub fn unref<'a, C: Context<'a>>(&mut self, cx: &mut C) -> &mut Self {
|
||||
self.has_ref = false;
|
||||
@ -82,7 +82,7 @@ impl EventQueue {
|
||||
self
|
||||
}
|
||||
|
||||
/// Prevent the Node event loop from exiting while this `EventQueue` exists. (Default)
|
||||
/// Prevent the Node event loop from exiting while this `Channel` exists. (Default)
|
||||
/// _Idempotent_
|
||||
pub fn reference<'a, C: Context<'a>>(&mut self, cx: &mut C) -> &mut Self {
|
||||
self.has_ref = true;
|
||||
@ -92,7 +92,7 @@ impl EventQueue {
|
||||
self
|
||||
}
|
||||
|
||||
/// Schedules a closure to execute on the JavaScript thread that created this EventQueue
|
||||
/// Schedules a closure to execute on the JavaScript thread that created this Channel
|
||||
/// Panics if there is a libuv error
|
||||
pub fn send<F>(&self, f: F)
|
||||
where
|
||||
@ -101,9 +101,9 @@ impl EventQueue {
|
||||
self.try_send(f).unwrap()
|
||||
}
|
||||
|
||||
/// Schedules a closure to execute on the JavaScript thread that created this EventQueue
|
||||
/// Schedules a closure to execute on the JavaScript thread that created this Channel
|
||||
/// Returns an `Error` if the task could not be scheduled.
|
||||
pub fn try_send<F>(&self, f: F) -> Result<(), EventQueueError>
|
||||
pub fn try_send<F>(&self, f: F) -> Result<(), SendError>
|
||||
where
|
||||
F: FnOnce(TaskContext) -> NeonResult<()> + Send + 'static,
|
||||
{
|
||||
@ -117,11 +117,11 @@ impl EventQueue {
|
||||
});
|
||||
});
|
||||
|
||||
self.tsfn.call(callback, None).map_err(|_| EventQueueError)
|
||||
self.tsfn.call(callback, None).map_err(|_| SendError)
|
||||
}
|
||||
|
||||
/// Returns a boolean indicating if this `EventQueue` will prevent the Node event
|
||||
/// queue from exiting.
|
||||
/// Returns a boolean indicating if this `Channel` will prevent the Node event
|
||||
/// loop from exiting.
|
||||
pub fn has_ref(&self) -> bool {
|
||||
self.has_ref
|
||||
}
|
||||
@ -138,19 +138,19 @@ impl EventQueue {
|
||||
}
|
||||
}
|
||||
|
||||
/// Error indicating that a closure was unable to be scheduled to execute on the event queue
|
||||
pub struct EventQueueError;
|
||||
/// Error indicating that a closure was unable to be scheduled to execute on the event loop.
|
||||
pub struct SendError;
|
||||
|
||||
impl std::fmt::Display for EventQueueError {
|
||||
impl std::fmt::Display for SendError {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
write!(f, "EventQueueError")
|
||||
write!(f, "SendError")
|
||||
}
|
||||
}
|
||||
|
||||
impl std::fmt::Debug for EventQueueError {
|
||||
impl std::fmt::Debug for SendError {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
std::fmt::Display::fmt(self, f)
|
||||
}
|
||||
}
|
||||
|
||||
impl std::error::Error for EventQueueError {}
|
||||
impl std::error::Error for SendError {}
|
||||
|
||||
@ -32,20 +32,20 @@
|
||||
//! # #[cfg(feature = "napi-1")] {
|
||||
//! # use neon::prelude::*;
|
||||
//! #
|
||||
//! # fn parse(filename: String, callback: Root<JsFunction>, queue: EventQueue) { }
|
||||
//! # fn parse(filename: String, callback: Root<JsFunction>, channel: Channel) { }
|
||||
//! #
|
||||
//! fn parse_async(mut cx: FunctionContext) -> JsResult<JsUndefined> {
|
||||
//! // The types `String`, `Root<JsFunction>`, and `EventQueue` can all be
|
||||
//! // The types `String`, `Root<JsFunction>`, and `Channel` 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();
|
||||
//! let channel = cx.channel();
|
||||
//!
|
||||
//! // Spawn a thread to complete the execution. This will _not_ block the
|
||||
//! // JavaScript event loop.
|
||||
//! // Spawn a background thread to complete the execution. The background
|
||||
//! // execution will _not_ block the JavaScript event loop.
|
||||
//! std::thread::spawn(move || {
|
||||
//! // Do the heavy lifting inside the background thread.
|
||||
//! parse(filename, callback, queue);
|
||||
//! parse(filename, callback, channel);
|
||||
//! });
|
||||
//!
|
||||
//! Ok(cx.undefined())
|
||||
@ -58,7 +58,7 @@
|
||||
//! 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:
|
||||
//! callback and the channel to notify the main thread of the result:
|
||||
//!
|
||||
//! ```
|
||||
//! # #[cfg(feature = "napi-1")] {
|
||||
@ -70,12 +70,12 @@
|
||||
//! Psd::from_bytes(&std::fs::read(&filename)?)
|
||||
//! }
|
||||
//!
|
||||
//! fn parse(filename: String, callback: Root<JsFunction>, queue: EventQueue) {
|
||||
//! fn parse(filename: String, callback: Root<JsFunction>, channel: Channel) {
|
||||
//! 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| {
|
||||
//! // loop. This _will_ block the event loop while executing.
|
||||
//! channel.send(move |mut cx| {
|
||||
//! let callback = callback.into_inner(&mut cx);
|
||||
//! let this = cx.undefined();
|
||||
//! let null = cx.null();
|
||||
@ -127,7 +127,17 @@
|
||||
mod event_queue;
|
||||
|
||||
#[cfg(all(feature = "napi-4", feature = "event-queue-api"))]
|
||||
pub use self::event_queue::{EventQueue, EventQueueError};
|
||||
pub use self::event_queue::{Channel, SendError};
|
||||
|
||||
#[cfg(all(feature = "napi-4", feature = "event-queue-api"))]
|
||||
#[deprecated(since = "0.9.0", note = "Please use the Channel type instead")]
|
||||
#[doc(hidden)]
|
||||
pub type EventQueue = self::event_queue::Channel;
|
||||
|
||||
#[cfg(all(feature = "napi-4", feature = "event-queue-api"))]
|
||||
#[deprecated(since = "0.9.0", note = "Please use the SendError type instead")]
|
||||
#[doc(hidden)]
|
||||
pub type EventQueueError = self::event_queue::SendError;
|
||||
|
||||
#[cfg(all(not(feature = "napi-1"), feature = "event-handler-api"))]
|
||||
mod event_handler;
|
||||
@ -138,5 +148,5 @@ pub use self::event_handler::EventHandler;
|
||||
#[cfg(all(feature = "napi-1", feature = "event-handler-api"))]
|
||||
compile_error!(
|
||||
"The `EventHandler` API is not supported with the N-API \
|
||||
backend. Use `EventQueue` instead."
|
||||
backend. Use `Channel` instead."
|
||||
);
|
||||
|
||||
@ -10,6 +10,9 @@ 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::{Channel, SendError};
|
||||
#[cfg(all(feature = "napi-4", feature = "event-queue-api"))]
|
||||
#[allow(deprecated)]
|
||||
pub use crate::event::{EventQueue, EventQueueError};
|
||||
pub use crate::handle::Handle;
|
||||
#[cfg(feature = "legacy-runtime")]
|
||||
|
||||
@ -1,76 +1,4 @@
|
||||
//! 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")]
|
||||
|
||||
44
test/cli/package-lock.json
generated
44
test/cli/package-lock.json
generated
@ -687,15 +687,14 @@
|
||||
"dev": true
|
||||
},
|
||||
"handlebars": {
|
||||
"version": "4.7.7",
|
||||
"resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.7.7.tgz",
|
||||
"integrity": "sha512-aAcXm5OAfE/8IXkcZvCepKU3VzW1/39Fb5ZuqMtgI/hT8X2YgoMvBY5dLhq/cpOvw7Lk1nK/UF71aLG/ZnVYRA==",
|
||||
"version": "4.5.3",
|
||||
"resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.5.3.tgz",
|
||||
"integrity": "sha512-3yPecJoJHK/4c6aZhSvxOyG4vJKDshV36VHp0iVCDVh7o9w2vwi3NSnL2MMPj3YdduqaBcu7cGbggJQM0br9xA==",
|
||||
"requires": {
|
||||
"minimist": "^1.2.5",
|
||||
"neo-async": "^2.6.0",
|
||||
"optimist": "^0.6.1",
|
||||
"source-map": "^0.6.1",
|
||||
"uglify-js": "^3.1.4",
|
||||
"wordwrap": "^1.0.0"
|
||||
"uglify-js": "^3.1.4"
|
||||
}
|
||||
},
|
||||
"has-flag": {
|
||||
@ -838,9 +837,9 @@
|
||||
}
|
||||
},
|
||||
"lodash": {
|
||||
"version": "4.17.21",
|
||||
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz",
|
||||
"integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg=="
|
||||
"version": "4.17.19",
|
||||
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.19.tgz",
|
||||
"integrity": "sha512-JNvd8XER9GQX0v2qJgsaN/mzFCNA5BRe/j8JN9d+tWyGLSodKQHKFicdwNYzWwI3wjRnaKPsGj1XkBjx/F96DQ=="
|
||||
},
|
||||
"lodash.padend": {
|
||||
"version": "4.6.1",
|
||||
@ -927,9 +926,9 @@
|
||||
}
|
||||
},
|
||||
"minimist": {
|
||||
"version": "1.2.5",
|
||||
"resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz",
|
||||
"integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw=="
|
||||
"version": "0.0.10",
|
||||
"resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.10.tgz",
|
||||
"integrity": "sha1-3j+YVD2/lggr5IrRoMfNqDYwHc8="
|
||||
},
|
||||
"mkdirp": {
|
||||
"version": "0.5.1",
|
||||
@ -1072,6 +1071,15 @@
|
||||
"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",
|
||||
@ -1489,9 +1497,9 @@
|
||||
"integrity": "sha1-XAgOXWYcu+OCWdLnCjxyU+hziB0="
|
||||
},
|
||||
"uglify-js": {
|
||||
"version": "3.13.5",
|
||||
"resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.13.5.tgz",
|
||||
"integrity": "sha512-xtB8yEqIkn7zmOyS2zUNBsYCBRhDkvlNxMMY2smuJ/qA8NCHeQvKCF3i9Z4k8FJH4+PJvZRtMrPynfZ75+CSZw==",
|
||||
"version": "3.10.3",
|
||||
"resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.10.3.tgz",
|
||||
"integrity": "sha512-Lh00i69Uf6G74mvYpHCI9KVVXLcHW/xu79YTvH7Mkc9zyKUeSPz0owW0dguj0Scavns3ZOh3wY63J0Zb97Za2g==",
|
||||
"optional": true
|
||||
},
|
||||
"v8flags": {
|
||||
@ -1545,9 +1553,9 @@
|
||||
}
|
||||
},
|
||||
"wordwrap": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz",
|
||||
"integrity": "sha1-J1hIEIkUVqQXHI0CJkQa3pDLyus="
|
||||
"version": "0.0.3",
|
||||
"resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.3.tgz",
|
||||
"integrity": "sha1-o9XabNXAvAAI03I0u68b7WMFkQc="
|
||||
},
|
||||
"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.7.7",
|
||||
"handlebars": "^4.5.3",
|
||||
"inquirer": "^3.0.6",
|
||||
"mkdirp": "^0.5.1",
|
||||
"quickly-copy-file": "^1.0.0",
|
||||
|
||||
18
test/electron/package-lock.json
generated
18
test/electron/package-lock.json
generated
@ -810,9 +810,9 @@
|
||||
"dev": true
|
||||
},
|
||||
"electron": {
|
||||
"version": "11.1.0",
|
||||
"resolved": "https://registry.npmjs.org/electron/-/electron-11.1.0.tgz",
|
||||
"integrity": "sha512-RFAhR/852VMaRd9NSe7jprwSoG9dLc6u1GwnqRWg+/3cy/8Zrwt1Betw1lXiZH7hGuB9K2cqju83Xv5Pq5ZSGA==",
|
||||
"version": "11.0.4",
|
||||
"resolved": "https://registry.npmjs.org/electron/-/electron-11.0.4.tgz",
|
||||
"integrity": "sha512-ipfQ28Km52iuDSe9VK0G5uuyxi8qy8szg+01kQTRXZFCLlpgsgU+vQxWkld2tkhXWdu+H3dmgYHvWtoijOvhjw==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@electron/get": "^1.0.1",
|
||||
@ -1342,9 +1342,9 @@
|
||||
}
|
||||
},
|
||||
"lodash": {
|
||||
"version": "4.17.21",
|
||||
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz",
|
||||
"integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==",
|
||||
"version": "4.17.20",
|
||||
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.20.tgz",
|
||||
"integrity": "sha512-PlhdFcillOINfeV7Ni6oF1TAEayyZBoZ8bcshTHqOYJYlrqzRK5hagpagky5o4HfCzzd1TRkXPMFq6cKk9rGmA==",
|
||||
"dev": true,
|
||||
"optional": true
|
||||
},
|
||||
@ -2085,9 +2085,9 @@
|
||||
"dev": true
|
||||
},
|
||||
"ua-parser-js": {
|
||||
"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==",
|
||||
"version": "0.7.22",
|
||||
"resolved": "https://registry.npmjs.org/ua-parser-js/-/ua-parser-js-0.7.22.tgz",
|
||||
"integrity": "sha512-YUxzMjJ5T71w6a8WWVcMGM6YWOTX27rCoIQgLXiWaxqXSx9D7DNjiGWn1aJIRSQ5qr0xuhra77bSIh6voR/46Q==",
|
||||
"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.1.0",
|
||||
"electron": "^11.0.3",
|
||||
"spectron": "^13.0.0"
|
||||
}
|
||||
}
|
||||
|
||||
@ -6,7 +6,7 @@ const assert = require('chai').assert;
|
||||
return typeof global.gc === 'function' ? describe : describe.skip;
|
||||
})()('sync', function() {
|
||||
afterEach(() => {
|
||||
// Force garbage collection to shutdown `EventQueue`
|
||||
// Force garbage collection to shutdown `Channel`
|
||||
global.gc();
|
||||
});
|
||||
|
||||
@ -60,9 +60,9 @@ const assert = require('chai').assert;
|
||||
global.gc();
|
||||
});
|
||||
|
||||
it('should be able to unref event queue', function () {
|
||||
// If the EventQueue is not unreferenced, the test runner will not cleanly exit
|
||||
addon.leak_event_queue();
|
||||
it('should be able to unref channel', function () {
|
||||
// If the Channel is not unreferenced, the test runner will not cleanly exit
|
||||
addon.leak_channel();
|
||||
});
|
||||
|
||||
it('should drop leaked Root from the global queue', function (cb) {
|
||||
|
||||
@ -13,10 +13,10 @@ pub fn useless_root(mut cx: FunctionContext) -> JsResult<JsObject> {
|
||||
|
||||
pub fn thread_callback(mut cx: FunctionContext) -> JsResult<JsUndefined> {
|
||||
let callback = cx.argument::<JsFunction>(0)?.root(&mut cx);
|
||||
let queue = cx.queue();
|
||||
let channel = cx.channel();
|
||||
|
||||
std::thread::spawn(move || {
|
||||
queue.send(move |mut cx| {
|
||||
channel.send(move |mut cx| {
|
||||
let callback = callback.into_inner(&mut cx);
|
||||
let this = cx.undefined();
|
||||
let args = Vec::<Handle<JsValue>>::new();
|
||||
@ -33,14 +33,14 @@ pub fn thread_callback(mut cx: FunctionContext) -> JsResult<JsUndefined> {
|
||||
pub fn multi_threaded_callback(mut cx: FunctionContext) -> JsResult<JsUndefined> {
|
||||
let n = cx.argument::<JsNumber>(0)?.value(&mut cx);
|
||||
let callback = cx.argument::<JsFunction>(1)?.root(&mut cx);
|
||||
let queue = Arc::new(cx.queue());
|
||||
let channel = Arc::new(cx.channel());
|
||||
|
||||
for i in 0..(n as usize) {
|
||||
let callback = callback.clone(&mut cx);
|
||||
let queue = Arc::clone(&queue);
|
||||
let channel = Arc::clone(&channel);
|
||||
|
||||
std::thread::spawn(move || {
|
||||
queue.send(move |mut cx| {
|
||||
channel.send(move |mut cx| {
|
||||
let callback = callback.into_inner(&mut cx);
|
||||
let this = cx.undefined();
|
||||
let args = vec![cx.number(i as f64)];
|
||||
@ -63,17 +63,17 @@ pub struct AsyncGreeter {
|
||||
greeting: String,
|
||||
callback: Root<JsFunction>,
|
||||
shutdown: Option<Root<JsFunction>>,
|
||||
queue: Arc<EventQueue>,
|
||||
channel: Arc<Channel>,
|
||||
}
|
||||
|
||||
impl AsyncGreeter {
|
||||
fn greet<'a, C: Context<'a>>(&self, mut cx: C) -> JsResult<'a, JsUndefined> {
|
||||
let greeting = self.greeting.clone();
|
||||
let callback = self.callback.clone(&mut cx);
|
||||
let queue = Arc::clone(&self.queue);
|
||||
let channel = Arc::clone(&self.channel);
|
||||
|
||||
std::thread::spawn(move || {
|
||||
queue.send(|mut cx| {
|
||||
channel.send(|mut cx| {
|
||||
let callback = callback.into_inner(&mut cx);
|
||||
let this = cx.undefined();
|
||||
let args = vec![cx.string(greeting)];
|
||||
@ -110,7 +110,7 @@ pub fn greeter_new(mut cx: FunctionContext) -> JsResult<BoxedGreeter> {
|
||||
let callback = cx.argument::<JsFunction>(1)?.root(&mut cx);
|
||||
let shutdown = cx.argument_opt(2);
|
||||
|
||||
let queue = cx.queue();
|
||||
let channel = cx.channel();
|
||||
let shutdown = shutdown
|
||||
.map(|v| v.downcast_or_throw::<JsFunction, _>(&mut cx))
|
||||
.transpose()?
|
||||
@ -120,7 +120,7 @@ pub fn greeter_new(mut cx: FunctionContext) -> JsResult<BoxedGreeter> {
|
||||
greeting,
|
||||
callback,
|
||||
shutdown,
|
||||
queue: Arc::new(queue),
|
||||
channel: Arc::new(channel),
|
||||
}));
|
||||
|
||||
Ok(greeter)
|
||||
@ -133,14 +133,14 @@ pub fn greeter_greet(mut cx: FunctionContext) -> JsResult<JsUndefined> {
|
||||
greeter.greet(cx)
|
||||
}
|
||||
|
||||
pub fn leak_event_queue(mut cx: FunctionContext) -> JsResult<JsUndefined> {
|
||||
let queue = Box::new({
|
||||
let mut queue = cx.queue();
|
||||
queue.unref(&mut cx);
|
||||
queue
|
||||
pub fn leak_channel(mut cx: FunctionContext) -> JsResult<JsUndefined> {
|
||||
let channel = Box::new({
|
||||
let mut channel = cx.channel();
|
||||
channel.unref(&mut cx);
|
||||
channel
|
||||
});
|
||||
|
||||
Box::leak(queue);
|
||||
Box::leak(channel);
|
||||
|
||||
Ok(cx.undefined())
|
||||
}
|
||||
@ -148,7 +148,7 @@ pub fn leak_event_queue(mut cx: FunctionContext) -> JsResult<JsUndefined> {
|
||||
pub fn drop_global_queue(mut cx: FunctionContext) -> JsResult<JsUndefined> {
|
||||
struct Wrapper {
|
||||
callback: Option<Root<JsFunction>>,
|
||||
queue: EventQueue,
|
||||
channel: Channel,
|
||||
}
|
||||
|
||||
impl Finalize for Wrapper {}
|
||||
@ -158,7 +158,7 @@ pub fn drop_global_queue(mut cx: FunctionContext) -> JsResult<JsUndefined> {
|
||||
impl Drop for Wrapper {
|
||||
fn drop(&mut self) {
|
||||
if let Some(callback) = self.callback.take() {
|
||||
self.queue.send(|mut cx| {
|
||||
self.channel.send(|mut cx| {
|
||||
let callback = callback.into_inner(&mut cx);
|
||||
let this = cx.undefined();
|
||||
let args = vec![cx.undefined()];
|
||||
@ -172,11 +172,11 @@ pub fn drop_global_queue(mut cx: FunctionContext) -> JsResult<JsUndefined> {
|
||||
}
|
||||
|
||||
let callback = cx.argument::<JsFunction>(0)?.root(&mut cx);
|
||||
let queue = cx.queue();
|
||||
let channel = cx.channel();
|
||||
|
||||
let wrapper = cx.boxed(Wrapper {
|
||||
callback: Some(callback),
|
||||
queue,
|
||||
channel,
|
||||
});
|
||||
|
||||
// Put the `Wrapper` instance in a `Root` and drop it
|
||||
|
||||
@ -255,7 +255,7 @@ fn main(mut cx: ModuleContext) -> NeonResult<()> {
|
||||
cx.export_function("multi_threaded_callback", multi_threaded_callback)?;
|
||||
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("leak_channel", leak_channel)?;
|
||||
cx.export_function("drop_global_queue", drop_global_queue)?;
|
||||
|
||||
Ok(())
|
||||
|
||||
Loading…
Reference in New Issue
Block a user