Skip to main content

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}