wasm_bindgen/closure.rs
1//! Support for closures in `wasm-bindgen`
2//!
3//! This module defines the [`ScopedClosure`] type which is used to pass Rust closures
4//! to JavaScript. All closures are unwind safe by default: panics are caught and converted to
5//! JavaScript exceptions when built with `panic=unwind`.
6//!
7//! # Immutable by Default
8//!
9//! The closure API defaults to **immutable** (`Fn`) closures because they are more
10//! likely to satisfy `UnwindSafe` automatically:
11//!
12//! - `&T` where `T: RefUnwindSafe` is `UnwindSafe`
13//! - `&mut T` is **never** `UnwindSafe` regardless of `T`
14//!
15//! This means:
16//! - [`ScopedClosure::borrow`] creates an immutable `Fn` closure
17//! - [`ScopedClosure::borrow_mut`] creates a mutable `FnMut` closure
18//! - [`ImmediateClosure::new`] creates an immutable `Fn` closure
19//! - [`ImmediateClosure::new_mut`] creates a mutable `FnMut` closure
20//!
21//! Immutable closures can be upcasted to mutable closures using [`upcast_ref`](crate::Upcast::upcast_ref).
22//!
23//! # Type Aliases
24//!
25//! - [`ScopedClosure<'a, T>`] — The unified closure type with a lifetime parameter
26//! - [`Closure<T>`] — Alias for `ScopedClosure<'static, T>` (for backwards compatibility)
27//! - [`ImmediateClosure<'a, T>`] — Lightweight wrapper for immediate callbacks with unwind safety
28//!
29//! # Unwind Safety
30//!
31//! For immediate/synchronous callbacks, you have two options:
32//!
33//! - **[`ImmediateClosure`]**: Recommended when you want panics to be caught and converted
34//! to JavaScript exceptions. This is safer but has slight overhead.
35//!
36//! - **`&dyn FnMut` / `&dyn Fn`**: Use when you don't need unwind safety and prefer
37//! panics to abort the process.
38//!
39//! For [`ScopedClosure`], the default constructors (`borrow`, `borrow_mut`, `own`) catch
40//! panics, while the `_aborting` variants (`borrow_aborting`, `borrow_mut_aborting`, etc.) do not.
41//!
42//! # Ownership Model
43//!
44//! `ScopedClosure` follows the same ownership model as other wasm-bindgen types:
45//! the JavaScript reference remains valid until the Rust value is dropped. When
46//! dropped, the closure is invalidated and any subsequent calls from JavaScript
47//! will throw an exception.
48//!
49//! For borrowed closures created with `borrow`/`borrow_mut`, Rust's borrow checker
50//! ensures the `ScopedClosure` cannot outlive the closure's captured data.
51//!
52//! See the [`ScopedClosure`] type documentation for detailed examples.
53
54#![allow(clippy::fn_to_numeric_cast)]
55use alloc::boxed::Box;
56use alloc::string::String;
57use core::fmt;
58use core::mem::{self, ManuallyDrop};
59
60use crate::__rt::marker::ErasableGeneric;
61use crate::__rt::marker::MaybeUnwindSafe;
62use crate::describe::*;
63use crate::JsValue;
64use crate::{convert::*, JsCast};
65use core::marker::PhantomData;
66use core::panic::AssertUnwindSafe;
67
68#[wasm_bindgen_macro::wasm_bindgen(wasm_bindgen = crate)]
69extern "C" {
70 type JsClosure;
71
72 #[wasm_bindgen(method)]
73 fn _wbg_cb_unref(js: &JsClosure);
74}
75
76/// A closure with a lifetime parameter that represents a Rust closure passed to JavaScript.
77///
78/// `ScopedClosure<'a, T>` is the unified closure type. The lifetime `'a` indicates
79/// how long the closure is valid:
80///
81/// - **`ScopedClosure<'static, T>`** - An owned closure with heap-allocated data. Requires
82/// `'static` captures. Use for long-lived closures like event listeners and timers.
83/// Created with [`Closure::new`] or [`ScopedClosure::own`]. May transfer ownership to the
84/// JS GC using finalizers.
85///
86/// - **`ScopedClosure<'a, T>`** (non-`'static`) - A borrowed closure referencing stack data.
87/// Allows non-`'static` captures. Use for immediate/synchronous callbacks. Created with
88/// [`ScopedClosure::borrow`] (for `FnMut`) or [`ScopedClosure::borrow_immutable`] (for `Fn`).
89/// Cannot transfer ownership to JS GC.
90///
91/// [`Closure<T>`] is currently a type alias for `ScopedClosure<'static, T>`. In
92/// a future release, a lifetime argument will be added to this alias.
93///
94/// # Ownership Model
95///
96/// `ScopedClosure` follows the same ownership model as other wasm-bindgen types:
97/// the JavaScript reference remains valid until the Rust value is dropped. When
98/// dropped, the closure is invalidated and any subsequent calls from JavaScript
99/// will throw: "closure invoked recursively or after being dropped".
100///
101/// For `'static` closures, you can also:
102/// - Pass by value to transfer ownership to JS (implements [`IntoWasmAbi`])
103/// - Call [`forget()`](Self::forget) to leak the closure (JS can use it indefinitely)
104/// - Call [`into_js_value()`](Self::into_js_value) to transfer to JS GC management
105///
106/// # Lifetime Safety
107///
108/// For borrowed closures, Rust's borrow checker ensures that `ScopedClosure` cannot
109/// be held longer than the closure's captured data:
110///
111/// ```ignore
112/// let mut sum = 0;
113/// let mut f = |x: u32| { sum += x; }; // f borrows sum
114/// let closure = ScopedClosure::borrow(&mut f); // closure borrows f
115/// // closure cannot outlive f, and f cannot outlive sum
116/// ```
117///
118/// # Examples
119///
120/// ## Borrowed closures with `ScopedClosure::borrow`
121///
122/// Use for immediate/synchronous callbacks where JS calls the closure right away:
123///
124/// ```ignore
125/// use wasm_bindgen::prelude::*;
126///
127/// #[wasm_bindgen]
128/// extern "C" {
129/// fn call_immediately(cb: &ScopedClosure<dyn FnMut(u32)>);
130/// }
131///
132/// let mut sum = 0;
133/// {
134/// let mut f = |x: u32| { sum += x; };
135/// let closure = ScopedClosure::borrow(&mut f);
136/// call_immediately(&closure);
137/// } // closure dropped here, JS function invalidated
138/// assert_eq!(sum, 42);
139/// ```
140///
141/// ## Owned closures with `Closure::new`
142///
143/// Use for long-lived callbacks like event listeners and timers:
144///
145/// ```ignore
146/// use wasm_bindgen::prelude::*;
147///
148/// #[wasm_bindgen]
149/// extern "C" {
150/// fn setInterval(closure: &Closure<dyn FnMut()>, time: u32) -> i32;
151/// }
152///
153/// // Closure::new requires 'static, so use `move` to capture by value
154/// let cb = Closure::new(move || {
155/// // ...
156/// });
157/// setInterval(&cb, 1000);
158/// // Must keep `cb` alive or call `cb.forget()` to transfer to JS
159/// ```
160///
161/// ## Transferring ownership to JS
162///
163/// Pass a `ScopedClosure<'static, T>` by value to transfer ownership:
164///
165/// ```ignore
166/// use wasm_bindgen::prelude::*;
167///
168/// #[wasm_bindgen]
169/// extern "C" {
170/// fn set_one_shot_callback(cb: ScopedClosure<dyn FnMut()>);
171/// }
172///
173/// let cb = ScopedClosure::own(|| { /* ... */ });
174/// set_one_shot_callback(cb); // Ownership transferred, no need to store
175/// ```
176pub struct ScopedClosure<'a, T: ?Sized> {
177 js: JsClosure,
178 // careful: must be Box<T> not just T because unsized PhantomData
179 // seems to have weird interaction with Pin<>
180 _marker: PhantomData<Box<T>>,
181 _lifetime: PhantomData<&'a ()>,
182}
183
184/// Alias for [`ScopedClosure<'static, T>`] for backwards compatibility.
185///
186/// In a future major version, `Closure` will become `ScopedClosure<'a, T>` with a
187/// lifetime parameter.
188pub type Closure<T> = ScopedClosure<'static, T>;
189
190// ScopedClosure is Unpin because it only contains a JsValue (which is just a u32)
191// and PhantomData markers. The closure data is either on the heap (owned) or
192// referenced through a raw pointer (borrowed), neither of which is stored inline.
193impl<T: ?Sized> Unpin for ScopedClosure<'_, T> {}
194
195fn _assert_compiles<T>(pin: core::pin::Pin<&mut ScopedClosure<'static, T>>) {
196 let _ = &mut *pin.get_mut();
197}
198
199impl<T: ?Sized> Drop for ScopedClosure<'_, T> {
200 fn drop(&mut self) {
201 // Invalidate the closure on the JS side.
202 //
203 // The JS bindings distinguish owned vs borrowed closures via the `dtor_idx`
204 // encoded in `WasmDescribe`: owned closures pass a non-zero destructor
205 // function pointer, borrowed closures pass `0`.
206 //
207 // For owned closures (`Closure::new`/`ScopedClosure::own`), this decreases
208 // the refcount and frees the Rust heap data when the count reaches zero.
209 //
210 // For borrowed closures (`ScopedClosure::borrow`/`borrow_mut`), this sets
211 // state.a = state.b = 0 to prevent any further calls to the closure.
212 self.js._wbg_cb_unref();
213 }
214}
215
216impl<'a, T> ScopedClosure<'a, T>
217where
218 T: ?Sized + WasmClosure,
219{
220 /// Obtain a `&JsValue` reference for this closure
221 pub fn as_js_value(&self) -> &JsValue {
222 self.js.unchecked_ref()
223 }
224}
225
226/// Methods for creating and managing `'static` closures.
227///
228/// These methods are only available on `ScopedClosure<'static, T>`
229/// not on borrowed `ScopedClosure<'a, T>` where `'a` is not `'static`.
230impl<T> ScopedClosure<'static, T>
231where
232 T: ?Sized + WasmClosure,
233{
234 /// Creates a new owned `'static` closure that aborts on panic.
235 ///
236 /// Alias for [`own_aborting`](Self::own_aborting).
237 ///
238 /// **Note: Not unwind safe. Prefer [`own`](Self::own) or `own` with
239 /// [`AssertUnwindSafe`](core::panic::AssertUnwindSafe) when possible.**
240 pub fn new<F>(t: F) -> Self
241 where
242 F: IntoWasmClosure<T> + 'static,
243 {
244 Self::_wrap(Box::new(t).unsize(), false)
245 }
246
247 /// Creates a new static owned `ScopedClosure<'static, T>` from the provided
248 /// Rust function, with panic unwind support.
249 ///
250 /// The type parameter `T` determines whether the closure is `Fn` or `FnMut`.
251 ///
252 /// Supports unwind via its UnwindSafe bound when building with panic=unwind.
253 ///
254 /// When provided to a JS function as an own value, to be managed by the JS GC.
255 ///
256 /// See [`borrow`](Self::borrow) for creating a borrowed `ScopedClosure` with
257 /// an associated lifetime (defaults to immutable `Fn`).
258 pub fn own<F>(t: F) -> Self
259 where
260 F: IntoWasmClosure<T> + MaybeUnwindSafe + 'static,
261 {
262 Self::_wrap(Box::new(t).unsize(), true)
263 }
264
265 /// Creates a new owned `'static` closure that aborts on panic.
266 ///
267 /// Unlike [`own`](Self::own), this version does NOT catch panics and does NOT
268 /// require `UnwindSafe`. If the closure panics, the process will abort.
269 ///
270 /// The type parameter `T` determines whether the closure is `Fn` or `FnMut`.
271 ///
272 /// When provided to a JS function as an own value, to be managed by the JS GC.
273 ///
274 /// See [`borrow_aborting`](Self::borrow_aborting) for creating a borrowed
275 /// `ScopedClosure` with an associated lifetime.
276 ///
277 /// **Note: Not unwind safe. Prefer [`own`](Self::own) or `own` with
278 /// [`AssertUnwindSafe`](core::panic::AssertUnwindSafe) when possible.**
279 pub fn own_aborting<F>(t: F) -> Self
280 where
281 F: IntoWasmClosure<T> + 'static,
282 {
283 Self::_wrap(Box::new(t).unsize(), false)
284 }
285
286 /// A more direct version of `Closure::new` which creates a `Closure` from
287 /// a `Box<dyn Fn>`/`Box<dyn FnMut>`, which is how it's kept internally.
288 ///
289 /// This version does NOT catch panics. If the closure panics, the process will abort.
290 ///
291 /// **Note: Not unwind safe. Prefer [`wrap_assert_unwind_safe`](Self::wrap_assert_unwind_safe)
292 /// when possible.**
293 pub fn wrap<F>(data: Box<F>) -> Self
294 where
295 F: IntoWasmClosure<T> + ?Sized,
296 {
297 Self::_wrap(data.unsize(), false)
298 }
299
300 /// A more direct version of `Closure::new` which creates a `Closure` from
301 /// a `Box<dyn Fn>`/`Box<dyn FnMut>`, which is how it's kept internally.
302 ///
303 /// **Safety: Unwind safety is assumed when using this function, like using
304 /// `AssertUnwindSafe(...)`, this must be verified explicitly.**
305 ///
306 /// This version catches panics when unwinding is available.
307 pub fn wrap_assert_unwind_safe<F>(data: Box<F>) -> Self
308 where
309 F: IntoWasmClosure<T> + ?Sized,
310 {
311 Self::_wrap(data.unsize(), true)
312 }
313
314 #[cfg(all(feature = "std", target_arch = "wasm32", panic = "unwind"))]
315 fn _wrap(data: Box<T>, unwind_safe: bool) -> Self {
316 Self {
317 js: crate::__rt::wbg_cast(OwnedClosureUnwind { data, unwind_safe }),
318 _marker: PhantomData,
319 _lifetime: PhantomData,
320 }
321 }
322
323 #[cfg(not(all(feature = "std", target_arch = "wasm32", panic = "unwind")))]
324 fn _wrap(data: Box<T>, _unwind_safe: bool) -> Self {
325 Self {
326 js: crate::__rt::wbg_cast(OwnedClosure(data)),
327 _marker: PhantomData,
328 _lifetime: PhantomData,
329 }
330 }
331
332 /// Creates a scoped closure by borrowing an immutable `Fn` closure with
333 /// panic unwind support.
334 ///
335 /// This is the recommended way to pass closures to JavaScript for immediate/
336 /// synchronous use. Unlike [`Closure::own`], this does not require the closure
337 /// to be `'static`, allowing you to capture references to local variables.
338 ///
339 /// Use [`borrow_mut`](Self::borrow_mut) when you need to mutate captured state.
340 ///
341 /// The returned `ScopedClosure<'a, _>` has lifetime `'a` from the closure
342 /// reference, which means it cannot outlive the closure or any data the
343 /// closure captures.
344 ///
345 /// Supports unwind via its UnwindSafe bound when building with panic=unwind.
346 /// The resulting closure can be upcasted to `FnMut` using [`upcast_ref`](crate::Upcast::upcast_ref).
347 ///
348 /// # When to use scoped closures
349 ///
350 /// Use `ScopedClosure::borrow` or `ScopedClosure::borrow_mut` when:
351 /// - JavaScript will call the closure immediately and not retain it
352 /// - You need to capture non-`'static` references
353 /// - You want automatic cleanup when the `ScopedClosure` is dropped
354 ///
355 /// # Closure lifetime
356 ///
357 /// The JavaScript function is only valid while the `ScopedClosure` exists.
358 /// Once dropped, the JavaScript function is invalidated. If JavaScript retains
359 /// a reference and calls it later, it will throw: "closure invoked recursively
360 /// or after being dropped".
361 ///
362 /// Rust's borrow checker ensures `ScopedClosure` cannot outlive the closure's
363 /// captured data, preventing use-after-free bugs.
364 ///
365 /// # Example
366 ///
367 /// ```ignore
368 /// use wasm_bindgen::prelude::*;
369 ///
370 /// #[wasm_bindgen]
371 /// extern "C" {
372 /// fn call_with_value(cb: &ScopedClosure<dyn Fn(u32)>, value: u32);
373 /// fn call_fnmut(cb: &ScopedClosure<dyn FnMut(u32)>, value: u32);
374 /// }
375 ///
376 /// let data = vec![1, 2, 3];
377 /// let f = |x| {
378 /// println!("data len: {}, x: {}", data.len(), x);
379 /// };
380 /// let closure = ScopedClosure::borrow(&f);
381 /// call_with_value(&closure, 42);
382 /// // Can also upcast to FnMut
383 /// call_fnmut(closure.upcast_ref(), 42);
384 /// ```
385 pub fn borrow<'a, F>(t: &'a F) -> ScopedClosure<'a, F::Static>
386 where
387 F: IntoWasmClosureRef<'a, T> + MaybeUnwindSafe + ?Sized,
388 {
389 let t: &T = t.unsize_closure_ref();
390 let (ptr, len): (u32, u32) = unsafe { mem::transmute_copy(&t) };
391 ScopedClosure {
392 js: crate::__rt::wbg_cast(BorrowedClosure::<T> {
393 data: WasmSlice { ptr, len },
394 unwind_safe: true,
395 _marker: PhantomData,
396 }),
397 _marker: PhantomData,
398 _lifetime: PhantomData,
399 }
400 }
401
402 /// Like [`borrow`](Self::borrow), but catches panics without requiring `MaybeUnwindSafe`.
403 ///
404 /// **Safety: Unwind safety is assumed when using this function, like using
405 /// `AssertUnwindSafe(...)`, this must be verified explicitly.**
406 pub fn borrow_assert_unwind_safe<'a, F>(t: &'a F) -> ScopedClosure<'a, F::Static>
407 where
408 F: IntoWasmClosureRef<'a, T> + ?Sized,
409 {
410 let t: &T = t.unsize_closure_ref();
411 let (ptr, len): (u32, u32) = unsafe { mem::transmute_copy(&t) };
412 ScopedClosure {
413 js: crate::__rt::wbg_cast(BorrowedClosure::<T> {
414 data: WasmSlice { ptr, len },
415 unwind_safe: true,
416 _marker: PhantomData,
417 }),
418 _marker: PhantomData,
419 _lifetime: PhantomData,
420 }
421 }
422
423 /// Like [`borrow`](Self::borrow), but does not catch panics.
424 ///
425 /// If the closure panics, the process will abort. This variant does not
426 /// require `UnwindSafe`.
427 ///
428 /// **Note: Not unwind safe. Prefer [`borrow`](Self::borrow) or
429 /// [`borrow_assert_unwind_safe`](Self::borrow_assert_unwind_safe) when possible.**
430 pub fn borrow_aborting<'a, F>(t: &'a F) -> ScopedClosure<'a, F::Static>
431 where
432 F: IntoWasmClosureRef<'a, T> + ?Sized,
433 {
434 let t: &T = t.unsize_closure_ref();
435 let (ptr, len): (u32, u32) = unsafe { mem::transmute_copy(&t) };
436 ScopedClosure {
437 js: crate::__rt::wbg_cast(BorrowedClosure::<T> {
438 data: WasmSlice { ptr, len },
439 unwind_safe: false,
440 _marker: PhantomData,
441 }),
442 _marker: PhantomData,
443 _lifetime: PhantomData,
444 }
445 }
446
447 /// Creates a scoped closure by mutably borrowing a `FnMut` closure.
448 ///
449 /// Use this for closures that need to mutate captured state. For closures that
450 /// don't need mutation, prefer [`borrow`](Self::borrow) which creates an immutable
451 /// `Fn` closure that is more likely to satisfy `UnwindSafe` automatically.
452 ///
453 /// See [`borrow`](Self::borrow) for full documentation on scoped closures.
454 ///
455 /// # Example
456 ///
457 /// ```ignore
458 /// use wasm_bindgen::prelude::*;
459 ///
460 /// #[wasm_bindgen]
461 /// extern "C" {
462 /// fn call_three_times(cb: &ScopedClosure<dyn FnMut(u32)>);
463 /// }
464 ///
465 /// let mut sum = 0;
466 /// let closure = ScopedClosure::borrow_mut(&mut |x: u32| {
467 /// sum += x;
468 /// });
469 /// call_three_times(&closure);
470 /// // closure dropped, `sum` is accessible again
471 /// assert_eq!(sum, 6); // 1 + 2 + 3
472 /// ```
473 pub fn borrow_mut<'a, F>(t: &'a mut F) -> ScopedClosure<'a, F::Static>
474 where
475 F: IntoWasmClosureRefMut<'a, T> + MaybeUnwindSafe + ?Sized,
476 {
477 let t: &mut T = t.unsize_closure_ref();
478 let (ptr, len): (u32, u32) = unsafe { mem::transmute_copy(&t) };
479 ScopedClosure {
480 js: crate::__rt::wbg_cast(BorrowedClosure::<T> {
481 data: WasmSlice { ptr, len },
482 unwind_safe: true,
483 _marker: PhantomData,
484 }),
485 _marker: PhantomData,
486 _lifetime: PhantomData,
487 }
488 }
489
490 /// Like [`borrow_mut`](Self::borrow_mut), but catches panics without requiring `MaybeUnwindSafe`.
491 ///
492 /// **Safety: Unwind safety is assumed when using this function, like using
493 /// `AssertUnwindSafe(...)`, this must be verified explicitly.**
494 pub fn borrow_mut_assert_unwind_safe<'a, F>(t: &'a mut F) -> ScopedClosure<'a, F::Static>
495 where
496 F: IntoWasmClosureRefMut<'a, T> + ?Sized,
497 {
498 let t: &mut T = t.unsize_closure_ref();
499 let (ptr, len): (u32, u32) = unsafe { mem::transmute_copy(&t) };
500 ScopedClosure {
501 js: crate::__rt::wbg_cast(BorrowedClosure::<T> {
502 data: WasmSlice { ptr, len },
503 unwind_safe: true,
504 _marker: PhantomData,
505 }),
506 _marker: PhantomData,
507 _lifetime: PhantomData,
508 }
509 }
510
511 /// Like [`borrow_mut`](Self::borrow_mut), but does not catch panics.
512 ///
513 /// If the closure panics, the process will abort. This variant does not
514 /// require `UnwindSafe`.
515 ///
516 /// **Note: Not unwind safe. Prefer [`borrow_mut`](Self::borrow_mut) or
517 /// [`borrow_mut_assert_unwind_safe`](Self::borrow_mut_assert_unwind_safe) when possible.**
518 pub fn borrow_mut_aborting<'a, F>(t: &'a mut F) -> ScopedClosure<'a, F::Static>
519 where
520 F: IntoWasmClosureRefMut<'a, T> + ?Sized,
521 {
522 let t: &mut T = t.unsize_closure_ref();
523 let (ptr, len): (u32, u32) = unsafe { mem::transmute_copy(&t) };
524 ScopedClosure {
525 js: crate::__rt::wbg_cast(BorrowedClosure::<T> {
526 data: WasmSlice { ptr, len },
527 unwind_safe: false,
528 _marker: PhantomData,
529 }),
530 _marker: PhantomData,
531 _lifetime: PhantomData,
532 }
533 }
534}
535
536impl<T> ScopedClosure<'static, T>
537where
538 T: ?Sized + WasmClosure,
539{
540 /// Release memory management of this closure from Rust to the JS GC.
541 ///
542 /// When a `Closure` is dropped it will release the Rust memory and
543 /// invalidate the associated JS closure, but this isn't always desired.
544 /// Some callbacks are alive for the entire duration of the program or for a
545 /// lifetime dynamically managed by the JS GC. This function can be used
546 /// to drop this `Closure` while keeping the associated JS function still
547 /// valid.
548 ///
549 /// If the platform supports weak references, the Rust memory will be
550 /// reclaimed when the JS closure is GC'd. If weak references is not
551 /// supported, this can be dangerous if this function is called many times
552 /// in an application because the memory leak will overwhelm the page
553 /// quickly and crash the wasm.
554 ///
555 /// # Safety Note
556 ///
557 /// This method is only available on `'static` closures. Calling it on a
558 /// borrowed `ScopedClosure` would be unsound because the closure data
559 /// would become invalid when the borrow ends.
560 pub fn into_js_value(self) -> JsValue {
561 let idx = self.js.idx;
562 mem::forget(self);
563 JsValue::_new(idx)
564 }
565
566 /// Same as `mem::forget(self)`.
567 ///
568 /// This can be used to fully relinquish closure ownership to the JS.
569 ///
570 /// # Safety Note
571 ///
572 /// This method is only available on `'static` closures. Calling it on a borrowed
573 /// `ScopedClosure` would be unsound because the closure data would become invalid
574 /// when the borrow ends.
575 pub fn forget(self) {
576 mem::forget(self);
577 }
578
579 /// Create a `Closure` from a function that can only be called once.
580 ///
581 /// Since we have no way of enforcing that JS cannot attempt to call this
582 /// `FnOne(A...) -> R` more than once, this produces a `Closure<dyn FnMut(A...)
583 /// -> R>` that will dynamically throw a JavaScript error if called more
584 /// than once.
585 ///
586 /// # Example
587 ///
588 /// ```rust,no_run
589 /// use wasm_bindgen::prelude::*;
590 ///
591 /// // Create an non-`Copy`, owned `String`.
592 /// let mut s = String::from("Hello");
593 ///
594 /// // Close over `s`. Since `f` returns `s`, it is `FnOnce` and can only be
595 /// // called once. If it was called a second time, it wouldn't have any `s`
596 /// // to work with anymore!
597 /// let f = move || {
598 /// s += ", World!";
599 /// s
600 /// };
601 ///
602 /// // Create a `Closure` from `f`. Note that the `Closure`'s type parameter
603 /// // is `FnMut`, even though `f` is `FnOnce`.
604 /// let closure: Closure<dyn FnMut() -> String> = Closure::once(f);
605 /// ```
606 ///
607 /// Note: the `A` and `R` type parameters are here just for backward compat
608 /// and will be removed in the future.
609 pub fn once<F, A, R>(fn_once: F) -> Self
610 where
611 F: WasmClosureFnOnce<T, A, R> + MaybeUnwindSafe,
612 {
613 Closure::_wrap(fn_once.into_fn_mut(), true)
614 }
615
616 /// Create a `Closure` from a function that can only be called once.
617 ///
618 /// Unlike `once`, this version does NOT catch panics and does NOT require `UnwindSafe`.
619 /// If the closure panics, the process will abort.
620 ///
621 /// Use this when:
622 /// - Your closure captures types that aren't `UnwindSafe` (like `Rc<Cell<T>>`)
623 /// - You don't need panic catching across the JS boundary
624 /// - You prefer abort-on-panic behavior
625 ///
626 /// Since we have no way of enforcing that JS cannot attempt to call this
627 /// `FnOnce(A...) -> R` more than once, this produces a `Closure<dyn FnMut(A...)
628 /// -> R>` that will dynamically throw a JavaScript error if called more
629 /// than once.
630 ///
631 /// **Note: Not unwind safe. Prefer [`once`](Self::once) or `once` with
632 /// [`AssertUnwindSafe`](core::panic::AssertUnwindSafe) when possible.**
633 ///
634 /// Note: the `A` and `R` type parameters are here just for backward compat
635 /// and will be removed in the future.
636 pub fn once_wrap<F, A, R>(fn_once: F) -> Self
637 where
638 F: WasmClosureFnOnceAbort<T, A, R>,
639 {
640 Closure::_wrap(fn_once.into_fn_mut(), false)
641 }
642
643 /// Convert a `FnOnce(A...) -> R` into a JavaScript `Function` object.
644 ///
645 /// If the JavaScript function is invoked more than once, it will throw an
646 /// exception.
647 ///
648 /// Unlike `Closure::once`, this does *not* return a `Closure` that can be
649 /// dropped before the function is invoked to deallocate the closure. The
650 /// only way the `FnOnce` is deallocated is by calling the JavaScript
651 /// function. If the JavaScript function is never called then the `FnOnce`
652 /// and everything it closes over will leak.
653 ///
654 /// ```rust,ignore
655 /// use wasm_bindgen::{prelude::*, JsCast};
656 ///
657 /// let f = Closure::once_into_js(move || {
658 /// // ...
659 /// });
660 ///
661 /// assert!(f.is_instance_of::<js_sys::Function>());
662 /// ```
663 ///
664 /// Note: the `A` and `R` type parameters are here just for backward compat
665 /// and will be removed in the future.
666 pub fn once_into_js<F, A, R>(fn_once: F) -> JsValue
667 where
668 F: WasmClosureFnOnce<T, A, R> + MaybeUnwindSafe,
669 {
670 fn_once.into_js_function()
671 }
672
673 /// Convert a `FnOnce(A...) -> R` into a JavaScript `Function` object.
674 ///
675 /// Unlike `once_into_js`, this version does NOT catch panics and does NOT require `UnwindSafe`.
676 /// If the closure panics, the process will abort.
677 ///
678 /// If the JavaScript function is invoked more than once, it will throw an
679 /// exception.
680 ///
681 /// Unlike `Closure::once_aborting`, this does *not* return a `Closure` that can be
682 /// dropped before the function is invoked to deallocate the closure. The
683 /// only way the `FnOnce` is deallocated is by calling the JavaScript
684 /// function. If the JavaScript function is never called then the `FnOnce`
685 /// and everything it closes over will leak.
686 ///
687 /// **Note: Not unwind safe. Prefer [`once_into_js`](Self::once_into_js) or `once_into_js` with
688 /// [`AssertUnwindSafe`](core::panic::AssertUnwindSafe) when possible.**
689 ///
690 /// Note: the `A` and `R` type parameters are here just for backward compat
691 /// and will be removed in the future.
692 pub fn once_into_js_wrap<F, A, R>(fn_once: F) -> JsValue
693 where
694 F: WasmClosureFnOnceAbort<T, A, R>,
695 {
696 fn_once.into_js_function()
697 }
698}
699
700/// A closure wrapper for immediate/synchronous callbacks with unwind safety.
701///
702/// `ImmediateClosure` wraps a borrowed closure for use in synchronous JS callbacks
703/// like `Array.forEach`, `Array.map`, etc. The JS side receives the closure,
704/// calls it immediately, and discards it - no GC tracking is needed.
705///
706/// Panics are caught and converted to JavaScript exceptions (when built with
707/// `panic=unwind`). No `UnwindSafe` bounds are required - the closure is wrapped
708/// internally.
709///
710/// # Unwind Safety
711///
712/// `ImmediateClosure` provides unwind safety by catching panics and converting them
713/// to JavaScript exceptions.
714///
715/// # Example
716///
717/// ```ignore
718/// use wasm_bindgen::prelude::*;
719///
720/// #[wasm_bindgen]
721/// extern "C" {
722/// fn forEach<'a>(cb: &ImmediateClosure<'a, dyn FnMut(JsValue) + 'a>);
723/// }
724///
725/// let mut sum = 0;
726/// let closure = ImmediateClosure::new_mut(&mut |val: JsValue| {
727/// sum += val.as_f64().unwrap() as i32;
728/// });
729/// forEach(&closure);
730/// // sum is now updated
731/// ```
732///
733/// **Note:** To ensure borrowed lifetimes are correctly inferred, make sure to pass
734/// the lifetime to both the ImmediateClosure lifetime parameter AND its dyn FnMut
735/// parameter, as in the example above.
736pub struct ImmediateClosure<'a, T: ?Sized> {
737 data: WasmSlice,
738 unwind_safe: bool,
739 _marker: PhantomData<&'a mut T>,
740}
741
742impl<'a, T: ?Sized + WasmClosure> ImmediateClosure<'a, T> {
743 /// Creates an immediate closure from an immutable borrow of a `Fn` closure.
744 ///
745 /// Immutable closures (`Fn`) are preferred because they are more likely to satisfy `UnwindSafe`
746 /// automatically. Use [`new_mut`](Self::new_mut) when you need to mutate captured state.
747 ///
748 /// Note that immutable closures can be `upcast()` to mutable closures on the JS boundary
749 /// when required by function signatures.
750 ///
751 /// Panics are caught as JS exceptions when building with panic=unwind.
752 /// The resulting closure can be upcasted to `FnMut` using [`upcast_ref`](crate::Upcast::upcast_ref).
753 ///
754 /// # Example
755 ///
756 /// ```ignore
757 /// let data = vec![1, 2, 3];
758 /// let closure = ImmediateClosure::new(&|| {
759 /// println!("data len: {}", data.len());
760 /// });
761 /// call_closure(&closure);
762 /// ```
763 pub fn new<F>(f: &'a F) -> ImmediateClosure<'a, F::WithLifetime>
764 where
765 F: IntoWasmClosureRef<'a, T> + ?Sized + MaybeUnwindSafe,
766 {
767 let t: &T = f.unsize_closure_ref();
768 let (ptr, len): (u32, u32) = unsafe { mem::transmute_copy(&t) };
769 ImmediateClosure {
770 data: WasmSlice { ptr, len },
771 unwind_safe: true,
772 _marker: PhantomData,
773 }
774 }
775
776 /// Creates an immediate closure from a mutable borrow of a `FnMut` closure.
777 ///
778 /// Use this for closures that need to mutate captured state. For closures that
779 /// don't need mutation, [`new`](Self::new) creates an immutable `Fn` closure
780 /// that is more likely to satisfy `UnwindSafe` automatically.
781 ///
782 /// Panics are caught as JS exceptions when building with panic=unwind.
783 ///
784 /// # Example
785 ///
786 /// ```ignore
787 /// let mut count = 0;
788 /// let closure = ImmediateClosure::new_mut(&mut || { count += 1; });
789 /// call_closure(&closure);
790 /// assert_eq!(count, 1);
791 /// ```
792 pub fn new_mut<F>(f: &'a mut F) -> ImmediateClosure<'a, F::WithLifetime>
793 where
794 F: IntoWasmClosureRefMut<'a, T> + ?Sized + MaybeUnwindSafe,
795 {
796 let t: &mut T = f.unsize_closure_ref();
797 let (ptr, len): (u32, u32) = unsafe { mem::transmute_copy(&t) };
798 ImmediateClosure {
799 data: WasmSlice { ptr, len },
800 unwind_safe: true,
801 _marker: PhantomData,
802 }
803 }
804}
805
806impl<'a, T: ?Sized + WasmClosure> ImmediateClosure<'a, T> {
807 /// Like [`new`](Self::new), but does not catch panics.
808 ///
809 /// This variant enables type inference from the expected type, since it
810 /// takes the dyn type directly.
811 ///
812 /// **Note: Not unwind safe. Prefer [`new`](Self::new) or
813 /// [`wrap_assert_unwind_safe`](Self::wrap_assert_unwind_safe) when possible.**
814 pub fn wrap_aborting(f: &'a T) -> Self {
815 ImmediateClosure {
816 data: T::to_wasm_slice(f),
817 unwind_safe: false,
818 _marker: PhantomData,
819 }
820 }
821
822 /// Like [`new_mut`](Self::new_mut), but does not catch panics.
823 ///
824 /// This variant enables type inference from the expected type, since it
825 /// takes the dyn type directly.
826 ///
827 /// **Note: Not unwind safe. Prefer [`new_mut`](Self::new_mut) or
828 /// [`wrap_mut_assert_unwind_safe`](Self::wrap_mut_assert_unwind_safe) when possible.**
829 pub fn wrap_mut_aborting(f: &'a mut T) -> Self {
830 ImmediateClosure {
831 data: T::to_wasm_slice(f),
832 unwind_safe: false,
833 _marker: PhantomData,
834 }
835 }
836
837 /// Like [`wrap_aborting`](Self::wrap_aborting), but catches panics and converts them to JS exceptions.
838 ///
839 /// **Safety: Unwind safety is assumed when using this function, like using
840 /// `AssertUnwindSafe(...)`, this must be verified explicitly.**
841 ///
842 /// # Example
843 ///
844 /// ```ignore
845 /// let data = vec![1, 2, 3];
846 /// // Type is inferred from context
847 /// let closure: ImmediateClosure<dyn Fn()> = ImmediateClosure::wrap_assert_unwind_safe(&|| {
848 /// println!("data len: {}", data.len());
849 /// });
850 /// ```
851 pub fn wrap_assert_unwind_safe(f: &'a T) -> Self {
852 ImmediateClosure {
853 data: T::to_wasm_slice(f),
854 unwind_safe: true,
855 _marker: PhantomData,
856 }
857 }
858
859 /// Like [`wrap_mut_aborting`](Self::wrap_mut_aborting), but catches panics and converts them to JS exceptions.
860 ///
861 /// **Safety: Unwind safety is assumed when using this function, like using
862 /// `AssertUnwindSafe(...)`, this must be verified explicitly.**
863 ///
864 /// # Example
865 ///
866 /// ```ignore
867 /// let mut count = 0;
868 /// // Type of `x` is inferred from context
869 /// let closure: ImmediateClosure<dyn FnMut(u32)> = ImmediateClosure::wrap_mut_assert_unwind_safe(&mut |x| {
870 /// count += x;
871 /// });
872 /// ```
873 pub fn wrap_mut_assert_unwind_safe(f: &'a mut T) -> Self {
874 ImmediateClosure {
875 data: T::to_wasm_slice(f),
876 unwind_safe: true,
877 _marker: PhantomData,
878 }
879 }
880
881 /// Returns a reference to this closure as a mutable `FnMut` closure.
882 ///
883 /// This is safe because every `Fn` can be called through a `FnMut` interface.
884 /// The fat pointer representation is compatible—`&dyn Fn` can be safely
885 /// reinterpreted as `&dyn FnMut`.
886 ///
887 /// Note: Unlike `ScopedClosure::as_mut`, this only supports the Fn→FnMut conversion
888 /// with the same argument and return types. `ImmediateClosure` stores a Rust fat
889 /// pointer directly, so argument/return type variance is not possible.
890 ///
891 /// # Example
892 ///
893 /// ```ignore
894 /// use wasm_bindgen::prelude::*;
895 ///
896 /// #[wasm_bindgen]
897 /// extern "C" {
898 /// fn needs_fnmut(cb: &ImmediateClosure<dyn FnMut(u32)>);
899 /// }
900 ///
901 /// let func: &dyn Fn(u32) = &|x| println!("{}", x);
902 /// let closure: ImmediateClosure<dyn Fn(u32)> = ImmediateClosure::wrap_assert_unwind_safe(func);
903 /// needs_fnmut(closure.as_mut());
904 /// ```
905 pub fn as_mut(&self) -> &ImmediateClosure<'a, T::AsMut> {
906 // SAFETY: ImmediateClosure stores a WasmSlice (fat pointer data) and metadata.
907 // The type parameter T is phantom data. A &dyn Fn fat pointer can be safely
908 // reinterpreted as &dyn FnMut since Fn is a supertrait of FnMut.
909 unsafe {
910 &*(self as *const ImmediateClosure<'a, T> as *const ImmediateClosure<'a, T::AsMut>)
911 }
912 }
913}
914
915impl<T: ?Sized> fmt::Debug for ImmediateClosure<'_, T> {
916 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
917 f.debug_struct("ImmediateClosure").finish_non_exhaustive()
918 }
919}
920
921/// A trait for converting an `FnOnce(A...) -> R` into a `FnMut(A...) -> R` that
922/// will throw if ever called more than once.
923#[doc(hidden)]
924pub trait WasmClosureFnOnce<FnMut: ?Sized, A, R>: 'static {
925 fn into_fn_mut(self) -> Box<FnMut>;
926
927 fn into_js_function(self) -> JsValue;
928}
929
930/// A trait for converting an `FnOnce(A...) -> R` into a `FnMut(A...) -> R` that
931/// will throw if ever called more than once. This variant does not require UnwindSafe.
932#[doc(hidden)]
933pub trait WasmClosureFnOnceAbort<FnMut: ?Sized, A, R>: 'static {
934 fn into_fn_mut(self) -> Box<FnMut>;
935
936 fn into_js_function(self) -> JsValue;
937}
938
939impl<T: ?Sized> AsRef<JsValue> for ScopedClosure<'_, T> {
940 fn as_ref(&self) -> &JsValue {
941 &self.js
942 }
943}
944
945/// Internal representation of an owned closure that we send to JS.
946/// This is used when panic=abort or when panic=unwind but without the unwind_safe flag.
947#[repr(transparent)]
948struct OwnedClosure<T: ?Sized>(Box<T>);
949
950/// Internal representation of an owned closure with unwind safety flag. Used
951/// when panic=unwind to pass both the closure and the unwind_safe flag to JS.
952#[cfg(all(feature = "std", target_arch = "wasm32", panic = "unwind"))]
953struct OwnedClosureUnwind<T: ?Sized> {
954 data: Box<T>,
955 unwind_safe: bool,
956}
957
958struct BorrowedClosure<T: ?Sized> {
959 data: WasmSlice,
960 unwind_safe: bool,
961 _marker: PhantomData<T>,
962}
963
964unsafe extern "C" fn destroy<T: ?Sized>(a: usize, mut b: usize) {
965 if a == 0 {
966 return;
967 }
968 // Mask out unwind_safe flag
969 b &= !0x80000000;
970 drop(mem::transmute_copy::<_, Box<T>>(&(a, b)));
971}
972
973impl<T> WasmDescribe for OwnedClosure<T>
974where
975 T: WasmClosure + ?Sized,
976{
977 #[cfg_attr(wasm_bindgen_unstable_test_coverage, coverage(off))]
978 fn describe() {
979 inform(CLOSURE);
980 inform(destroy::<T> as *const () as usize as u32);
981 inform(T::IS_MUT as u32);
982 T::describe();
983 }
984}
985
986impl<T> WasmDescribe for BorrowedClosure<T>
987where
988 T: WasmClosure + ?Sized,
989{
990 #[cfg_attr(wasm_bindgen_unstable_test_coverage, coverage(off))]
991 fn describe() {
992 inform(CLOSURE);
993 inform(0);
994 inform(T::IS_MUT as u32);
995 T::describe();
996 }
997}
998
999impl<T> IntoWasmAbi for OwnedClosure<T>
1000where
1001 T: WasmClosure + ?Sized,
1002{
1003 type Abi = WasmSlice;
1004
1005 fn into_abi(self) -> WasmSlice {
1006 let (a, b): (usize, usize) = unsafe { mem::transmute_copy(&ManuallyDrop::new(self)) };
1007 WasmSlice {
1008 ptr: a as u32,
1009 len: b as u32,
1010 }
1011 }
1012}
1013
1014impl<T> IntoWasmAbi for BorrowedClosure<T>
1015where
1016 T: WasmClosure + ?Sized,
1017{
1018 type Abi = WasmSlice;
1019 fn into_abi(self) -> WasmSlice {
1020 let WasmSlice { ptr, mut len } = self.data;
1021 if self.unwind_safe {
1022 len |= 0x80000000;
1023 }
1024 WasmSlice { ptr, len }
1025 }
1026}
1027
1028#[cfg(all(feature = "std", target_arch = "wasm32", panic = "unwind"))]
1029impl<T> WasmDescribe for OwnedClosureUnwind<T>
1030where
1031 T: WasmClosure + ?Sized,
1032{
1033 #[cfg_attr(wasm_bindgen_unstable_test_coverage, coverage(off))]
1034 fn describe() {
1035 // Delegate to the inner closure's descriptor - type info is the same
1036 OwnedClosure::<T>::describe();
1037 }
1038}
1039
1040#[cfg(all(feature = "std", target_arch = "wasm32", panic = "unwind"))]
1041impl<T> IntoWasmAbi for OwnedClosureUnwind<T>
1042where
1043 T: WasmClosure + ?Sized,
1044{
1045 type Abi = WasmSlice;
1046
1047 fn into_abi(self) -> WasmSlice {
1048 let (a, b): (usize, usize) = unsafe { mem::transmute_copy(&ManuallyDrop::new(self.data)) };
1049 // Pack unwind_safe into most significant bit (bit 31) of vtable
1050 let b_with_flag = if self.unwind_safe {
1051 (b as u32) | 0x80000000
1052 } else {
1053 b as u32
1054 };
1055 WasmSlice {
1056 ptr: a as u32,
1057 len: b_with_flag,
1058 }
1059 }
1060}
1061
1062impl<T> WasmDescribe for ScopedClosure<'_, T>
1063where
1064 T: WasmClosure + ?Sized,
1065{
1066 #[cfg_attr(wasm_bindgen_unstable_test_coverage, coverage(off))]
1067 fn describe() {
1068 inform(EXTERNREF);
1069 }
1070}
1071
1072// `ScopedClosure` can be passed by reference to imports (for any lifetime).
1073impl<T> IntoWasmAbi for &ScopedClosure<'_, T>
1074where
1075 T: WasmClosure + ?Sized,
1076{
1077 type Abi = u32;
1078
1079 fn into_abi(self) -> u32 {
1080 (&self.js).into_abi()
1081 }
1082}
1083
1084impl<T> OptionIntoWasmAbi for &ScopedClosure<'_, T>
1085where
1086 T: WasmClosure + ?Sized,
1087{
1088 fn none() -> Self::Abi {
1089 0
1090 }
1091}
1092
1093/// `'static` closures can be passed by value to JS, transferring ownership.
1094///
1095/// This is useful for one-shot callbacks where you want JS to own the closure.
1096/// The closure will be cleaned up by JS GC (if weak references are supported)
1097/// or will leak (if weak references are not supported).
1098///
1099/// # Example
1100///
1101/// ```ignore
1102/// #[wasm_bindgen]
1103/// extern "C" {
1104/// fn set_one_shot_callback(cb: Closure<dyn FnMut()>);
1105/// }
1106///
1107/// let cb = Closure::new(|| { /* ... */ });
1108/// set_one_shot_callback(cb); // Ownership transferred to JS
1109/// // No need to store or forget the closure
1110/// ```
1111impl<T> IntoWasmAbi for ScopedClosure<'static, T>
1112where
1113 T: WasmClosure + ?Sized,
1114{
1115 type Abi = u32;
1116
1117 fn into_abi(self) -> u32 {
1118 let idx = self.js.idx;
1119 mem::forget(self);
1120 idx
1121 }
1122}
1123
1124impl<T> OptionIntoWasmAbi for ScopedClosure<'static, T>
1125where
1126 T: WasmClosure + ?Sized,
1127{
1128 fn none() -> Self::Abi {
1129 0
1130 }
1131}
1132
1133impl<T> WasmDescribe for ImmediateClosure<'_, T>
1134where
1135 T: WasmClosure + ?Sized,
1136{
1137 #[cfg_attr(wasm_bindgen_unstable_test_coverage, coverage(off))]
1138 fn describe() {
1139 // Delegate to the underlying dyn Fn/FnMut - uses FUNCTION descriptor
1140 <T as WasmDescribe>::describe();
1141 }
1142}
1143
1144impl<T> IntoWasmAbi for &ImmediateClosure<'_, T>
1145where
1146 T: WasmClosure + ?Sized,
1147{
1148 type Abi = WasmSlice;
1149
1150 fn into_abi(self) -> WasmSlice {
1151 let WasmSlice { ptr, len } = self.data;
1152 let len_with_flag = if self.unwind_safe {
1153 len | 0x80000000
1154 } else {
1155 len
1156 };
1157 WasmSlice {
1158 ptr,
1159 len: len_with_flag,
1160 }
1161 }
1162}
1163
1164impl<T> OptionIntoWasmAbi for &ImmediateClosure<'_, T>
1165where
1166 T: WasmClosure + ?Sized,
1167{
1168 fn none() -> WasmSlice {
1169 WasmSlice { ptr: 0, len: 0 }
1170 }
1171}
1172
1173fn _check() {
1174 fn _assert<T: IntoWasmAbi>() {}
1175 // ScopedClosure by reference (any lifetime)
1176 _assert::<&ScopedClosure<dyn Fn()>>();
1177 _assert::<&ScopedClosure<dyn Fn(String)>>();
1178 _assert::<&ScopedClosure<dyn Fn() -> String>>();
1179 _assert::<&ScopedClosure<dyn FnMut()>>();
1180 _assert::<&ScopedClosure<dyn FnMut(String)>>();
1181 _assert::<&ScopedClosure<dyn FnMut() -> String>>();
1182 // ScopedClosure by value (only 'static)
1183 _assert::<ScopedClosure<'static, dyn Fn()>>();
1184 _assert::<ScopedClosure<'static, dyn FnMut()>>();
1185 _assert::<Closure<dyn Fn()>>();
1186 _assert::<Closure<dyn FnMut()>>();
1187 // ImmediateClosure by reference
1188 _assert::<&ImmediateClosure<dyn Fn()>>();
1189 _assert::<&ImmediateClosure<dyn Fn(String)>>();
1190 _assert::<&ImmediateClosure<dyn Fn() -> String>>();
1191 _assert::<&ImmediateClosure<dyn FnMut()>>();
1192 _assert::<&ImmediateClosure<dyn FnMut(String)>>();
1193 _assert::<&ImmediateClosure<dyn FnMut() -> String>>();
1194}
1195
1196impl<T> fmt::Debug for ScopedClosure<'_, T>
1197where
1198 T: ?Sized,
1199{
1200 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1201 write!(f, "Closure {{ ... }}")
1202 }
1203}
1204
1205/// An internal trait for the `Closure` type.
1206///
1207/// This trait is not stable and it's not recommended to use this in bounds or
1208/// implement yourself.
1209#[doc(hidden)]
1210pub unsafe trait WasmClosure: WasmDescribe {
1211 const IS_MUT: bool;
1212 /// The mutable version of this closure type.
1213 /// For `dyn Fn(...) -> R` this is `dyn FnMut(...) -> R`.
1214 /// For `dyn FnMut(...) -> R` this is itself.
1215 type AsMut: ?Sized;
1216 fn to_wasm_slice(r: &Self) -> WasmSlice;
1217}
1218
1219unsafe impl<T: WasmClosure> WasmClosure for AssertUnwindSafe<T> {
1220 const IS_MUT: bool = T::IS_MUT;
1221 type AsMut = T::AsMut;
1222 fn to_wasm_slice(r: &Self) -> WasmSlice {
1223 let (ptr, len): (u32, u32) = unsafe { mem::transmute_copy(&r) };
1224 WasmSlice { ptr, len }
1225 }
1226}
1227
1228/// An internal trait for the `Closure` type.
1229///
1230/// This trait is not stable and it's not recommended to use this in bounds or
1231/// implement yourself.
1232#[doc(hidden)]
1233pub trait IntoWasmClosure<T: ?Sized> {
1234 fn unsize(self: Box<Self>) -> Box<T>;
1235}
1236
1237impl<T: ?Sized + WasmClosure> IntoWasmClosure<T> for T {
1238 fn unsize(self: Box<Self>) -> Box<T> {
1239 self
1240 }
1241}
1242
1243/// Trait for converting a reference to a closure into a trait object reference.
1244///
1245/// This trait is not stable and it's not recommended to use this in bounds or
1246/// implement yourself.
1247#[doc(hidden)]
1248pub trait IntoWasmClosureRef<'a, T: ?Sized> {
1249 /// The `'static` version of `T`. For example, if `T` is `dyn Fn() + 'a`,
1250 /// then `Static` is `dyn Fn()` (implicitly `'static`).
1251 type Static: ?Sized + WasmClosure;
1252 type WithLifetime: ?Sized + WasmClosure + 'a;
1253 fn unsize_closure_ref(&self) -> &T;
1254}
1255
1256/// Trait for converting a mutable reference to a closure into a trait object reference.
1257///
1258/// This trait is not stable and it's not recommended to use this in bounds or
1259/// implement yourself.
1260#[doc(hidden)]
1261pub trait IntoWasmClosureRefMut<'a, T: ?Sized> {
1262 /// The `'static` version of `T`. For example, if `T` is `dyn FnMut() + 'a`,
1263 /// then `Static` is `dyn FnMut()` (implicitly `'static`).
1264 type Static: ?Sized + WasmClosure;
1265 type WithLifetime: ?Sized + WasmClosure + 'a;
1266 fn unsize_closure_ref(&mut self) -> &mut T;
1267}
1268
1269// Blanket impl for AssertUnwindSafe - delegates to inner type
1270impl<'a, T: ?Sized, F> IntoWasmClosureRef<'a, T> for AssertUnwindSafe<F>
1271where
1272 F: IntoWasmClosureRef<'a, T>,
1273{
1274 type Static = F::Static;
1275 type WithLifetime = F::WithLifetime;
1276 fn unsize_closure_ref(&self) -> &T {
1277 self.0.unsize_closure_ref()
1278 }
1279}
1280
1281impl<'a, T: ?Sized, F> IntoWasmClosureRefMut<'a, T> for AssertUnwindSafe<F>
1282where
1283 F: IntoWasmClosureRefMut<'a, T>,
1284{
1285 type Static = F::Static;
1286 type WithLifetime = F::WithLifetime;
1287 fn unsize_closure_ref(&mut self) -> &mut T {
1288 self.0.unsize_closure_ref()
1289 }
1290}
1291
1292// In ScopedClosure, the Rust closure type is the phantom type that erases,
1293// unlike ImmedateClosure which is the reverse.
1294unsafe impl<T: ?Sized + WasmClosure> ErasableGeneric for ScopedClosure<'_, T> {
1295 type Repr = ScopedClosure<'static, dyn FnMut()>;
1296}