Skip to content

Commit 903efe2

Browse files
committed
Adopt wasm-bindgen unwind safety enforcement
Update wasm-bindgen submodule to pick up unwind safety enforcement on #[wasm_bindgen] exports (wasm-bindgen/wasm-bindgen#5128). Add wasm-streams and gloo as submodules pointing at forks that propagate unwind safety bounds through closures and timers. Patch both via [patch.crates-io] so the worker crate compiles against the new enforcement. Refactor durable object test fixtures to use Cell wrapped in AssertUnwindSafe, replacing RefCell. Cell is single-threaded safe for Copy types because every operation is an atomic move with no borrow guard to leave dangling; AssertUnwindSafe is the narrow, honest assertion for the interior mutability fields without making blanket promises about State/Env. Add cargo url replacement so transitive git deps fetched via SSH fall back to HTTPS for cargo generate users.
1 parent 3d0903a commit 903efe2

43 files changed

Lines changed: 144 additions & 124 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.cargo/config.toml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,5 @@
11
[target.wasm32-unknown-unknown]
22
rustflags = ["--cfg", "getrandom_backend=\"wasm_js\""]
3+
4+
[url."https://github.com/"]
5+
insteadOf = ["git@github.com:", "ssh://git@github.com/"]

.gitmodules

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,14 @@
11
[submodule "wasm-bindgen"]
22
path = wasm-bindgen
33
url = https://github.com/wasm-bindgen/wasm-bindgen
4-
[submodule "wasm-streams"]
5-
path = wasm-streams
6-
url = https://github.com/guybedford/wasm-streams
74
[submodule "ts-gen"]
85
path = ts-gen
96
url = https://github.com/wasm-bindgen/ts-gen
7+
[submodule "wasm-streams"]
8+
path = wasm-streams
9+
url = https://github.com/guybedford/wasm-streams
10+
branch = fix-unwind-safety-impls
11+
[submodule "gloo"]
12+
path = gloo
13+
url = https://github.com/guybedford/gloo
14+
branch = fix-gloo-timers-unwind-safety

Cargo.lock

