-
Notifications
You must be signed in to change notification settings - Fork 290
Migration guide for 0.10 #859
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from 2 commits
Commits
Show all changes
7 commits
Select commit
Hold shift + click to select a range
d5f085f
Add migration guide for 0.10.
dherman efde9a7
Update README to point to new migration guide.
dherman c4ae1b5
Backticks for `new`
dherman 47c8056
Compute `call_with().args(...)` arguments inline, to demonstrate more…
dherman 1f30b91
Typo: `h32` -> `u32`
dherman 75e4558
Add missing type annotation
dherman c5d6ed8
Uncaught errors are now reported as promise rejections
dherman File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,246 @@ | ||
| # Neon 0.10 Migration Guide | ||
|
|
||
| With the API improvements of Neon 0.10, a few backwards-incompatible changes have been introduced. This migration guide provides all the information you should need to make the (small!) code changes required for upgrading to Neon 0.10. | ||
|
|
||
| We have made an effort to minimize these changes, and believe they should typically lead to simpler, clearer code. **If you run into any trouble migrating your code to 0.10, please file an issue or reach out for help on the [community Slack](https://rust-bindings.slack.com/)!** | ||
|
|
||
| # Major changes | ||
|
|
||
| ## Object property access is generic | ||
|
|
||
| To improve the ergonomics of the common case of downcasting the result of property access to a specific type, the signature of `Object::get()` has been changed to have a generic return type. This means that code that follows `Object::get()` with `.downcast_or_throw()` or `.downcast::<V>().or_throw()` no longer needs to do so. | ||
|
|
||
| **Before:** | ||
|
|
||
| ```rust | ||
| obj.get(&mut cx, "name")?.downcast::<V, _>(&mut cx).or_throw(&mut cx)? | ||
| ``` | ||
|
|
||
| **After (option 1):** | ||
|
|
||
| ```rust | ||
| obj.get::<V, _, _>(&mut cx, "name")? | ||
| ``` | ||
|
|
||
| **After (option 2):** | ||
|
|
||
| ```rust | ||
| let v: Handle<V> = obj.get(&mut cx, "name")? | ||
| ``` | ||
|
|
||
| ## Layered APIs for function calls | ||
|
|
||
| The API for calling (or constructing, i.e. the Neon equivalent of the JavaScript new operator) a JS function has been split into two layered alternatives. The existing `.call()` and `.construct()` functions are now a lower-level primitive, which no longer offers automatic downcasting of arguments or result. But Neon 0.10 now offers a more convenient API for calling functions with an options object and method chaining, with the introduction of the `.call_with()` and `.construct_with()` methods. | ||
|
|
||
| ### Example: Calling a function | ||
|
|
||
| **Before:** | ||
|
|
||
| ```rust | ||
| let s: Handle<JsString> = ...; | ||
| let n: Handle<JsNumber> = ...; | ||
| let args: Vec<Handle<JsValue>> = vec![s.upcast(), n.upcast()]; | ||
| let this = cx.global(); | ||
| f.call(&mut cx, this, args) | ||
| ``` | ||
|
|
||
| **After (low-level API):** | ||
|
|
||
| ```rust | ||
| let s: Handle<JsString> = ...; | ||
| let n: Handle<JsNumber> = ...; | ||
| let this = cx.global(); | ||
| f.call(&mut cx, this, [s.upcast(), n.upcast()]) | ||
| ``` | ||
|
|
||
| **After (high-level API):** | ||
|
|
||
| ```rust | ||
| let s: Handle<JsString> = ...; | ||
| let n: Handle<JsNumber> = ...; | ||
| f.call_with(&cx) | ||
| .args((s, n)) | ||
dherman marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| .apply(&mut cx) | ||
| ``` | ||
|
|
||
| ### Example: Constructing with a function | ||
|
|
||
| **Before:** | ||
|
|
||
| ```rust | ||
| let s: Handle<JsString> = ...; | ||
| let n: Handle<JsNumber> = ...; | ||
| let args: Vec<Handle<JsValue>> = vec![s.upcast(), n.upcast()]; | ||
| f.construct(&mut cx, args) | ||
| ``` | ||
|
|
||
| **After (low-level API):** | ||
|
|
||
| ```rust | ||
| let s: Handle<JsString> = ...; | ||
| let n: Handle<JsNumber> = ...; | ||
| f.construct(&mut cx, [s.upcast(), n.upcast()]) | ||
| ``` | ||
|
|
||
| **After (high-level API):** | ||
|
|
||
| ```rust | ||
| let s: Handle<JsString> = ...; | ||
| let n: Handle<JsNumber> = ...; | ||
| f.construct_with(&cx) | ||
| .args((s, n)) | ||
| .apply(&mut cx) | ||
| ``` | ||
|
|
||
| ## Idiomatic typed arrays | ||
|
|
||
| Neon 0.10 replaces the previous typed array API with a more idiomatic API. JavaScript typed arrays (e.g. [`Uint32Array`](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Uint32Array)) can be represented with corresponding Rust types (e.g. [`JsTypedArray<u32>`](https://docs.rs/neon/0.10.0-alpha.3/neon/types/struct.JsTypedArray.html)), allowing easy access to their internals as Rust slices. | ||
|
|
||
| ### Example: Reading a buffer | ||
|
|
||
| **Before:** | ||
|
|
||
| ```rust | ||
| let b: Handle<JsArrayBuffer> = ...; | ||
| { | ||
| let guard = cx.lock(); | ||
| let data = b.borrow(&guard); | ||
| let slice = data.as_slice::<u32>(); | ||
| ... | ||
| } | ||
| ``` | ||
|
|
||
| **After:** | ||
|
|
||
| ```rust | ||
| let b: Handle<JsTypedArray<u32>> = ...; | ||
| let slice = b.as_slice(&cx); | ||
| ``` | ||
|
|
||
| ### Example: Reading and writing buffers | ||
|
|
||
| **Before:** | ||
|
|
||
| ```rust | ||
| let b1: Handle<JsArrayBuffer> = ...; | ||
| let b2: Handle<JsArrayBuffer> = ...; | ||
| { | ||
| let guard = cx.lock(); | ||
| let data1 = b1.borrow(&guard); | ||
| let data2 = b2.borrow(&guard); | ||
| let slice1 = data1.as_slice::<u32>(); | ||
| let slice2 = data2.as_slice::<u32>(); | ||
| ... | ||
| } | ||
| ``` | ||
|
|
||
| **After:** | ||
|
|
||
| ```rust | ||
| let src_buf: Handle<JsTypedArray<u32>> = ...; | ||
| let dst_buf: Handle<JsTypedArray<h32>> = ...; | ||
dherman marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| { | ||
| let lock = cx.lock(); | ||
| let src = src_buf.as_slice(&lock).unwrap(); | ||
| let dst = dst_buf.as_mut_slice(&lock).unwrap(); | ||
| ... | ||
| } | ||
| ``` | ||
|
|
||
| ### Example: Casting buffer types | ||
|
|
||
| Previous versions of Neon came with a special datatype for casting the data of an ArrayBuffer, but this had incomplete handling of unaligned data and is deprecated in Neon 0.10. Crates like [bytemuck](https://crates.io/crates/bytemuck) can be used for casting buffer slices. | ||
|
|
||
| **Before:** | ||
|
|
||
| ```rust | ||
| let b: Handle<JsArrayBuffer> = ...; | ||
| { | ||
| let guard = cx.lock(); | ||
| let data = b.borrow(&guard); | ||
| let u8_slice = data.as_slice::<u8>(); | ||
| let f32_slice = data.as_slice::<f32>(); | ||
| ... | ||
| } | ||
| ``` | ||
|
|
||
| **After:** | ||
|
|
||
| ```rust | ||
| use bytemuck::cast_slice; | ||
|
|
||
| let b: Handle<JsArrayBuffer> = ...; | ||
| let u8_slice = b.as_slice(&cx); | ||
| let f32_slice = cast_slice(u8_slice); | ||
dherman marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| ``` | ||
|
|
||
| # Minor changes | ||
|
|
||
| ## Uncaught errors in tasks | ||
|
|
||
| Starting with 0.10, uncaught errors (whether Rust panics or JavaScript exceptions) in a task are now captured and reported to Node as an [`uncaughtException` event](https://nodejs.org/api/process.html#event-uncaughtexception). Previously, an uncaught JavaScript exception would be ignored. To handle uncaught exceptions, either wrap the body of a task with [`try_catch`](https://docs.rs/neon/0.10.0-alpha.3/neon/context/trait.Context.html#method.try_catch) or, alternatively, capture all uncaught exceptions in Node with [`process.setUncaughtExceptionCaptureCallback()`](https://nodejs.org/api/process.html#processsetuncaughtexceptioncapturecallbackfn). | ||
dherman marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
|
|
||
| **Before:** | ||
|
|
||
| ```rust | ||
| cx.task(|| "hello".to_string()) | ||
| .and_then(|mut cx, _| { | ||
| cx.throw_error("ignore me") | ||
| }) | ||
| ``` | ||
|
|
||
| **After:** | ||
|
|
||
| ```rust | ||
| cx.task(|| "hello".to_string()) | ||
| .and_then(|mut cx, _| { | ||
| let _ = cx.try_catch(() { | ||
| cx.throw_error("ignore me") | ||
| }); | ||
| Ok(()) | ||
| }) | ||
| ``` | ||
|
|
||
| ## `Channel::send` returns `JoinHandle` | ||
|
|
||
| The [`Channel::send()`](https://docs.rs/neon/0.10.0-alpha.3/neon/event/struct.Channel.html#method.send) method now returns a [`JoinHandle`](https://docs.rs/neon/0.10.0-alpha.3/neon/event/struct.JoinHandle.html) type instead of `()`, allowing code to optionally and conveniently block on the result with [`JoinHandle::join()`](https://docs.rs/neon/0.10.0-alpha.3/neon/event/struct.JoinHandle.html#method.join). Non-blocking code should usually work with little to no change; sometimes a semicolon may be needed to explicitly ignore the `JoinHandle`. | ||
|
|
||
| **Before:** | ||
|
|
||
| ```rust | ||
| fn helper<'a, C: Context<'a>>(cx: &mut C, ch: Channel) { | ||
| ch.send(...) | ||
| } | ||
| ``` | ||
|
|
||
| **After:** | ||
|
|
||
| ```rust | ||
| fn helper<'a, C: Context<'a>>(cx: &mut C, ch: Channel) { | ||
| ch.send(...); | ||
| } | ||
| ``` | ||
|
|
||
| ## Value types aren't cloneable | ||
|
|
||
| Previous versions of Neon had a safety bug in allowing types that implement the [`Value`](https://docs.rs/neon/0.10.0-alpha.3/neon/types/trait.Value.html) trait to be cloned. This has been fixed in Neon 0.10. It should be rare for code to ever need to clone a value. In most cases where this may be occurring, a [`Handle`](https://docs.rs/neon/0.10.0-alpha.3/neon/handle/struct.Handle.html) or reference (`&`) should work. For longer-lived use cases such as storing a value in a Rust static variable, use a [`Root`](https://docs.rs/neon/0.10.0-alpha.3/neon/handle/struct.Root.html). | ||
|
|
||
| **Before:** | ||
|
|
||
| ```rust | ||
| fn helper<'a, C: Context<'a>>(cx: &mut C, s: JsString) -> ... { | ||
| ... | ||
| } | ||
| ``` | ||
|
|
||
| **After:** | ||
|
|
||
| ```rust | ||
| fn helper<'a, C: Context<'a>>(cx: &mut C, s: Handle<JsString>) -> ... { | ||
| ... | ||
| } | ||
| ``` | ||
|
|
||
| ## Context methods now all take `&mut self` | ||
|
|
||
| Context methods such as [`execute_scoped`](https://docs.rs/neon/0.10.0-alpha.3/neon/context/trait.Context.html#method.execute_scoped), [`compute_scoped`](https://docs.rs/neon/0.10.0-alpha.3/neon/context/trait.Context.html#method.compute_scoped), and [`lock`](https://docs.rs/neon/0.10.0-alpha.3/neon/context/trait.Context.html#method.lock) all take `&mut self` instead of the previous `&self`. This was necessary for safety and is more consistent with other `Context` methods. In normal usage, this should not require code changes. | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
File renamed without changes.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.