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 /// Alias for [`Closure::own`].
235 ///
236 /// Creates a new static owned `ScopedClosure<'static, T>` from the provided
237 /// Rust function, with panic unwind support.
238 ///
239 /// The type parameter `T` determines whether the closure is `Fn` or `FnMut`.
240 ///
241 /// Supports unwind via its UnwindSafe bound when building with panic=unwind.
242 /// Alternatively, pass `Closure::own(AssertUnwindSafe(...))` to assert unwind
243 /// safety, or use [`own_assert_unwind_safe`](Self::own_assert_unwind_safe) or
244 /// [`own_aborting`](Self::own_aborting).
245 ///
246 /// When provided to a JS function as an own value, to be managed by the JS GC.
247 ///
248 /// See [`borrow`](Self::borrow) for creating a borrowed `ScopedClosure` with
249 /// an associated lifetime (defaults to immutable `Fn`).
250 pub fn new<F>(t: F) -> Self
251 where
252 F: IntoWasmClosure<T> + MaybeUnwindSafe + 'static,
253 {
254 Self::_wrap(Box::new(t).unsize(), true)
255 }
256
257 /// Creates a new static owned `ScopedClosure<'static, T>` from the provided
258 /// Rust function, with panic unwind support.
259 ///
260 /// The type parameter `T` determines whether the closure is `Fn` or `FnMut`.
261 ///
262 /// Supports unwind via its UnwindSafe bound when building with panic=unwind.
263 /// Alternatively, pass `Closure::own(AssertUnwindSafe(...))` to assert unwind
264 /// safety, or use [`own_assert_unwind_safe`](Self::own_assert_unwind_safe) or
265 /// [`own_aborting`](Self::own_aborting).
266 ///
267 /// When provided to a JS function as an own value, to be managed by the JS GC.
268 ///
269 /// See [`borrow`](Self::borrow) for creating a borrowed `ScopedClosure` with
270 /// an associated lifetime (defaults to immutable `Fn`).
271 pub fn own<F>(t: F) -> Self
272 where
273 F: IntoWasmClosure<T> + MaybeUnwindSafe + 'static,
274 {
275 Self::_wrap(Box::new(t).unsize(), true)
276 }
277
278 /// Creates a new owned `'static` closure that aborts on panic.
279 ///
280 /// Unlike [`own`](Self::own), this version does NOT catch panics and does NOT
281 /// require `UnwindSafe`. If the closure panics, the process will abort.
282 ///
283 /// The type parameter `T` determines whether the closure is `Fn` or `FnMut`.
284 ///
285 /// When provided to a JS function as an own value, to be managed by the JS GC.
286 ///
287 /// See [`borrow_aborting`](Self::borrow_aborting) for creating a borrowed
288 /// `ScopedClosure` with an associated lifetime.
289 ///
290 /// **Note: Not unwind safe. Prefer [`own`](Self::own) or `own` with
291 /// [`AssertUnwindSafe`](core::panic::AssertUnwindSafe) when possible.**
292 pub fn own_aborting<F>(t: F) -> Self
293 where
294 F: IntoWasmClosure<T> + 'static,
295 {
296 Self::_wrap(Box::new(t).unsize(), false)
297 }
298
299 /// Creates a new static owned `ScopedClosure<'static, T>` from the provided
300 /// Rust function, with panic unwind support.
301 ///
302 /// The type parameter `T` determines whether the closure is `Fn` or `FnMut`.
303 ///
304 /// When provided to a JS function as an own value, to be managed by the JS GC.
305 ///
306 /// **Safety: Unwind safety is assumed when using this function, like using
307 /// `AssertUnwindSafe(...)`, this must be verified explicitly.**
308 ///
309 /// See [`borrow_aborting`](Self::borrow_aborting) for creating a borrowed
310 /// `ScopedClosure` with an associated lifetime.
311 pub fn own_assert_unwind_safe<F>(t: F) -> Self
312 where
313 F: IntoWasmClosure<T> + 'static,
314 {
315 Self::_wrap(Box::new(t).unsize(), true)
316 }
317
318 /// A more direct version of `Closure::new` which creates a `Closure` from
319 /// a `Box<dyn Fn>`/`Box<dyn FnMut>`, which is how it's kept internally.
320 ///
321 /// Supports unwind via its UnwindSafe bound when building with panic=unwind.
322 /// Alternatively, use [`wrap_assert_unwind_safe`](Self::wrap_assert_unwind_safe)
323 /// to assert unwind safety, or use [`wrap_aborting`](Self::wrap_aborting).
324 ///
325 pub fn wrap<F>(data: Box<F>) -> Self
326 where
327 F: IntoWasmClosure<T> + ?Sized + MaybeUnwindSafe,
328 {
329 Self::_wrap(data.unsize(), true)
330 }
331
332 /// A more direct version of `Closure::new` which creates a `Closure` from
333 /// a `Box<dyn Fn>`/`Box<dyn FnMut>`, which is how it's kept internally.
334 ///
335 /// This version aborts on panics.
336 pub fn wrap_aborting<F>(data: Box<F>) -> Self
337 where
338 F: IntoWasmClosure<T> + ?Sized,
339 {
340 Self::_wrap(data.unsize(), false)
341 }
342
343 /// A more direct version of `Closure::new` which creates a `Closure` from
344 /// a `Box<dyn Fn>`/`Box<dyn FnMut>`, which is how it's kept internally.
345 ///
346 /// **Safety: Unwind safety is assumed when using this function, like using
347 /// `AssertUnwindSafe(...)`, this must be verified explicitly.**
348 ///
349 /// This version catches panics when unwinding is available.
350 pub fn wrap_assert_unwind_safe<F>(data: Box<F>) -> Self
351 where
352 F: IntoWasmClosure<T> + ?Sized,
353 {
354 Self::_wrap(data.unsize(), true)
355 }
356
357 #[cfg(all(feature = "std", target_arch = "wasm32", panic = "unwind"))]
358 fn _wrap(data: Box<T>, unwind_safe: bool) -> Self {
359 Self {
360 js: crate::__rt::wbg_cast(OwnedClosureUnwind { data, unwind_safe }),
361 _marker: PhantomData,
362 _lifetime: PhantomData,
363 }
364 }
365
366 #[cfg(not(all(feature = "std", target_arch = "wasm32", panic = "unwind")))]
367 fn _wrap(data: Box<T>, _unwind_safe: bool) -> Self {
368 Self {
369 js: crate::__rt::wbg_cast(OwnedClosure(data)),
370 _marker: PhantomData,
371 _lifetime: PhantomData,
372 }
373 }
374
375 /// Creates a scoped closure by borrowing an immutable `Fn` closure with
376 /// panic unwind support.
377 ///
378 /// This is the recommended way to pass closures to JavaScript for immediate/
379 /// synchronous use. Unlike [`Closure::own`], this does not require the closure
380 /// to be `'static`, allowing you to capture references to local variables.
381 ///
382 /// Use [`borrow_mut`](Self::borrow_mut) when you need to mutate captured state.
383 ///
384 /// The returned `ScopedClosure<'a, _>` has lifetime `'a` from the closure
385 /// reference, which means it cannot outlive the closure or any data the
386 /// closure captures.
387 ///
388 /// Supports unwind via its UnwindSafe bound when building with panic=unwind.
389 /// Wrap with `AssertUnwindSafe` if necessary to achieve this bound, or
390 /// use [`borrow_assert_unwind_safe`](Self::borrow_assert_unwind_safe) or
391 /// [`borrow_aborting`](Self::borrow_aborting) for non-unwind-safe functions.
392 ///
393 /// The resulting closure can be upcasted to `FnMut` using [`upcast_ref`](crate::Upcast::upcast_ref).
394 ///
395 /// # When to use scoped closures
396 ///
397 /// Use `ScopedClosure::borrow` or `ScopedClosure::borrow_mut` when:
398 /// - JavaScript will call the closure immediately and not retain it
399 /// - You need to capture non-`'static` references
400 /// - You want automatic cleanup when the `ScopedClosure` is dropped
401 ///
402 /// # Closure lifetime
403 ///
404 /// The JavaScript function is only valid while the `ScopedClosure` exists.
405 /// Once dropped, the JavaScript function is invalidated. If JavaScript retains
406 /// a reference and calls it later, it will throw: "closure invoked recursively
407 /// or after being dropped".
408 ///
409 /// Rust's borrow checker ensures `ScopedClosure` cannot outlive the closure's
410 /// captured data, preventing use-after-free bugs.
411 ///
412 /// # Example
413 ///
414 /// ```ignore
415 /// use wasm_bindgen::prelude::*;
416 ///
417 /// #[wasm_bindgen]
418 /// extern "C" {
419 /// fn call_with_value(cb: &ScopedClosure<dyn Fn(u32)>, value: u32);
420 /// fn call_fnmut(cb: &ScopedClosure<dyn FnMut(u32)>, value: u32);
421 /// }
422 ///
423 /// let data = vec![1, 2, 3];
424 /// let f = |x| {
425 /// println!("data len: {}, x: {}", data.len(), x);
426 /// };
427 /// let closure = ScopedClosure::borrow(&f);
428 /// call_with_value(&closure, 42);
429 /// // Can also upcast to FnMut
430 /// call_fnmut(closure.upcast_ref(), 42);
431 /// ```
432 pub fn borrow<'a, F>(t: &'a F) -> ScopedClosure<'a, F::Static>
433 where
434 F: IntoWasmClosureRef<'a, T> + MaybeUnwindSafe + ?Sized,
435 {
436 let t: &T = t.unsize_closure_ref();
437 let (ptr, len): (u32, u32) = unsafe { mem::transmute_copy(&t) };
438 ScopedClosure {
439 js: crate::__rt::wbg_cast(BorrowedClosure::<T> {
440 data: WasmSlice { ptr, len },
441 unwind_safe: true,
442 _marker: PhantomData,
443 }),
444 _marker: PhantomData,
445 _lifetime: PhantomData,
446 }
447 }
448
449 /// Like [`borrow`](Self::borrow), but does not catch panics.
450 ///
451 /// If the closure panics, the process will abort. This variant does not
452 /// require `UnwindSafe`.
453 ///
454 /// **Note: Not unwind safe. Prefer [`borrow`](Self::borrow) or
455 /// [`borrow_assert_unwind_safe`](Self::borrow_assert_unwind_safe) when possible.**
456 pub fn borrow_aborting<'a, F>(t: &'a F) -> ScopedClosure<'a, F::Static>
457 where
458 F: IntoWasmClosureRef<'a, T> + ?Sized,
459 {
460 let t: &T = t.unsize_closure_ref();
461 let (ptr, len): (u32, u32) = unsafe { mem::transmute_copy(&t) };
462 ScopedClosure {
463 js: crate::__rt::wbg_cast(BorrowedClosure::<T> {
464 data: WasmSlice { ptr, len },
465 unwind_safe: false,
466 _marker: PhantomData,
467 }),
468 _marker: PhantomData,
469 _lifetime: PhantomData,
470 }
471 }
472
473 /// Like [`borrow`](Self::borrow), but catches panics without requiring `MaybeUnwindSafe`.
474 ///
475 /// **Safety: Unwind safety is assumed when using this function, like using
476 /// `AssertUnwindSafe(...)`, this must be verified explicitly.**
477 pub fn borrow_assert_unwind_safe<'a, F>(t: &'a F) -> ScopedClosure<'a, F::Static>
478 where
479 F: IntoWasmClosureRef<'a, T> + ?Sized,
480 {
481 let t: &T = t.unsize_closure_ref();
482 let (ptr, len): (u32, u32) = unsafe { mem::transmute_copy(&t) };
483 ScopedClosure {
484 js: crate::__rt::wbg_cast(BorrowedClosure::<T> {
485 data: WasmSlice { ptr, len },
486 unwind_safe: true,
487 _marker: PhantomData,
488 }),
489 _marker: PhantomData,
490 _lifetime: PhantomData,
491 }
492 }
493
494 /// Creates a scoped closure by mutably borrowing a `FnMut` closure.
495 ///
496 /// Use this for closures that need to mutate captured state. For closures that
497 /// don't need mutation, prefer [`borrow`](Self::borrow) which creates an immutable
498 /// `Fn` closure that is more likely to satisfy `UnwindSafe` automatically.
499 ///
500 /// Supports unwind via its UnwindSafe bound when building with panic=unwind.
501 /// Wrap with `AssertUnwindSafe` if necessary to achieve this bound, or
502 /// use [`borrow_mut_assert_unwind_safe`](Self::borrow_mut_assert_unwind_safe) or
503 /// [`borrow_mut_aborting`](Self::borrow_mut_aborting) for non-unwind-safe functions.
504 ///
505 /// See [`borrow`](Self::borrow) for full documentation on scoped closures.
506 ///
507 /// # Example
508 ///
509 /// ```ignore
510 /// use wasm_bindgen::prelude::*;
511 ///
512 /// #[wasm_bindgen]
513 /// extern "C" {
514 /// fn call_three_times(cb: &ScopedClosure<dyn FnMut(u32)>);
515 /// }
516 ///
517 /// let mut sum = 0;
518 /// let closure = ScopedClosure::borrow_mut(&mut |x: u32| {
519 /// sum += x;
520 /// });
521 /// call_three_times(&closure);
522 /// // closure dropped, `sum` is accessible again
523 /// assert_eq!(sum, 6); // 1 + 2 + 3
524 /// ```
525 pub fn borrow_mut<'a, F>(t: &'a mut F) -> ScopedClosure<'a, F::Static>
526 where
527 F: IntoWasmClosureRefMut<'a, T> + MaybeUnwindSafe + ?Sized,
528 {
529 let t: &mut T = t.unsize_closure_ref();
530 let (ptr, len): (u32, u32) = unsafe { mem::transmute_copy(&t) };
531 ScopedClosure {
532 js: crate::__rt::wbg_cast(BorrowedClosure::<T> {
533 data: WasmSlice { ptr, len },
534 unwind_safe: true,
535 _marker: PhantomData,
536 }),
537 _marker: PhantomData,
538 _lifetime: PhantomData,
539 }
540 }
541
542 /// Like [`borrow_mut`](Self::borrow_mut), but does not catch panics.
543 ///
544 /// If the closure panics, the process will abort. This variant does not
545 /// require `UnwindSafe`.
546 ///
547 /// **Note: Not unwind safe. Prefer [`borrow_mut`](Self::borrow_mut) or
548 /// [`borrow_mut_assert_unwind_safe`](Self::borrow_mut_assert_unwind_safe) when possible.**
549 pub fn borrow_mut_aborting<'a, F>(t: &'a mut F) -> ScopedClosure<'a, F::Static>
550 where
551 F: IntoWasmClosureRefMut<'a, T> + ?Sized,
552 {
553 let t: &mut T = t.unsize_closure_ref();
554 let (ptr, len): (u32, u32) = unsafe { mem::transmute_copy(&t) };
555 ScopedClosure {
556 js: crate::__rt::wbg_cast(BorrowedClosure::<T> {
557 data: WasmSlice { ptr, len },
558 unwind_safe: false,
559 _marker: PhantomData,
560 }),
561 _marker: PhantomData,
562 _lifetime: PhantomData,
563 }
564 }
565
566 /// Like [`borrow_mut`](Self::borrow_mut), but catches panics without requiring `MaybeUnwindSafe`.
567 ///
568 /// **Safety: Unwind safety is assumed when using this function, like using
569 /// `AssertUnwindSafe(...)`, this must be verified explicitly.**
570 pub fn borrow_mut_assert_unwind_safe<'a, F>(t: &'a mut F) -> ScopedClosure<'a, F::Static>
571 where
572 F: IntoWasmClosureRefMut<'a, T> + ?Sized,
573 {
574 let t: &mut T = t.unsize_closure_ref();
575 let (ptr, len): (u32, u32) = unsafe { mem::transmute_copy(&t) };
576 ScopedClosure {
577 js: crate::__rt::wbg_cast(BorrowedClosure::<T> {
578 data: WasmSlice { ptr, len },
579 unwind_safe: true,
580 _marker: PhantomData,
581 }),
582 _marker: PhantomData,
583 _lifetime: PhantomData,
584 }
585 }
586
587 /// Release memory management of this closure from Rust to the JS GC.
588 ///
589 /// When a `Closure` is dropped it will release the Rust memory and
590 /// invalidate the associated JS closure, but this isn't always desired.
591 /// Some callbacks are alive for the entire duration of the program or for a
592 /// lifetime dynamically managed by the JS GC. This function can be used
593 /// to drop this `Closure` while keeping the associated JS function still
594 /// valid.
595 ///
596 /// If the platform supports weak references, the Rust memory will be
597 /// reclaimed when the JS closure is GC'd. If weak references is not
598 /// supported, this can be dangerous if this function is called many times
599 /// in an application because the memory leak will overwhelm the page
600 /// quickly and crash the wasm.
601 ///
602 /// # Safety Note
603 ///
604 /// This method is only available on `'static` closures. Calling it on a
605 /// borrowed `ScopedClosure` would be unsound because the closure data
606 /// would become invalid when the borrow ends.
607 pub fn into_js_value(self) -> JsValue {
608 let idx = self.js.idx;
609 mem::forget(self);
610 JsValue::_new(idx)
611 }
612
613 /// Same as `mem::forget(self)`.
614 ///
615 /// This can be used to fully relinquish closure ownership to the JS.
616 ///
617 /// # Safety Note
618 ///
619 /// This method is only available on `'static` closures. Calling it on a borrowed
620 /// `ScopedClosure` would be unsound because the closure data would become invalid
621 /// when the borrow ends.
622 pub fn forget(self) {
623 mem::forget(self);
624 }
625
626 /// Create a `Closure` from a function that can only be called once.
627 ///
628 /// Since we have no way of enforcing that JS cannot attempt to call this
629 /// `FnOne(A...) -> R` more than once, this produces a `Closure<dyn FnMut(A...)
630 /// -> R>` that will dynamically throw a JavaScript error if called more
631 /// than once.
632 ///
633 /// # Example
634 ///
635 /// ```rust,no_run
636 /// use wasm_bindgen::prelude::*;
637 ///
638 /// // Create an non-`Copy`, owned `String`.
639 /// let mut s = String::from("Hello");
640 ///
641 /// // Close over `s`. Since `f` returns `s`, it is `FnOnce` and can only be
642 /// // called once. If it was called a second time, it wouldn't have any `s`
643 /// // to work with anymore!
644 /// let f = move || {
645 /// s += ", World!";
646 /// s
647 /// };
648 ///
649 /// // Create a `Closure` from `f`. Note that the `Closure`'s type parameter
650 /// // is `FnMut`, even though `f` is `FnOnce`.
651 /// let closure: Closure<dyn FnMut() -> String> = Closure::once(f);
652 /// ```
653 ///
654 /// Note: the `A` and `R` type parameters are here just for backward compat
655 /// and will be removed in the future.
656 pub fn once<F, A, R>(fn_once: F) -> Self
657 where
658 F: WasmClosureFnOnce<T, A, R> + MaybeUnwindSafe,
659 {
660 Closure::_wrap(fn_once.into_fn_mut(), true)
661 }
662
663 /// Create a `Closure` from a function that can only be called once.
664 ///
665 /// Unlike `once`, this version does NOT catch panics and does NOT require `UnwindSafe`.
666 /// If the closure panics, the process will abort.
667 ///
668 /// Use this when:
669 /// - Your closure captures types that aren't `UnwindSafe` (like `Rc<Cell<T>>`)
670 /// - You don't need panic catching across the JS boundary
671 /// - You prefer abort-on-panic behavior
672 ///
673 /// Since we have no way of enforcing that JS cannot attempt to call this
674 /// `FnOnce(A...) -> R` more than once, this produces a `Closure<dyn FnMut(A...)
675 /// -> R>` that will dynamically throw a JavaScript error if called more
676 /// than once.
677 ///
678 /// **Note: Not unwind safe. Prefer [`once`](Self::once) or `once` with
679 /// [`AssertUnwindSafe`](core::panic::AssertUnwindSafe) when possible.**
680 ///
681 /// Note: the `A` and `R` type parameters are here just for backward compat
682 /// and will be removed in the future.
683 pub fn once_aborting<F, A, R>(fn_once: F) -> Self
684 where
685 F: WasmClosureFnOnceAbort<T, A, R>,
686 {
687 Closure::_wrap(fn_once.into_fn_mut(), false)
688 }
689
690 /// Create a `Closure` from a function that can only be called once,
691 /// with panic unwind support.
692 ///
693 /// **Safety: Unwind safety is assumed when using this function, like using
694 /// `AssertUnwindSafe(...)`, this must be verified explicitly.**
695 ///
696 /// Use this when:
697 /// - Your closure captures types that aren't `UnwindSafe` (like `Rc<Cell<T>>`)
698 /// - You still want panics to be caught and converted to JS exceptions
699 ///
700 /// Since we have no way of enforcing that JS cannot attempt to call this
701 /// `FnOnce(A...) -> R` more than once, this produces a `Closure<dyn FnMut(A...)
702 /// -> R>` that will dynamically throw a JavaScript error if called more
703 /// than once.
704 ///
705 /// Note: the `A` and `R` type parameters are here just for backward compat
706 /// and will be removed in the future.
707 pub fn once_assert_unwind_safe<F, A, R>(fn_once: F) -> Self
708 where
709 F: WasmClosureFnOnceAbort<T, A, R>,
710 {
711 Closure::_wrap(fn_once.into_fn_mut(), true)
712 }
713
714 // TODO: Update once closures to be generated on construction as once
715 // closures instead of using wrap(). Then we can share the same into_js()
716 // function between all closures, and deprecate this method.
717 /// Convert a `FnOnce(A...) -> R` into a JavaScript `Function` object.
718 ///
719 /// If the JavaScript function is invoked more than once, it will throw an
720 /// exception.
721 ///
722 /// Unlike `Closure::once`, this does *not* return a `Closure` that can be
723 /// dropped before the function is invoked to deallocate the closure. The
724 /// only way the `FnOnce` is deallocated is by calling the JavaScript
725 /// function. If the JavaScript function is never called then the `FnOnce`
726 /// and everything it closes over will leak.
727 ///
728 /// ```rust,ignore
729 /// use wasm_bindgen::{prelude::*, JsCast};
730 ///
731 /// let f = Closure::once_into_js(move || {
732 /// // ...
733 /// });
734 ///
735 /// assert!(f.is_instance_of::<js_sys::Function>());
736 /// ```
737 ///
738 /// Note: the `A` and `R` type parameters are here just for backward compat
739 /// and will be removed in the future.
740 pub fn once_into_js<F, A, R>(fn_once: F) -> JsValue
741 where
742 F: WasmClosureFnOnce<T, A, R> + MaybeUnwindSafe,
743 {
744 fn_once.into_js_function()
745 }
746}
747
748/// A closure wrapper for immediate/synchronous callbacks with unwind safety.
749///
750/// `ImmediateClosure` wraps a borrowed closure for use in synchronous JS callbacks
751/// like `Array.forEach`, `Array.map`, etc. The JS side receives the closure,
752/// calls it immediately, and discards it - no GC tracking is needed.
753///
754/// Panics are caught and converted to JavaScript exceptions (when built with
755/// `panic=unwind`). No `UnwindSafe` bounds are required - the closure is wrapped
756/// internally.
757///
758/// # Unwind Safety
759///
760/// `ImmediateClosure` provides unwind safety by catching panics and converting them
761/// to JavaScript exceptions.
762///
763/// # Example
764///
765/// ```ignore
766/// use wasm_bindgen::prelude::*;
767///
768/// #[wasm_bindgen]
769/// extern "C" {
770/// fn forEach<'a>(cb: ImmediateClosure<'a, dyn FnMut(JsValue) + 'a>);
771/// }
772///
773/// let mut sum = 0;
774/// forEach(ImmediateClosure::new_mut(&mut |val: JsValue| {
775/// sum += val.as_f64().unwrap() as i32;
776/// }));
777/// // sum is now updated
778/// ```
779///
780/// **Note:** To ensure borrowed lifetimes are correctly inferred, make sure to pass
781/// the lifetime to both the ImmediateClosure lifetime parameter AND its dyn FnMut
782/// parameter, as in the example above.
783pub struct ImmediateClosure<'a, T: ?Sized> {
784 data: WasmSlice,
785 unwind_safe: bool,
786 _marker: PhantomData<&'a mut T>,
787}
788
789impl<'a, T: ?Sized + WasmClosure> ImmediateClosure<'a, T> {
790 /// Creates an immediate closure from an immutable borrow of a `Fn` closure.
791 ///
792 /// Immutable closures (`Fn`) are preferred because they are more likely to satisfy `UnwindSafe`
793 /// automatically. Use [`new_mut`](Self::new_mut) when you need to mutate captured state.
794 ///
795 /// Note that immutable closures can be `upcast()` to mutable closures on the JS boundary
796 /// when required by function signatures.
797 ///
798 /// Panics are caught as JS exceptions when building with panic=unwind.
799 /// The resulting closure can be upcasted to `FnMut` using [`upcast_ref`](crate::Upcast::upcast_ref).
800 ///
801 /// # Example
802 ///
803 /// ```ignore
804 /// let data = vec![1, 2, 3];
805 /// let closure = ImmediateClosure::new(&|| {
806 /// println!("data len: {}", data.len());
807 /// });
808 /// call_closure(&closure);
809 /// ```
810 pub fn new<F>(f: &'a F) -> ImmediateClosure<'a, F::WithLifetime>
811 where
812 F: IntoWasmClosureRef<'a, T> + ?Sized + MaybeUnwindSafe,
813 {
814 let t: &T = f.unsize_closure_ref();
815 let (ptr, len): (u32, u32) = unsafe { mem::transmute_copy(&t) };
816 ImmediateClosure {
817 data: WasmSlice { ptr, len },
818 unwind_safe: true,
819 _marker: PhantomData,
820 }
821 }
822
823 /// Like [`new`](Self::new), but does not catch panics.
824 ///
825 /// This variant enables type inference from the expected type, since it
826 /// takes the dyn type directly.
827 ///
828 /// **Note: Not unwind safe. Prefer [`new`](Self::new) or
829 /// [`new_assert_unwind_safe`](Self::new_assert_unwind_safe) when possible.**
830 pub fn new_aborting(f: &'a T) -> Self {
831 ImmediateClosure {
832 data: T::to_wasm_slice(f),
833 unwind_safe: false,
834 _marker: PhantomData,
835 }
836 }
837
838 /// Like [`new_aborting`](Self::new_aborting), but catches panics and converts them to JS exceptions.
839 ///
840 /// **Safety: Unwind safety is assumed when using this function, like using
841 /// `AssertUnwindSafe(...)`, this must be verified explicitly.**
842 ///
843 /// # Example
844 ///
845 /// ```ignore
846 /// let data = vec![1, 2, 3];
847 /// // Type is inferred from context
848 /// let closure: ImmediateClosure<dyn Fn()> = ImmediateClosure::new_assert_unwind_safe(&|| {
849 /// println!("data len: {}", data.len());
850 /// });
851 /// ```
852 pub fn new_assert_unwind_safe(f: &'a T) -> Self {
853 ImmediateClosure {
854 data: T::to_wasm_slice(f),
855 unwind_safe: true,
856 _marker: PhantomData,
857 }
858 }
859
860 /// Creates an immediate closure from a mutable borrow of a `FnMut` closure.
861 ///
862 /// Use this for closures that need to mutate captured state. For closures that
863 /// don't need mutation, [`new`](Self::new) creates an immutable `Fn` closure
864 /// that is more likely to satisfy `UnwindSafe` automatically.
865 ///
866 /// Panics are caught as JS exceptions when building with panic=unwind.
867 ///
868 /// # Example
869 ///
870 /// ```ignore
871 /// let mut count = 0;
872 /// let closure = ImmediateClosure::new_mut(&mut || { count += 1; });
873 /// call_closure(&closure);
874 /// assert_eq!(count, 1);
875 /// ```
876 pub fn new_mut<F>(f: &'a mut F) -> ImmediateClosure<'a, F::WithLifetime>
877 where
878 F: IntoWasmClosureRefMut<'a, T> + ?Sized + MaybeUnwindSafe,
879 {
880 let t: &mut T = f.unsize_closure_ref();
881 let (ptr, len): (u32, u32) = unsafe { mem::transmute_copy(&t) };
882 ImmediateClosure {
883 data: WasmSlice { ptr, len },
884 unwind_safe: true,
885 _marker: PhantomData,
886 }
887 }
888
889 /// Like [`new_mut`](Self::new_mut), but does not catch panics.
890 ///
891 /// This variant enables type inference from the expected type, since it
892 /// takes the dyn type directly.
893 ///
894 /// **Note: Not unwind safe. Prefer [`new_mut`](Self::new_mut) or
895 /// [`new_mut_assert_unwind_safe`](Self::new_mut_assert_unwind_safe) when possible.**
896 pub fn new_mut_aborting(f: &'a mut T) -> Self {
897 ImmediateClosure {
898 data: T::to_wasm_slice(f),
899 unwind_safe: false,
900 _marker: PhantomData,
901 }
902 }
903
904 /// Like [`new_mut_aborting`](Self::new_mut_aborting), but catches panics and converts them to JS exceptions.
905 ///
906 /// **Safety: Unwind safety is assumed when using this function, like using
907 /// `AssertUnwindSafe(...)`, this must be verified explicitly.**
908 ///
909 /// # Example
910 ///
911 /// ```ignore
912 /// let mut count = 0;
913 /// // Type of `x` is inferred from context
914 /// let closure: ImmediateClosure<dyn FnMut(u32)> = ImmediateClosure::new_mut_assert_unwind_safe(&mut |x| {
915 /// count += x;
916 /// });
917 /// ```
918 pub fn new_mut_assert_unwind_safe(f: &'a mut T) -> Self {
919 ImmediateClosure {
920 data: T::to_wasm_slice(f),
921 unwind_safe: true,
922 _marker: PhantomData,
923 }
924 }
925
926 /// Converts this closure to a mutable `FnMut` closure.
927 ///
928 /// This is safe because every `Fn` can be called through a `FnMut` interface.
929 /// The fat pointer representation is compatible—`dyn Fn` can be safely
930 /// reinterpreted as `dyn FnMut`.
931 ///
932 /// Note: Unlike `ScopedClosure::as_mut`, this only supports the Fn→FnMut conversion
933 /// with the same argument and return types. `ImmediateClosure` stores a Rust fat
934 /// pointer directly, so argument/return type variance is not possible.
935 ///
936 /// # Example
937 ///
938 /// ```ignore
939 /// use wasm_bindgen::prelude::*;
940 ///
941 /// #[wasm_bindgen]
942 /// extern "C" {
943 /// fn needs_fnmut(cb: ImmediateClosure<dyn FnMut(u32)>);
944 /// }
945 ///
946 /// let func: &dyn Fn(u32) = &|x| println!("{}", x);
947 /// let closure: ImmediateClosure<dyn Fn(u32)> = ImmediateClosure::new_assert_unwind_safe(func);
948 /// needs_fnmut(closure.as_mut());
949 /// ```
950 pub fn as_mut(self) -> ImmediateClosure<'a, T::AsMut> {
951 // SAFETY: ImmediateClosure stores a WasmSlice (fat pointer data) and metadata.
952 // The type parameter T is phantom data. A dyn Fn fat pointer can be safely
953 // reinterpreted as dyn FnMut since Fn is a supertrait of FnMut.
954 ImmediateClosure {
955 data: self.data,
956 unwind_safe: self.unwind_safe,
957 _marker: PhantomData,
958 }
959 }
960}
961
962impl<T: ?Sized> fmt::Debug for ImmediateClosure<'_, T> {
963 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
964 f.debug_struct("ImmediateClosure").finish_non_exhaustive()
965 }
966}
967
968/// A trait for converting an `FnOnce(A...) -> R` into a `FnMut(A...) -> R` that
969/// will throw if ever called more than once.
970#[doc(hidden)]
971pub trait WasmClosureFnOnce<FnMut: ?Sized, A, R>: 'static {
972 fn into_fn_mut(self) -> Box<FnMut>;
973
974 fn into_js_function(self) -> JsValue;
975}
976
977/// A trait for converting an `FnOnce(A...) -> R` into a `FnMut(A...) -> R` that
978/// will throw if ever called more than once. This variant does not require UnwindSafe.
979#[doc(hidden)]
980pub trait WasmClosureFnOnceAbort<FnMut: ?Sized, A, R>: 'static {
981 fn into_fn_mut(self) -> Box<FnMut>;
982
983 fn into_js_function(self) -> JsValue;
984}
985
986impl<T: ?Sized> AsRef<JsValue> for ScopedClosure<'_, T> {
987 fn as_ref(&self) -> &JsValue {
988 &self.js
989 }
990}
991
992/// Internal representation of an owned closure that we send to JS.
993/// This is used when panic=abort or when panic=unwind but without the unwind_safe flag.
994#[repr(transparent)]
995struct OwnedClosure<T: ?Sized>(Box<T>);
996
997/// Internal representation of an owned closure with unwind safety flag. Used
998/// when panic=unwind to pass both the closure and the unwind_safe flag to JS.
999#[cfg(all(feature = "std", target_arch = "wasm32", panic = "unwind"))]
1000struct OwnedClosureUnwind<T: ?Sized> {
1001 data: Box<T>,
1002 unwind_safe: bool,
1003}
1004
1005struct BorrowedClosure<T: ?Sized> {
1006 data: WasmSlice,
1007 unwind_safe: bool,
1008 _marker: PhantomData<T>,
1009}
1010
1011unsafe extern "C" fn destroy<T: ?Sized>(a: usize, mut b: usize) {
1012 if a == 0 {
1013 return;
1014 }
1015 // Mask out unwind_safe flag
1016 b &= !0x80000000;
1017 drop(mem::transmute_copy::<_, Box<T>>(&(a, b)));
1018}
1019
1020impl<T> WasmDescribe for OwnedClosure<T>
1021where
1022 T: WasmClosure + ?Sized,
1023{
1024 #[cfg_attr(wasm_bindgen_unstable_test_coverage, coverage(off))]
1025 fn describe() {
1026 inform(CLOSURE);
1027 inform(destroy::<T> as *const () as usize as u32);
1028 inform(T::IS_MUT as u32);
1029 T::describe();
1030 }
1031}
1032
1033impl<T> WasmDescribe for BorrowedClosure<T>
1034where
1035 T: WasmClosure + ?Sized,
1036{
1037 #[cfg_attr(wasm_bindgen_unstable_test_coverage, coverage(off))]
1038 fn describe() {
1039 inform(CLOSURE);
1040 inform(0);
1041 inform(T::IS_MUT as u32);
1042 T::describe();
1043 }
1044}
1045
1046impl<T> IntoWasmAbi for OwnedClosure<T>
1047where
1048 T: WasmClosure + ?Sized,
1049{
1050 type Abi = WasmSlice;
1051
1052 fn into_abi(self) -> WasmSlice {
1053 let (a, b): (usize, usize) = unsafe { mem::transmute_copy(&ManuallyDrop::new(self)) };
1054 WasmSlice {
1055 ptr: a as u32,
1056 len: b as u32,
1057 }
1058 }
1059}
1060
1061impl<T> IntoWasmAbi for BorrowedClosure<T>
1062where
1063 T: WasmClosure + ?Sized,
1064{
1065 type Abi = WasmSlice;
1066 fn into_abi(self) -> WasmSlice {
1067 let WasmSlice { ptr, mut len } = self.data;
1068 if self.unwind_safe {
1069 len |= 0x80000000;
1070 }
1071 WasmSlice { ptr, len }
1072 }
1073}
1074
1075#[cfg(all(feature = "std", target_arch = "wasm32", panic = "unwind"))]
1076impl<T> WasmDescribe for OwnedClosureUnwind<T>
1077where
1078 T: WasmClosure + ?Sized,
1079{
1080 #[cfg_attr(wasm_bindgen_unstable_test_coverage, coverage(off))]
1081 fn describe() {
1082 // Delegate to the inner closure's descriptor - type info is the same
1083 OwnedClosure::<T>::describe();
1084 }
1085}
1086
1087#[cfg(all(feature = "std", target_arch = "wasm32", panic = "unwind"))]
1088impl<T> IntoWasmAbi for OwnedClosureUnwind<T>
1089where
1090 T: WasmClosure + ?Sized,
1091{
1092 type Abi = WasmSlice;
1093
1094 fn into_abi(self) -> WasmSlice {
1095 let (a, b): (usize, usize) = unsafe { mem::transmute_copy(&ManuallyDrop::new(self.data)) };
1096 // Pack unwind_safe into most significant bit (bit 31) of vtable
1097 let b_with_flag = if self.unwind_safe {
1098 (b as u32) | 0x80000000
1099 } else {
1100 b as u32
1101 };
1102 WasmSlice {
1103 ptr: a as u32,
1104 len: b_with_flag,
1105 }
1106 }
1107}
1108
1109impl<T> WasmDescribe for ScopedClosure<'_, T>
1110where
1111 T: WasmClosure + ?Sized,
1112{
1113 #[cfg_attr(wasm_bindgen_unstable_test_coverage, coverage(off))]
1114 fn describe() {
1115 inform(EXTERNREF);
1116 }
1117}
1118
1119// `ScopedClosure` can be passed by reference to imports (for any lifetime).
1120impl<T> IntoWasmAbi for &ScopedClosure<'_, T>
1121where
1122 T: WasmClosure + ?Sized,
1123{
1124 type Abi = u32;
1125
1126 fn into_abi(self) -> u32 {
1127 (&self.js).into_abi()
1128 }
1129}
1130
1131impl<T> OptionIntoWasmAbi for &ScopedClosure<'_, T>
1132where
1133 T: WasmClosure + ?Sized,
1134{
1135 fn none() -> Self::Abi {
1136 0
1137 }
1138}
1139
1140/// `'static` closures can be passed by value to JS, transferring ownership.
1141///
1142/// This is useful for one-shot callbacks where you want JS to own the closure.
1143/// The closure will be cleaned up by JS GC (if weak references are supported)
1144/// or will leak (if weak references are not supported).
1145///
1146/// # Example
1147///
1148/// ```ignore
1149/// #[wasm_bindgen]
1150/// extern "C" {
1151/// fn set_one_shot_callback(cb: Closure<dyn FnMut()>);
1152/// }
1153///
1154/// let cb = Closure::new(|| { /* ... */ });
1155/// set_one_shot_callback(cb); // Ownership transferred to JS
1156/// // No need to store or forget the closure
1157/// ```
1158impl<T> IntoWasmAbi for ScopedClosure<'static, T>
1159where
1160 T: WasmClosure + ?Sized,
1161{
1162 type Abi = u32;
1163
1164 fn into_abi(self) -> u32 {
1165 let idx = self.js.idx;
1166 mem::forget(self);
1167 idx
1168 }
1169}
1170
1171impl<T> OptionIntoWasmAbi for ScopedClosure<'static, T>
1172where
1173 T: WasmClosure + ?Sized,
1174{
1175 fn none() -> Self::Abi {
1176 0
1177 }
1178}
1179
1180impl<T> WasmDescribe for ImmediateClosure<'_, T>
1181where
1182 T: WasmClosure + ?Sized,
1183{
1184 #[cfg_attr(wasm_bindgen_unstable_test_coverage, coverage(off))]
1185 fn describe() {
1186 // For FnMut closures, wrap with REFMUT so the CLI generates
1187 // a reentrancy guard in JS. For Fn closures, emit bare FUNCTION.
1188 if T::IS_MUT {
1189 inform(REFMUT);
1190 }
1191 T::describe();
1192 }
1193}
1194
1195impl<T> IntoWasmAbi for ImmediateClosure<'_, T>
1196where
1197 T: WasmClosure + ?Sized,
1198{
1199 type Abi = WasmSlice;
1200
1201 fn into_abi(self) -> WasmSlice {
1202 let WasmSlice { ptr, len } = self.data;
1203 let len_with_flag = if self.unwind_safe {
1204 len | 0x80000000
1205 } else {
1206 len
1207 };
1208 WasmSlice {
1209 ptr,
1210 len: len_with_flag,
1211 }
1212 }
1213}
1214
1215impl<T> OptionIntoWasmAbi for ImmediateClosure<'_, T>
1216where
1217 T: WasmClosure + ?Sized,
1218{
1219 fn none() -> WasmSlice {
1220 WasmSlice { ptr: 0, len: 0 }
1221 }
1222}
1223
1224fn _check() {
1225 fn _assert<T: IntoWasmAbi>() {}
1226 // ScopedClosure by reference (any lifetime)
1227 _assert::<&ScopedClosure<dyn Fn()>>();
1228 _assert::<&ScopedClosure<dyn Fn(String)>>();
1229 _assert::<&ScopedClosure<dyn Fn() -> String>>();
1230 _assert::<&ScopedClosure<dyn FnMut()>>();
1231 _assert::<&ScopedClosure<dyn FnMut(String)>>();
1232 _assert::<&ScopedClosure<dyn FnMut() -> String>>();
1233 // ScopedClosure by value (only 'static)
1234 _assert::<ScopedClosure<'static, dyn Fn()>>();
1235 _assert::<ScopedClosure<'static, dyn FnMut()>>();
1236 _assert::<Closure<dyn Fn()>>();
1237 _assert::<Closure<dyn FnMut()>>();
1238 // ImmediateClosure by value
1239 _assert::<ImmediateClosure<dyn Fn()>>();
1240 _assert::<ImmediateClosure<dyn Fn(String)>>();
1241 _assert::<ImmediateClosure<dyn Fn() -> String>>();
1242 _assert::<ImmediateClosure<dyn FnMut()>>();
1243 _assert::<ImmediateClosure<dyn FnMut(String)>>();
1244 _assert::<ImmediateClosure<dyn FnMut() -> String>>();
1245}
1246
1247impl<T> fmt::Debug for ScopedClosure<'_, T>
1248where
1249 T: ?Sized,
1250{
1251 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1252 write!(f, "Closure {{ ... }}")
1253 }
1254}
1255
1256/// An internal trait for the `Closure` type.
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 unsafe trait WasmClosure: WasmDescribe {
1262 const IS_MUT: bool;
1263 /// The mutable version of this closure type.
1264 /// For `dyn Fn(...) -> R` this is `dyn FnMut(...) -> R`.
1265 /// For `dyn FnMut(...) -> R` this is itself.
1266 type AsMut: ?Sized;
1267 fn to_wasm_slice(r: &Self) -> WasmSlice;
1268}
1269
1270unsafe impl<T: WasmClosure> WasmClosure for AssertUnwindSafe<T> {
1271 const IS_MUT: bool = T::IS_MUT;
1272 type AsMut = T::AsMut;
1273 fn to_wasm_slice(r: &Self) -> WasmSlice {
1274 let (ptr, len): (u32, u32) = unsafe { mem::transmute_copy(&r) };
1275 WasmSlice { ptr, len }
1276 }
1277}
1278
1279/// An internal trait for the `Closure` type.
1280///
1281/// This trait is not stable and it's not recommended to use this in bounds or
1282/// implement yourself.
1283#[doc(hidden)]
1284pub trait IntoWasmClosure<T: ?Sized> {
1285 fn unsize(self: Box<Self>) -> Box<T>;
1286}
1287
1288impl<T: ?Sized + WasmClosure> IntoWasmClosure<T> for T {
1289 fn unsize(self: Box<Self>) -> Box<T> {
1290 self
1291 }
1292}
1293
1294/// Trait for converting a reference to a closure into a trait object reference.
1295///
1296/// This trait is not stable and it's not recommended to use this in bounds or
1297/// implement yourself.
1298#[doc(hidden)]
1299pub trait IntoWasmClosureRef<'a, T: ?Sized> {
1300 /// The `'static` version of `T`. For example, if `T` is `dyn Fn() + 'a`,
1301 /// then `Static` is `dyn Fn()` (implicitly `'static`).
1302 type Static: ?Sized + WasmClosure;
1303 type WithLifetime: ?Sized + WasmClosure + 'a;
1304 fn unsize_closure_ref(&self) -> &T;
1305}
1306
1307/// Trait for converting a mutable reference to a closure into a trait object reference.
1308///
1309/// This trait is not stable and it's not recommended to use this in bounds or
1310/// implement yourself.
1311#[doc(hidden)]
1312pub trait IntoWasmClosureRefMut<'a, T: ?Sized> {
1313 /// The `'static` version of `T`. For example, if `T` is `dyn FnMut() + 'a`,
1314 /// then `Static` is `dyn FnMut()` (implicitly `'static`).
1315 type Static: ?Sized + WasmClosure;
1316 type WithLifetime: ?Sized + WasmClosure + 'a;
1317 fn unsize_closure_ref(&mut self) -> &mut T;
1318}
1319
1320// Blanket impl for AssertUnwindSafe - delegates to inner type
1321impl<'a, T: ?Sized, F> IntoWasmClosureRef<'a, T> for AssertUnwindSafe<F>
1322where
1323 F: IntoWasmClosureRef<'a, T>,
1324{
1325 type Static = F::Static;
1326 type WithLifetime = F::WithLifetime;
1327 fn unsize_closure_ref(&self) -> &T {
1328 self.0.unsize_closure_ref()
1329 }
1330}
1331
1332impl<'a, T: ?Sized, F> IntoWasmClosureRefMut<'a, T> for AssertUnwindSafe<F>
1333where
1334 F: IntoWasmClosureRefMut<'a, T>,
1335{
1336 type Static = F::Static;
1337 type WithLifetime = F::WithLifetime;
1338 fn unsize_closure_ref(&mut self) -> &mut T {
1339 self.0.unsize_closure_ref()
1340 }
1341}
1342
1343// In ScopedClosure, the Rust closure type is the phantom type that erases,
1344// unlike ImmedateClosure which is the reverse.
1345unsafe impl<T: ?Sized + WasmClosure> ErasableGeneric for ScopedClosure<'_, T> {
1346 type Repr = ScopedClosure<'static, dyn FnMut()>;
1347}