Lines changed: 11 additions & 15 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 19 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@ exclude = [
1414
"examples/axum",
1515
"templates/*",
1616
"wasm-bindgen",
17+
"wasm-streams",
18+
"gloo",
1719
"generated",
1820
]
1921
resolver = "2"
@@ -27,7 +29,7 @@ chrono = { version = "0.4.41", default-features = false, features = [
2729
futures-channel = "0.3.31"
2830
futures-util = { version = "0.3.31", default-features = false }
2931
http = "1.3"
30-
js-sys = { version = "0.3.98" }
32+
js-sys = { version = "0.3.99" }
3133
serde = { version = "1.0.164", features = ["derive"] }
3234
strum = { version = "0.27", features = ["derive"] }
3335
serde_json = "1.0.140"
@@ -36,14 +38,14 @@ syn = "2.0.17"
3638
trybuild = "1.0"
3739
proc-macro2 = "1.0.60"
3840
quote = "1.0.28"
39-
wasm-bindgen = { version = "0.2.121" }
40-
wasm-bindgen-cli-support = { version = "0.2.121" }
41-
wasm-bindgen-futures = { version = "0.4.71" }
42-
wasm-bindgen-macro-support = { version = "0.2.121" }
43-
wasm-bindgen-shared = { version = "0.2.121" }
44-
wasm-bindgen-test = { version = "0.3.71" }
41+
wasm-bindgen = { version = "0.2.122" }
42+
wasm-bindgen-cli-support = { version = "0.2.122" }
43+
wasm-bindgen-futures = { version = "0.4.72" }
44+
wasm-bindgen-macro-support = { version = "0.2.122" }
45+
wasm-bindgen-shared = { version = "0.2.122" }
46+
wasm-bindgen-test = { version = "0.3.72" }
4547
wasm-streams = { version = "0.5.0" }
46-
web-sys = { version = "0.3.98", features = [
48+
web-sys = { version = "0.3.99", features = [
4749
"AbortController",
4850
"AbortSignal",
4951
"BinaryType",
@@ -105,11 +107,12 @@ opt-level = "z"
105107
# These are local patches we use to test against local wasm bindgen
106108
# We always align on the exact stable wasm bindgen version for releases
107109
[patch.crates-io]
108-
js-sys = { version = "0.3.98", path = './wasm-bindgen/crates/js-sys' }
109-
wasm-bindgen = { version = "0.2.121", path = './wasm-bindgen' }
110-
wasm-bindgen-cli-support = { version = "0.2.121", path = "./wasm-bindgen/crates/cli-support" }
111-
wasm-bindgen-futures = { version = "0.4.71", path = './wasm-bindgen/crates/futures' }
112-
wasm-bindgen-macro-support = { version = "0.2.121", path = "./wasm-bindgen/crates/macro-support" }
113-
wasm-bindgen-shared = { version = "0.2.121", path = "./wasm-bindgen/crates/shared" }
114-
wasm-bindgen-test = { version = "0.3.71", path = "./wasm-bindgen/crates/test" }
115-
web-sys = { version = "0.3.98", path = './wasm-bindgen/crates/web-sys' }
110+
js-sys = { version = "0.3.99", path = './wasm-bindgen/crates/js-sys' }
111+
wasm-bindgen = { version = "0.2.122", path = './wasm-bindgen' }
112+
wasm-bindgen-cli-support = { version = "0.2.122", path = "./wasm-bindgen/crates/cli-support" }
113+
wasm-bindgen-futures = { version = "0.4.72", path = './wasm-bindgen/crates/futures' }
114+
wasm-bindgen-macro-support = { version = "0.2.122", path = "./wasm-bindgen/crates/macro-support" }
115+
wasm-bindgen-shared = { version = "0.2.122", path = "./wasm-bindgen/crates/shared" }
116+
wasm-bindgen-test = { version = "0.3.72", path = "./wasm-bindgen/crates/test" }
117+
web-sys = { version = "0.3.99", path = './wasm-bindgen/crates/web-sys' }
118+
wasm-streams = { version = "0.5.0", path = './wasm-streams' }

examples/rpc-client/src/calculator.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ impl Calculator for CalculatorService {
2828
async fn add(&self, a: u32, b: u32) -> ::worker::Result<u32> {
2929
let promise = self.0.add(a, b)?;
3030
let fut = ::worker::send::SendFuture::new(
31-
::worker::wasm_bindgen_futures::JsFuture::from(promise),
31+
::worker::js_sys::futures::JsFuture::from(promise),
3232
);
3333
let output = fut.await?;
3434
Ok(::serde_wasm_bindgen::from_value(output)?)

gloo

Submodule gloo added at d73276e

test/src/container.rs

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@ use std::time::Duration;
88

99
use futures_util::StreamExt;
1010
use wasm_bindgen::{throw_str, UnwrapThrowExt};
11-
use wasm_bindgen_futures::spawn_local;
1211
use worker::*;
1312

1413
use crate::SomeSharedData;
@@ -29,7 +28,7 @@ impl DurableObject for EchoContainer {
2928
}
3029
let ready = Arc::new(AtomicBool::new(false));
3130
let ready_clone = Arc::clone(&ready);
32-
spawn_local(async move {
31+
js_sys::futures::spawn_local(async move {
3332
for _ in 0..10 {
3433
match container
3534
.get_tcp_port(8080)
@@ -112,7 +111,7 @@ pub async fn handle_container(
112111
None => return Response::error("Expected websocket response", 500),
113112
};
114113
ws.accept()?;
115-
spawn_local(redir_websocket(ws, server));
114+
js_sys::futures::spawn_local(redir_websocket(ws, server));
116115
Response::from_websocket(client)
117116
}
118117
_ => Response::error("Container method not allowed", 405),

test/src/counter.rs

Lines changed: 21 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,37 +1,39 @@
1-
use std::cell::RefCell;
1+
use std::cell::Cell;
2+
use std::panic::AssertUnwindSafe;
23
use tokio_stream::{StreamExt, StreamMap};
34
use worker::{
4-
durable_object, wasm_bindgen, wasm_bindgen_futures, DurableObject, Env, Error, Method, Request,
5-
Response, ResponseBuilder, Result, State, WebSocket, WebSocketIncomingMessage, WebSocketPair,
6-
WebsocketEvent,
5+
durable_object, wasm_bindgen, DurableObject, Env, Error, Method, Request, Response,
6+
ResponseBuilder, Result, State, WebSocket, WebSocketIncomingMessage, WebSocketPair,
7+
WebsocketEvent, js_sys
78
};
89

910
use crate::SomeSharedData;
1011

1112
#[durable_object]
1213
pub struct Counter {
13-
count: RefCell<usize>,
14-
unstored_count: RefCell<usize>,
14+
count: AssertUnwindSafe<Cell<usize>>,
15+
unstored_count: AssertUnwindSafe<Cell<usize>>,
1516
state: State,
16-
initialized: RefCell<bool>,
17+
initialized: AssertUnwindSafe<Cell<bool>>,
1718
env: Env,
1819
}
1920

2021
impl DurableObject for Counter {
2122
fn new(state: State, env: Env) -> Self {
2223
Self {
23-
count: RefCell::new(0),
24-
unstored_count: RefCell::new(0),
25-
initialized: RefCell::new(false),
24+
count: AssertUnwindSafe(Cell::new(0)),
25+
unstored_count: AssertUnwindSafe(Cell::new(0)),
26+
initialized: AssertUnwindSafe(Cell::new(false)),
2627
state,
2728
env,
2829
}
2930
}
3031

3132
async fn fetch(&self, req: Request) -> Result<Response> {
32-
if !*self.initialized.borrow() {
33-
*self.initialized.borrow_mut() = true;
34-
*self.count.borrow_mut() = self.state.storage().get("count").await?.unwrap_or(0);
33+
if !self.initialized.get() {
34+
self.initialized.set(true);
35+
self.count
36+
.set(self.state.storage().get("count").await?.unwrap_or(0));
3537
}
3638

3739
if req.path().eq("/ws") {
@@ -49,15 +51,15 @@ impl DurableObject for Counter {
4951
.empty());
5052
}
5153

52-
*self.unstored_count.borrow_mut() += 1;
53-
*self.count.borrow_mut() += 10;
54-
let count = *self.count.borrow();
54+
self.unstored_count.set(self.unstored_count.get() + 1);
55+
self.count.set(self.count.get() + 10);
56+
let count = self.count.get();
5557
self.state.storage().put("count", count).await?;
5658

5759
Response::ok(format!(
5860
"[durable_object]: self.count: {}, self.unstored_count: {}, secret value: {}",
59-
self.count.borrow(),
60-
self.unstored_count.borrow(),
61+
self.count.get(),
62+
self.unstored_count.get(),
6163
self.env.secret("SOME_SECRET")?
6264
))
6365
}
@@ -134,7 +136,7 @@ pub async fn handle_websocket(req: Request, env: Env, _data: SomeSharedData) ->
134136
let do_ws = res.websocket().expect("server did not accept websocket");
135137
do_ws.accept()?;
136138

137-
wasm_bindgen_futures::spawn_local(async move {
139+
js_sys::futures::spawn_local(async move {
138140
let event_stream = server.events().expect("could not open stream");
139141
let do_event_stream = do_ws.events().expect("could not open stream");
140142

test/src/durable.rs

Lines changed: 13 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
use serde::Serialize;
2+
use std::cell::Cell;
3+
use std::collections::HashMap;
24
use std::convert::TryFrom;
3-
use std::{cell::RefCell, collections::HashMap};
5+
use std::panic::AssertUnwindSafe;
46
use worker::DurableObject;
57

68
use worker::{
@@ -13,14 +15,14 @@ use worker::{
1315
#[durable_object]
1416
pub struct MyClass {
1517
state: State,
16-
number: RefCell<usize>,
18+
number: AssertUnwindSafe<Cell<usize>>,
1719
}
1820

1921
impl DurableObject for MyClass {
2022
fn new(state: State, _env: Env) -> Self {
2123
Self {
2224
state,
23-
number: RefCell::new(0),
25+
number: AssertUnwindSafe(Cell::new(0)),
2426
}
2527
}
2628

@@ -153,13 +155,14 @@ impl DurableObject for MyClass {
153155
);
154156
}
155157

156-
*self.number.borrow_mut() = storage.get("count").await?.unwrap_or(0) + 1;
158+
self.number
159+
.set(storage.get("count").await?.unwrap_or(0) + 1);
157160

158161
storage.delete_all().await?;
159162

160-
let count = *self.number.borrow();
163+
let count = self.number.get();
161164
storage.put("count", count).await?;
162-
Response::ok(self.number.borrow().to_string())
165+
Response::ok(self.number.get().to_string())
163166
}
164167
"/transaction" => {
165168
Response::error("transactional storage API is still unstable", 501)
@@ -178,20 +181,20 @@ impl DurableObject for MyClass {
178181
pub struct AnotherClass {
179182
#[allow(unused)]
180183
state: State,
181-
counter: RefCell<i32>,
184+
counter: AssertUnwindSafe<Cell<i32>>,
182185
}
183186

184187
impl DurableObject for AnotherClass {
185188
fn new(state: State, _env: Env) -> Self {
186189
Self {
187190
state,
188-
counter: RefCell::new(0),
191+
counter: AssertUnwindSafe(Cell::new(0)),
189192
}
190193
}
191194

192195
async fn fetch(&self, _req: Request) -> Result<Response> {
193-
*self.counter.borrow_mut() += 1;
194-
Response::ok(format!("Counter: {}", self.counter.borrow()))
196+
self.counter.set(self.counter.get() + 1);
197+
Response::ok(format!("Counter: {}", self.counter.get()))
195198
}
196199
}
197200

0 commit comments

Comments
 (0)