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//!
19//! Immutable closures can be upcasted to mutable closures using [`upcast_ref`](crate::Upcast::upcast_ref).
20//!
21//! # Type Aliases
22//!
23//! - [`ScopedClosure<'a, T>`] — The unified closure type with a lifetime parameter
24//! - [`Closure<T>`] — Alias for `ScopedClosure<'static, T>` (for backwards compatibility)
25//!
26//! # Unwind Safety
27//!
28//! For immediate/synchronous callbacks, use `&dyn FnMut` / `&dyn Fn`, when you are
29//! **absolutely sure** the code will support unwind safety.
30//!
31//! For [`ScopedClosure`], the default constructors (`borrow`, `borrow_mut`, `own`) catch
32//! panics, while the `_aborting` variants (`borrow_aborting`, `borrow_mut_aborting`, etc.) do not.
33//!
34//! # Ownership Model
35//!
36//! `ScopedClosure` follows the same ownership model as other wasm-bindgen types:
37//! the JavaScript reference remains valid until the Rust value is dropped. When
38//! dropped, the closure is invalidated and any subsequent calls from JavaScript
39//! will throw an exception.
40//!
41//! For borrowed closures created with `borrow`/`borrow_mut`, Rust's borrow checker
42//! ensures the `ScopedClosure` cannot outlive the closure's captured data.
43//!
44//! See the [`ScopedClosure`] type documentation for detailed examples.
45
46#![allow(clippy::fn_to_numeric_cast)]
47use alloc::boxed::Box;
48use alloc::string::String;
49use core::fmt;
50use core::mem::{self, ManuallyDrop};
51
52use crate::__rt::marker::ErasableGeneric;
53use crate::__rt::marker::MaybeUnwindSafe;
54use crate::__rt::WasmWord;
55use crate::describe::*;
56use crate::JsValue;
57use crate::{convert::*, JsCast};
58use core::marker::PhantomData;
59use core::panic::AssertUnwindSafe;
60
61#[wasm_bindgen_macro::wasm_bindgen(wasm_bindgen = crate)]
62extern "C" {
63    // `no_into_js_generic` is required because closures are deliberately
64    // not `Clone`: duplicating the Rust wrapper over a JS callback would
65    // break the "owned once" destruction semantics the type is designed
66    // to enforce.
67    #[wasm_bindgen(no_into_js_generic)]
68    type JsClosure;
69
70    #[wasm_bindgen(method)]
71    fn _wbg_cb_unref(js: &JsClosure);
72}
73
74/// A closure with a lifetime parameter that represents a Rust closure passed to JavaScript.
75///
76/// `ScopedClosure<'a, T>` is the unified closure type. The lifetime `'a` indicates
77/// how long the closure is valid:
78///
79/// - **`ScopedClosure<'static, T>`** - An owned closure with heap-allocated data. Requires
80///   `'static` captures. Use for long-lived closures like event listeners and timers.
81///   Created with [`Closure::new`] or [`ScopedClosure::own`]. May transfer ownership to the
82///   JS GC using finalizers.
83///
84/// - **`ScopedClosure<'a, T>`** (non-`'static`) - A borrowed closure referencing stack data.
85///   Allows non-`'static` captures. Use for immediate/synchronous callbacks. Created with
86///   [`ScopedClosure::borrow`] (for `FnMut`) or [`ScopedClosure::borrow_immutable`] (for `Fn`).
87///   Cannot transfer ownership to JS GC.
88///
89/// [`Closure<T>`] is currently a type alias for `ScopedClosure<'static, T>`. In
90/// a future release, a lifetime argument will be added to this alias.
91///
92/// # Ownership Model
93///
94/// `ScopedClosure` follows the same ownership model as other wasm-bindgen types:
95/// the JavaScript reference remains valid until the Rust value is dropped. When
96/// dropped, the closure is invalidated and any subsequent calls from JavaScript
97/// will throw: "closure invoked recursively or after being dropped".
98///
99/// For `'static` closures, you can also:
100/// - Pass by value to transfer ownership to JS (implements [`IntoWasmAbi`])
101/// - Call [`forget()`](Self::forget) to leak the closure (JS can use it indefinitely)
102/// - Call [`into_js_value()`](Self::into_js_value) to transfer to JS GC management
103///
104/// # Lifetime Safety
105///
106/// For borrowed closures, Rust's borrow checker ensures that `ScopedClosure` cannot
107/// be held longer than the closure's captured data:
108///
109/// ```ignore
110/// let mut sum = 0;
111/// let mut f = |x: u32| { sum += x; };  // f borrows sum
112/// let closure = ScopedClosure::borrow(&mut f);  // closure borrows f
113/// // closure cannot outlive f, and f cannot outlive sum
114/// ```
115///
116/// # Examples
117///
118/// ## Borrowed closures with `ScopedClosure::borrow`
119///
120/// Use for immediate/synchronous callbacks where JS calls the closure right away:
121///
122/// ```ignore
123/// use wasm_bindgen::prelude::*;
124///
125/// #[wasm_bindgen]
126/// extern "C" {
127///     fn call_immediately(cb: &ScopedClosure<dyn FnMut(u32)>);
128/// }
129///
130/// let mut sum = 0;
131/// {
132///     let mut f = |x: u32| { sum += x; };
133///     let closure = ScopedClosure::borrow(&mut f);
134///     call_immediately(&closure);
135/// }  // closure dropped here, JS function invalidated
136/// assert_eq!(sum, 42);
137/// ```
138///
139/// ## Owned closures with `Closure::new`
140///
141/// Use for long-lived callbacks like event listeners and timers:
142///
143/// ```ignore
144/// use wasm_bindgen::prelude::*;
145///
146/// #[wasm_bindgen]
147/// extern "C" {
148///     fn setInterval(closure: &Closure<dyn FnMut()>, time: u32) -> i32;
149/// }
150///
151/// // Closure::new requires 'static, so use `move` to capture by value
152/// let cb = Closure::new(move || {
153///     // ...
154/// });
155/// setInterval(&cb, 1000);
156/// // Must keep `cb` alive or call `cb.forget()` to transfer to JS
157/// ```
158///
159/// ## Transferring ownership to JS
160///
161/// Pass a `ScopedClosure<'static, T>` by value to transfer ownership:
162///
163/// ```ignore
164/// use wasm_bindgen::prelude::*;
165///
166/// #[wasm_bindgen]
167/// extern "C" {
168///     fn set_one_shot_callback(cb: ScopedClosure<dyn FnMut()>);
169/// }
170///
171/// let cb = ScopedClosure::own(|| { /* ... */ });
172/// set_one_shot_callback(cb);  // Ownership transferred, no need to store
173/// ```
174pub struct ScopedClosure<'a, T: ?Sized> {
175    js: JsClosure,
176    // careful: must be Box<T> not just T because unsized PhantomData
177    // seems to have weird interaction with Pin<>
178    _marker: PhantomData<Box<T>>,
179    _lifetime: PhantomData<&'a ()>,
180}
181
182/// Alias for [`ScopedClosure<'static, T>`] for backwards compatibility.
183///
184/// In a future major version, `Closure` will become `ScopedClosure<'a, T>` with a
185/// lifetime parameter.
186pub type Closure<T> = ScopedClosure<'static, T>;
187
188// ScopedClosure is Unpin because it only contains a JsValue (which is just a u32)
189// and PhantomData markers. The closure data is either on the heap (owned) or
190// referenced through a raw pointer (borrowed), neither of which is stored inline.
191impl<T: ?Sized> Unpin for ScopedClosure<'_, T> {}
192
193fn _assert_compiles<T>(pin: core::pin::Pin<&mut ScopedClosure<'static, T>>) {
194    let _ = &mut *pin.get_mut();
195}
196
197impl<T: ?Sized> Drop for ScopedClosure<'_, T> {
198    fn drop(&mut self) {
199        // Invalidate the closure on the JS side.
200        //
201        // The JS bindings distinguish owned vs borrowed closures via the `dtor_idx`
202        // encoded in `WasmDescribe`: owned closures pass a non-zero destructor
203        // function pointer, borrowed closures pass `0`.
204        //
205        // For owned closures (`Closure::new`/`ScopedClosure::own`), this decreases
206        // the refcount and frees the Rust heap data when the count reaches zero.
207        //
208        // For borrowed closures (`ScopedClosure::borrow`/`borrow_mut`), this sets
209        // state.a = state.b = 0 to prevent any further calls to the closure.
210        self.js._wbg_cb_unref();
211    }
212}
213
214impl<'a, T> ScopedClosure<'a, T>
215where
216    T: ?Sized + WasmClosure,
217{
218    /// Obtain a `&JsValue` reference for this closure
219    pub fn as_js_value(&self) -> &JsValue {
220        self.js.unchecked_ref()
221    }
222}
223
224/// Methods for creating and managing `'static` closures.
225///
226/// These methods are only available on `ScopedClosure<'static, T>`
227/// not on borrowed `ScopedClosure<'a, T>` where `'a` is not `'static`.
228impl<T> ScopedClosure<'static, T>
229where
230    T: ?Sized + WasmClosure,
231{
232    /// Alias for [`Closure::own`].
233    ///
234    /// Creates a new static owned `ScopedClosure<'static, T>` from the provided
235    /// Rust function, with panic unwind support.
236    ///
237    /// The type parameter `T` determines whether the closure is `Fn` or `FnMut`.
238    ///
239    /// Supports unwind via its UnwindSafe bound when building with panic=unwind.
240    /// Alternatively, pass `Closure::own(AssertUnwindSafe(...))` to assert unwind
241    /// safety, or use [`own_assert_unwind_safe`](Self::own_assert_unwind_safe) or
242    /// [`own_aborting`](Self::own_aborting).
243    ///
244    /// When provided to a JS function as an own value, to be managed by the JS GC.
245    ///
246    /// See [`borrow`](Self::borrow) for creating a borrowed `ScopedClosure` with
247    /// an associated lifetime (defaults to immutable `Fn`).
248    pub fn new<F>(t: F) -> Self
249    where
250        F: IntoWasmClosure<T> + MaybeUnwindSafe + 'static,
251    {
252        Self::own(t)
253    }
254
255    /// Creates a new static owned `ScopedClosure<'static, T>` from the provided
256    /// Rust function, with panic unwind support.
257    ///
258    /// The type parameter `T` determines whether the closure is `Fn` or `FnMut`.
259    ///
260    /// Supports unwind via its UnwindSafe bound when building with panic=unwind.
261    /// Alternatively, pass `Closure::own(AssertUnwindSafe(...))` to assert unwind
262    /// safety, or use [`own_assert_unwind_safe`](Self::own_assert_unwind_safe) or
263    /// [`own_aborting`](Self::own_aborting).
264    ///
265    /// When provided to a JS function as an own value, to be managed by the JS GC.
266    ///
267    /// See [`borrow`](Self::borrow) for creating a borrowed `ScopedClosure` with
268    /// an associated lifetime (defaults to immutable `Fn`).
269    pub fn own<F>(t: F) -> Self
270    where
271        F: IntoWasmClosure<T> + MaybeUnwindSafe + 'static,
272    {
273        Self::wrap_maybe_aborting::<true>(Box::new(t))
274    }
275
276    /// Creates a new owned `'static` closure that aborts on panic.
277    ///
278    /// Unlike [`own`](Self::own), this version does NOT catch panics and does NOT
279    /// require `UnwindSafe`. If the closure panics, the process will abort.
280    ///
281    /// The type parameter `T` determines whether the closure is `Fn` or `FnMut`.
282    ///
283    /// When provided to a JS function as an own value, to be managed by the JS GC.
284    ///
285    /// See [`borrow_aborting`](Self::borrow_aborting) for creating a borrowed
286    /// `ScopedClosure` with an associated lifetime.
287    ///
288    /// **Note: Not unwind safe. Prefer [`own`](Self::own) or `own` with
289    /// [`AssertUnwindSafe`](core::panic::AssertUnwindSafe) when possible.**
290    pub fn own_aborting<F>(t: F) -> Self
291    where
292        F: IntoWasmClosure<T> + 'static,
293    {
294        Self::wrap_maybe_aborting::<false>(Box::new(t))
295    }
296
297    /// Creates a new static owned `ScopedClosure<'static, T>` from the provided
298    /// Rust function, with panic unwind support.
299    ///
300    /// The type parameter `T` determines whether the closure is `Fn` or `FnMut`.
301    ///
302    /// When provided to a JS function as an own value, to be managed by the JS GC.
303    ///
304    /// **Safety: Unwind safety is assumed when using this function, like using
305    /// `AssertUnwindSafe(...)`, this must be verified explicitly.**
306    ///
307    /// See [`borrow_aborting`](Self::borrow_aborting) for creating a borrowed
308    /// `ScopedClosure` with an associated lifetime.
309    pub fn own_assert_unwind_safe<F>(t: F) -> Self
310    where
311        F: IntoWasmClosure<T> + 'static,
312    {
313        Self::wrap_maybe_aborting::<true>(Box::new(t))
314    }
315
316    /// A more direct version of `Closure::new` which creates a `Closure` from
317    /// a `Box<dyn Fn>`/`Box<dyn FnMut>`, which is how it's kept internally.
318    ///
319    /// Supports unwind via its UnwindSafe bound when building with panic=unwind.
320    /// Alternatively, use [`wrap_assert_unwind_safe`](Self::wrap_assert_unwind_safe)
321    /// to assert unwind safety, or use [`wrap_aborting`](Self::wrap_aborting).
322    ///
323    pub fn wrap<F>(data: Box<F>) -> Self
324    where
325        F: IntoWasmClosure<T> + ?Sized + MaybeUnwindSafe,
326    {
327        Self::wrap_maybe_aborting::<true>(data)
328    }
329
330    /// A more direct version of `Closure::new` which creates a `Closure` from
331    /// a `Box<dyn Fn>`/`Box<dyn FnMut>`, which is how it's kept internally.
332    ///
333    /// This version aborts on panics.
334    pub fn wrap_aborting<F>(data: Box<F>) -> Self
335    where
336        F: IntoWasmClosure<T> + ?Sized,
337    {
338        Self::wrap_maybe_aborting::<false>(data)
339    }
340
341    /// A more direct version of `Closure::new` which creates a `Closure` from
342    /// a `Box<dyn Fn>`/`Box<dyn FnMut>`, which is how it's kept internally.
343    ///
344    /// **Safety: Unwind safety is assumed when using this function, like using
345    /// `AssertUnwindSafe(...)`, this must be verified explicitly.**
346    ///
347    /// This version catches panics when unwinding is available.
348    pub fn wrap_assert_unwind_safe<F>(data: Box<F>) -> Self
349    where
350        F: IntoWasmClosure<T> + ?Sized,
351    {
352        Self::wrap_maybe_aborting::<true>(data)
353    }
354
355    fn wrap_maybe_aborting<const UNWIND_SAFE: bool>(
356        data: Box<impl IntoWasmClosure<T> + ?Sized>,
357    ) -> Self {
358        Self {
359            js: crate::__rt::wbg_cast(OwnedClosure::<T, UNWIND_SAFE>(data.unsize())),
360            _marker: PhantomData,
361            _lifetime: PhantomData,
362        }
363    }
364
365    /// Creates a scoped closure by borrowing an immutable `Fn` closure with
366    /// panic unwind support.
367    ///
368    /// This is the recommended way to pass closures to JavaScript for immediate/
369    /// synchronous use. Unlike [`Closure::own`], this does not require the closure
370    /// to be `'static`, allowing you to capture references to local variables.
371    ///
372    /// Use [`borrow_mut`](Self::borrow_mut) when you need to mutate captured state.
373    ///
374    /// The returned `ScopedClosure<'a, _>` has lifetime `'a` from the closure
375    /// reference, which means it cannot outlive the closure or any data the
376    /// closure captures.
377    ///
378    /// Supports unwind via its UnwindSafe bound when building with panic=unwind.
379    /// Wrap with `AssertUnwindSafe` if necessary to achieve this bound, or
380    /// use [`borrow_assert_unwind_safe`](Self::borrow_assert_unwind_safe) or
381    /// [`borrow_aborting`](Self::borrow_aborting) for non-unwind-safe functions.
382    ///
383    /// The resulting closure can be upcasted to `FnMut` using [`upcast_ref`](crate::Upcast::upcast_ref).
384    ///
385    /// # When to use scoped closures
386    ///
387    /// Use `ScopedClosure::borrow` or `ScopedClosure::borrow_mut` when:
388    /// - JavaScript will call the closure immediately and not retain it
389    /// - You need to capture non-`'static` references
390    /// - You want automatic cleanup when the `ScopedClosure` is dropped
391    ///
392    /// # Closure lifetime
393    ///
394    /// The JavaScript function is only valid while the `ScopedClosure` exists.
395    /// Once dropped, the JavaScript function is invalidated. If JavaScript retains
396    /// a reference and calls it later, it will throw: "closure invoked recursively
397    /// or after being dropped".
398    ///
399    /// Rust's borrow checker ensures `ScopedClosure` cannot outlive the closure's
400    /// captured data, preventing use-after-free bugs.
401    ///
402    /// # Example
403    ///
404    /// ```ignore
405    /// use wasm_bindgen::prelude::*;
406    ///
407    /// #[wasm_bindgen]
408    /// extern "C" {
409    ///     fn call_with_value(cb: &ScopedClosure<dyn Fn(u32)>, value: u32);
410    ///     fn call_fnmut(cb: &ScopedClosure<dyn FnMut(u32)>, value: u32);
411    /// }
412    ///
413    /// let data = vec![1, 2, 3];
414    /// let f = |x| {
415    ///     println!("data len: {}, x: {}", data.len(), x);
416    /// };
417    /// let closure = ScopedClosure::borrow(&f);
418    /// call_with_value(&closure, 42);
419    /// // Can also upcast to FnMut
420    /// call_fnmut(closure.upcast_ref(), 42);
421    /// ```
422    pub fn borrow<'a, F>(t: &'a F) -> ScopedClosure<'a, T::Static>
423    where
424        F: IntoWasmClosureRef<T> + MaybeUnwindSafe + ?Sized,
425    {
426        Self::borrow_assert_unwind_safe(t)
427    }
428
429    /// Like [`borrow`](Self::borrow), but does not catch panics.
430    ///
431    /// If the closure panics, the process will abort. This variant does not
432    /// require `UnwindSafe`.
433    ///
434    /// **Note: Not unwind safe. Prefer [`borrow`](Self::borrow) or
435    /// [`borrow_assert_unwind_safe`](Self::borrow_assert_unwind_safe) when possible.**
436    pub fn borrow_aborting<'a, F>(t: &'a F) -> ScopedClosure<'a, T::Static>
437    where
438        F: IntoWasmClosureRef<T> + ?Sized,
439    {
440        Self::wrap_borrow::<_, false>(t)
441    }
442
443    /// Like [`borrow`](Self::borrow), but catches panics without requiring `MaybeUnwindSafe`.
444    ///
445    /// **Safety: Unwind safety is assumed when using this function, like using
446    /// `AssertUnwindSafe(...)`, this must be verified explicitly.**
447    pub fn borrow_assert_unwind_safe<'a, F>(t: &'a F) -> ScopedClosure<'a, T::Static>
448    where
449        F: IntoWasmClosureRef<T> + ?Sized,
450    {
451        Self::wrap_borrow::<_, true>(t)
452    }
453
454    fn wrap_borrow<'a, F, const UNWIND_SAFE: bool>(t: &'a F) -> ScopedClosure<'a, T::Static>
455    where
456        F: IntoWasmClosureRef<T> + ?Sized,
457    {
458        let t: &T = t.unsize_closure_ref();
459        let (ptr, len): (usize, usize) = unsafe { mem::transmute_copy(&t) };
460        ScopedClosure {
461            js: crate::__rt::wbg_cast(BorrowedClosure::<T, UNWIND_SAFE> {
462                data: WasmSlice::from_usize(ptr, len),
463                _marker: PhantomData,
464            }),
465            _marker: PhantomData,
466            _lifetime: PhantomData,
467        }
468    }
469
470    /// Creates a scoped closure by mutably borrowing a `FnMut` closure.
471    ///
472    /// Use this for closures that need to mutate captured state. For closures that
473    /// don't need mutation, prefer [`borrow`](Self::borrow) which creates an immutable
474    /// `Fn` closure that is more likely to satisfy `UnwindSafe` automatically.
475    ///
476    /// Supports unwind via its UnwindSafe bound when building with panic=unwind.
477    /// Wrap with `AssertUnwindSafe` if necessary to achieve this bound, or
478    /// use [`borrow_mut_assert_unwind_safe`](Self::borrow_mut_assert_unwind_safe) or
479    /// [`borrow_mut_aborting`](Self::borrow_mut_aborting) for non-unwind-safe functions.
480    ///
481    /// See [`borrow`](Self::borrow) for full documentation on scoped closures.
482    ///
483    /// # Example
484    ///
485    /// ```ignore
486    /// use wasm_bindgen::prelude::*;
487    ///
488    /// #[wasm_bindgen]
489    /// extern "C" {
490    ///     fn call_three_times(cb: &ScopedClosure<dyn FnMut(u32)>);
491    /// }
492    ///
493    /// let mut sum = 0;
494    /// let closure = ScopedClosure::borrow_mut(&mut |x: u32| {
495    ///     sum += x;
496    /// });
497    /// call_three_times(&closure);
498    /// // closure dropped, `sum` is accessible again
499    /// assert_eq!(sum, 6); // 1 + 2 + 3
500    /// ```
501    pub fn borrow_mut<'a, F>(t: &'a mut F) -> ScopedClosure<'a, T::Static>
502    where
503        F: IntoWasmClosureRefMut<T> + MaybeUnwindSafe + ?Sized,
504    {
505        Self::borrow_mut_assert_unwind_safe(t)
506    }
507
508    /// Like [`borrow_mut`](Self::borrow_mut), but does not catch panics.
509    ///
510    /// If the closure panics, the process will abort. This variant does not
511    /// require `UnwindSafe`.
512    ///
513    /// **Note: Not unwind safe. Prefer [`borrow_mut`](Self::borrow_mut) or
514    /// [`borrow_mut_assert_unwind_safe`](Self::borrow_mut_assert_unwind_safe) when possible.**
515    pub fn borrow_mut_aborting<'a, F>(t: &'a mut F) -> ScopedClosure<'a, T::Static>
516    where
517        F: IntoWasmClosureRefMut<T> + ?Sized,
518    {
519        Self::wrap_borrow_mut::<_, false>(t)
520    }
521
522    /// Like [`borrow_mut`](Self::borrow_mut), but catches panics without requiring `MaybeUnwindSafe`.
523    ///
524    /// **Safety: Unwind safety is assumed when using this function, like using
525    /// `AssertUnwindSafe(...)`, this must be verified explicitly.**
526    pub fn borrow_mut_assert_unwind_safe<'a, F>(t: &'a mut F) -> ScopedClosure<'a, T::Static>
527    where
528        F: IntoWasmClosureRefMut<T> + ?Sized,
529    {
530        Self::wrap_borrow_mut::<_, true>(t)
531    }
532
533    fn wrap_borrow_mut<'a, F, const UNWIND_SAFE: bool>(t: &'a mut F) -> ScopedClosure<'a, T::Static>
534    where
535        F: IntoWasmClosureRefMut<T> + ?Sized,
536    {
537        let t: &mut T = t.unsize_closure_ref();
538        let (ptr, len): (usize, usize) = unsafe { mem::transmute_copy(&t) };
539        ScopedClosure {
540            js: crate::__rt::wbg_cast(BorrowedClosure::<T, UNWIND_SAFE> {
541                data: WasmSlice::from_usize(ptr, len),
542                _marker: PhantomData,
543            }),
544            _marker: PhantomData,
545            _lifetime: PhantomData,
546        }
547    }
548
549    /// Release memory management of this closure from Rust to the JS GC.
550    ///
551    /// When a `Closure` is dropped it will release the Rust memory and
552    /// invalidate the associated JS closure, but this isn't always desired.
553    /// Some callbacks are alive for the entire duration of the program or for a
554    /// lifetime dynamically managed by the JS GC. This function can be used
555    /// to drop this `Closure` while keeping the associated JS function still
556    /// valid.
557    ///
558    /// If the platform supports weak references, the Rust memory will be
559    /// reclaimed when the JS closure is GC'd. If weak references is not
560    /// supported, this can be dangerous if this function is called many times
561    /// in an application because the memory leak will overwhelm the page
562    /// quickly and crash the wasm.
563    ///
564    /// # Safety Note
565    ///
566    /// This method is only available on `'static` closures. Calling it on a
567    /// borrowed `ScopedClosure` would be unsound because the closure data
568    /// would become invalid when the borrow ends.
569    pub fn into_js_value(self) -> JsValue {
570        let idx = self.js.idx;
571        mem::forget(self);
572        JsValue::_new(idx)
573    }
574
575    /// Same as `mem::forget(self)`.
576    ///
577    /// This can be used to fully relinquish closure ownership to the JS.
578    ///
579    /// # Safety Note
580    ///
581    /// This method is only available on `'static` closures. Calling it on a borrowed
582    /// `ScopedClosure` would be unsound because the closure data would become invalid
583    /// when the borrow ends.
584    pub fn forget(self) {
585        mem::forget(self);
586    }
587
588    /// Create a `Closure` from a function that can only be called once.
589    ///
590    /// Since we have no way of enforcing that JS cannot attempt to call this
591    /// `FnOne(A...) -> R` more than once, this produces a `Closure<dyn FnMut(A...)
592    /// -> R>` that will dynamically throw a JavaScript error if called more
593    /// than once.
594    ///
595    /// # Example
596    ///
597    /// ```rust,no_run
598    /// use wasm_bindgen::prelude::*;
599    ///
600    /// // Create an non-`Copy`, owned `String`.
601    /// let mut s = String::from("Hello");
602    ///
603    /// // Close over `s`. Since `f` returns `s`, it is `FnOnce` and can only be
604    /// // called once. If it was called a second time, it wouldn't have any `s`
605    /// // to work with anymore!
606    /// let f = move || {
607    ///     s += ", World!";
608    ///     s
609    /// };
610    ///
611    /// // Create a `Closure` from `f`. Note that the `Closure`'s type parameter
612    /// // is `FnMut`, even though `f` is `FnOnce`.
613    /// let closure: Closure<dyn FnMut() -> String> = Closure::once(f);
614    /// ```
615    ///
616    /// Note: the `A` and `R` type parameters are here just for backward compat
617    /// and will be removed in the future.
618    pub fn once<F, A, R>(fn_once: F) -> Self
619    where
620        F: WasmClosureFnOnce<T, A, R> + MaybeUnwindSafe,
621    {
622        Closure::wrap_maybe_aborting::<true>(fn_once.into_fn_mut())
623    }
624
625    /// Create a `Closure` from a function that can only be called once.
626    ///
627    /// Unlike `once`, this version does NOT catch panics and does NOT require `UnwindSafe`.
628    /// If the closure panics, the process will abort.
629    ///
630    /// Use this when:
631    /// - Your closure captures types that aren't `UnwindSafe` (like `Rc<Cell<T>>`)
632    /// - You don't need panic catching across the JS boundary
633    /// - You prefer abort-on-panic behavior
634    ///
635    /// Since we have no way of enforcing that JS cannot attempt to call this
636    /// `FnOnce(A...) -> R` more than once, this produces a `Closure<dyn FnMut(A...)
637    /// -> R>` that will dynamically throw a JavaScript error if called more
638    /// than once.
639    ///
640    /// **Note: Not unwind safe. Prefer [`once`](Self::once) or `once` with
641    /// [`AssertUnwindSafe`](core::panic::AssertUnwindSafe) when possible.**
642    ///
643    /// Note: the `A` and `R` type parameters are here just for backward compat
644    /// and will be removed in the future.
645    pub fn once_aborting<F, A, R>(fn_once: F) -> Self
646    where
647        F: WasmClosureFnOnceAbort<T, A, R>,
648    {
649        Closure::wrap_maybe_aborting::<false>(fn_once.into_fn_mut())
650    }
651
652    /// Create a `Closure` from a function that can only be called once,
653    /// with panic unwind support.
654    ///
655    /// **Safety: Unwind safety is assumed when using this function, like using
656    /// `AssertUnwindSafe(...)`, this must be verified explicitly.**
657    ///
658    /// Use this when:
659    /// - Your closure captures types that aren't `UnwindSafe` (like `Rc<Cell<T>>`)
660    /// - You still want panics to be caught and converted to JS exceptions
661    ///
662    /// Since we have no way of enforcing that JS cannot attempt to call this
663    /// `FnOnce(A...) -> R` more than once, this produces a `Closure<dyn FnMut(A...)
664    /// -> R>` that will dynamically throw a JavaScript error if called more
665    /// than once.
666    ///
667    /// Note: the `A` and `R` type parameters are here just for backward compat
668    /// and will be removed in the future.
669    pub fn once_assert_unwind_safe<F, A, R>(fn_once: F) -> Self
670    where
671        F: WasmClosureFnOnceAbort<T, A, R>,
672    {
673        Closure::wrap_maybe_aborting::<true>(fn_once.into_fn_mut())
674    }
675
676    // TODO: Update once closures to be generated on construction as once
677    // closures instead of using wrap(). Then we can share the same into_js()
678    // function between all closures, and deprecate this method.
679    /// Convert a `FnOnce(A...) -> R` into a JavaScript `Function` object.
680    ///
681    /// If the JavaScript function is invoked more than once, it will throw an
682    /// exception.
683    ///
684    /// Unlike `Closure::once`, this does *not* return a `Closure` that can be
685    /// dropped before the function is invoked to deallocate the closure. The
686    /// only way the `FnOnce` is deallocated is by calling the JavaScript
687    /// function. If the JavaScript function is never called then the `FnOnce`
688    /// and everything it closes over will leak.
689    ///
690    /// ```rust,ignore
691    /// use wasm_bindgen::{prelude::*, JsCast};
692    ///
693    /// let f = Closure::once_into_js(move || {
694    ///     // ...
695    /// });
696    ///
697    /// assert!(f.is_instance_of::<js_sys::Function>());
698    /// ```
699    ///
700    /// Note: the `A` and `R` type parameters are here just for backward compat
701    /// and will be removed in the future.
702    pub fn once_into_js<F, A, R>(fn_once: F) -> JsValue
703    where
704        F: WasmClosureFnOnce<T, A, R> + MaybeUnwindSafe,
705    {
706        fn_once.into_js_function()
707    }
708}
709
710/// A trait for converting an `FnOnce(A...) -> R` into a `FnMut(A...) -> R` that
711/// will throw if ever called more than once.
712#[doc(hidden)]
713pub trait WasmClosureFnOnce<FnMut: ?Sized, A, R>: 'static {
714    fn into_fn_mut(self) -> Box<FnMut>;
715
716    fn into_js_function(self) -> JsValue;
717}
718
719/// A trait for converting an `FnOnce(A...) -> R` into a `FnMut(A...) -> R` that
720/// will throw if ever called more than once. This variant does not require UnwindSafe.
721#[doc(hidden)]
722pub trait WasmClosureFnOnceAbort<FnMut: ?Sized, A, R>: 'static {
723    fn into_fn_mut(self) -> Box<FnMut>;
724
725    fn into_js_function(self) -> JsValue;
726}
727
728impl<T: ?Sized> AsRef<JsValue> for ScopedClosure<'_, T> {
729    fn as_ref(&self) -> &JsValue {
730        &self.js
731    }
732}
733
734/// Internal representation of an owned closure sent to JS.
735/// `UNWIND_SAFE` selects the invoke shim: `true` catches panics, `false` does not.
736#[repr(transparent)]
737struct OwnedClosure<T: ?Sized, const UNWIND_SAFE: bool>(Box<T>);
738
739/// Internal representation of a borrowed closure sent to JS.
740/// `UNWIND_SAFE` selects the invoke shim: `true` catches panics, `false` does not.
741struct BorrowedClosure<T: ?Sized, const UNWIND_SAFE: bool> {
742    data: WasmSlice,
743    _marker: PhantomData<T>,
744}
745
746/// Destroys an owned closure by reconstructing and dropping its
747/// `Box<dyn Trait>` representation from the raw pointer data `(a, b)`.
748///
749/// # Safety
750///
751/// `(a, b)` must be a valid pair previously produced by `Box::into_raw` on a
752/// `Box<dyn FnOnce/FnMut/Fn>` closure, or `a` must be zero (in which case this
753/// is a no-op).
754#[no_mangle]
755pub unsafe extern "C" fn __wbindgen_destroy_closure(a: WasmWord, b: WasmWord) {
756    if a.is_zero() {
757        return;
758    }
759
760    // Usual way to erase any trait details, so we are just left with layout and
761    // drop implementation that any dyn trait has.
762    // See eg https://doc.rust-lang.org/beta/nightly-rustc/rustc_lint/traits/static.DYN_DROP.html#explanation
763    //
764    // This allows to use `destroy` in a non-generic way for any closures.
765    trait ErasedPlaceholderForDrop {}
766
767    drop(mem::transmute_copy::<_, Box<dyn ErasedPlaceholderForDrop>>(
768        &(a.into_usize(), b.into_usize()),
769    ));
770}
771
772impl<T, const UNWIND_SAFE: bool> WasmDescribe for OwnedClosure<T, UNWIND_SAFE>
773where
774    T: WasmClosure + ?Sized,
775{
776    #[cfg_attr(wasm_bindgen_unstable_test_coverage, coverage(off))]
777    fn describe() {
778        inform(CLOSURE);
779        inform(1);
780        inform(T::IS_MUT as u32);
781        T::describe_invoke::<UNWIND_SAFE>();
782    }
783}
784
785impl<T, const UNWIND_SAFE: bool> WasmDescribe for BorrowedClosure<T, UNWIND_SAFE>
786where
787    T: WasmClosure + ?Sized,
788{
789    #[cfg_attr(wasm_bindgen_unstable_test_coverage, coverage(off))]
790    fn describe() {
791        inform(CLOSURE);
792        inform(0);
793        inform(T::IS_MUT as u32);
794        T::describe_invoke::<UNWIND_SAFE>();
795    }
796}
797
798impl<T, const UNWIND_SAFE: bool> IntoWasmAbi for OwnedClosure<T, UNWIND_SAFE>
799where
800    T: WasmClosure + ?Sized,
801{
802    type Abi = WasmSlice;
803
804    fn into_abi(self) -> WasmSlice {
805        let (a, b): (usize, usize) = unsafe { mem::transmute_copy(&ManuallyDrop::new(self)) };
806        WasmSlice::from_usize(a, b)
807    }
808}
809
810impl<T, const UNWIND_SAFE: bool> IntoWasmAbi for BorrowedClosure<T, UNWIND_SAFE>
811where
812    T: WasmClosure + ?Sized,
813{
814    type Abi = WasmSlice;
815    fn into_abi(self) -> WasmSlice {
816        self.data
817    }
818}
819
820impl<T> WasmDescribe for ScopedClosure<'_, T>
821where
822    T: WasmClosure + ?Sized,
823{
824    #[cfg_attr(wasm_bindgen_unstable_test_coverage, coverage(off))]
825    fn describe() {
826        inform(EXTERNREF);
827    }
828}
829
830// `ScopedClosure` can be passed by reference to imports (for any lifetime).
831impl<T> IntoWasmAbi for &ScopedClosure<'_, T>
832where
833    T: WasmClosure + ?Sized,
834{
835    type Abi = u32;
836
837    fn into_abi(self) -> u32 {
838        (&self.js).into_abi()
839    }
840}
841
842impl<T> OptionIntoWasmAbi for &ScopedClosure<'_, T>
843where
844    T: WasmClosure + ?Sized,
845{
846    fn none() -> Self::Abi {
847        0
848    }
849}
850
851/// `'static` closures can be passed by value to JS, transferring ownership.
852///
853/// This is useful for one-shot callbacks where you want JS to own the closure.
854/// The closure will be cleaned up by JS GC (if weak references are supported)
855/// or will leak (if weak references are not supported).
856///
857/// # Example
858///
859/// ```ignore
860/// #[wasm_bindgen]
861/// extern "C" {
862///     fn set_one_shot_callback(cb: Closure<dyn FnMut()>);
863/// }
864///
865/// let cb = Closure::new(|| { /* ... */ });
866/// set_one_shot_callback(cb);  // Ownership transferred to JS
867/// // No need to store or forget the closure
868/// ```
869impl<T> IntoWasmAbi for ScopedClosure<'static, T>
870where
871    T: WasmClosure + ?Sized,
872{
873    type Abi = u32;
874
875    fn into_abi(self) -> u32 {
876        let idx = self.js.idx;
877        mem::forget(self);
878        idx
879    }
880}
881
882impl<T> OptionIntoWasmAbi for ScopedClosure<'static, T>
883where
884    T: WasmClosure + ?Sized,
885{
886    fn none() -> Self::Abi {
887        0
888    }
889}
890
891fn _check() {
892    fn _assert<T: IntoWasmAbi>() {}
893    // ScopedClosure by reference (any lifetime)
894    _assert::<&ScopedClosure<dyn Fn()>>();
895    _assert::<&ScopedClosure<dyn Fn(String)>>();
896    _assert::<&ScopedClosure<dyn Fn() -> String>>();
897    _assert::<&ScopedClosure<dyn FnMut()>>();
898    _assert::<&ScopedClosure<dyn FnMut(String)>>();
899    _assert::<&ScopedClosure<dyn FnMut() -> String>>();
900    // ScopedClosure by value (only 'static)
901    _assert::<ScopedClosure<'static, dyn Fn()>>();
902    _assert::<ScopedClosure<'static, dyn FnMut()>>();
903    _assert::<Closure<dyn Fn()>>();
904    _assert::<Closure<dyn FnMut()>>();
905}
906
907impl<T> fmt::Debug for ScopedClosure<'_, T>
908where
909    T: ?Sized,
910{
911    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
912        write!(f, "Closure {{ ... }}")
913    }
914}
915
916/// An internal trait for the `Closure` type.
917///
918/// This trait is not stable and it's not recommended to use this in bounds or
919/// implement yourself.
920#[doc(hidden)]
921pub unsafe trait WasmClosure: WasmDescribe {
922    const IS_MUT: bool;
923    /// The `'static` version of `Self`. For example, if `Self` is `dyn Fn() + 'a`,
924    /// then `Static` is `dyn Fn()` (implicitly `'static`).
925    type Static: ?Sized + WasmClosure;
926    /// The mutable version of this closure type.
927    /// For `dyn Fn(...) -> R` this is `dyn FnMut(...) -> R`.
928    /// For `dyn FnMut(...) -> R` this is itself.
929    type AsMut: ?Sized;
930    /// Emit the FUNCTION descriptor with the invoke shim selected by
931    /// `UNWIND_SAFE`: `true` picks the panic-catching shim, `false`
932    /// picks the non-catching shim.
933    fn describe_invoke<const UNWIND_SAFE: bool>();
934}
935
936unsafe impl<T: WasmClosure> WasmClosure for AssertUnwindSafe<T> {
937    type Static = T::Static;
938    const IS_MUT: bool = T::IS_MUT;
939    type AsMut = T::AsMut;
940    fn describe_invoke<const UNWIND_SAFE: bool>() {
941        T::describe_invoke::<UNWIND_SAFE>();
942    }
943}
944
945/// An internal trait for the `Closure` type.
946///
947/// This trait is not stable and it's not recommended to use this in bounds or
948/// implement yourself.
949#[doc(hidden)]
950pub trait IntoWasmClosure<T: ?Sized> {
951    fn unsize(self: Box<Self>) -> Box<T>;
952}
953
954impl<T: ?Sized + WasmClosure> IntoWasmClosure<T> for T {
955    fn unsize(self: Box<Self>) -> Box<T> {
956        self
957    }
958}
959
960/// Trait for converting a reference to a closure into a trait object reference.
961///
962/// This trait is not stable and it's not recommended to use this in bounds or
963/// implement yourself.
964#[doc(hidden)]
965pub trait IntoWasmClosureRef<T: ?Sized> {
966    fn unsize_closure_ref(&self) -> &T;
967}
968
969/// Trait for converting a mutable reference to a closure into a trait object reference.
970///
971/// This trait is not stable and it's not recommended to use this in bounds or
972/// implement yourself.
973#[doc(hidden)]
974pub trait IntoWasmClosureRefMut<T: ?Sized> {
975    fn unsize_closure_ref(&mut self) -> &mut T;
976}
977
978// Blanket impl for AssertUnwindSafe - delegates to inner type
979impl<T: ?Sized, F> IntoWasmClosureRef<T> for AssertUnwindSafe<F>
980where
981    F: IntoWasmClosureRef<T>,
982{
983    fn unsize_closure_ref(&self) -> &T {
984        self.0.unsize_closure_ref()
985    }
986}
987
988impl<T: ?Sized, F> IntoWasmClosureRefMut<T> for AssertUnwindSafe<F>
989where
990    F: IntoWasmClosureRefMut<T>,
991{
992    fn unsize_closure_ref(&mut self) -> &mut T {
993        self.0.unsize_closure_ref()
994    }
995}
996
997// In ScopedClosure, the Rust closure type is the phantom type that erases.
998unsafe impl<T: ?Sized + WasmClosure> ErasableGeneric for ScopedClosure<'_, T> {
999    type Repr = ScopedClosure<'static, dyn FnMut()>;
1000}