pub struct ScopedClosure<'a, T: ?Sized> { /* private fields */ }Expand description
A closure with a lifetime parameter that represents a Rust closure passed to JavaScript.
ScopedClosure<'a, T> is the unified closure type. The lifetime 'a indicates
how long the closure is valid:
-
ScopedClosure<'static, T>- An owned closure with heap-allocated data. Requires'staticcaptures. Use for long-lived closures like event listeners and timers. Created withClosure::neworScopedClosure::own. May transfer ownership to the JS GC using finalizers. -
ScopedClosure<'a, T>(non-'static) - A borrowed closure referencing stack data. Allows non-'staticcaptures. Use for immediate/synchronous callbacks. Created withScopedClosure::borrow(forFnMut) or [ScopedClosure::borrow_immutable] (forFn). Cannot transfer ownership to JS GC.
Closure<T> is currently a type alias for ScopedClosure<'static, T>. In
a future release, a lifetime argument will be added to this alias.
§Ownership Model
ScopedClosure follows the same ownership model as other wasm-bindgen types:
the JavaScript reference remains valid until the Rust value is dropped. When
dropped, the closure is invalidated and any subsequent calls from JavaScript
will throw: “closure invoked recursively or after being dropped”.
For 'static closures, you can also:
- Pass by value to transfer ownership to JS (implements
IntoWasmAbi) - Call
forget()to leak the closure (JS can use it indefinitely) - Call
into_js_value()to transfer to JS GC management
§Lifetime Safety
For borrowed closures, Rust’s borrow checker ensures that ScopedClosure cannot
be held longer than the closure’s captured data:
let mut sum = 0;
let mut f = |x: u32| { sum += x; }; // f borrows sum
let closure = ScopedClosure::borrow(&mut f); // closure borrows f
// closure cannot outlive f, and f cannot outlive sum§Examples
§Borrowed closures with ScopedClosure::borrow
Use for immediate/synchronous callbacks where JS calls the closure right away:
use wasm_bindgen::prelude::*;
#[wasm_bindgen]
extern "C" {
fn call_immediately(cb: &ScopedClosure<dyn FnMut(u32)>);
}
let mut sum = 0;
{
let mut f = |x: u32| { sum += x; };
let closure = ScopedClosure::borrow(&mut f);
call_immediately(&closure);
} // closure dropped here, JS function invalidated
assert_eq!(sum, 42);§Owned closures with Closure::new
Use for long-lived callbacks like event listeners and timers:
use wasm_bindgen::prelude::*;
#[wasm_bindgen]
extern "C" {
fn setInterval(closure: &Closure<dyn FnMut()>, time: u32) -> i32;
}
// Closure::new requires 'static, so use `move` to capture by value
let cb = Closure::new(move || {
// ...
});
setInterval(&cb, 1000);
// Must keep `cb` alive or call `cb.forget()` to transfer to JS§Transferring ownership to JS
Pass a ScopedClosure<'static, T> by value to transfer ownership:
use wasm_bindgen::prelude::*;
#[wasm_bindgen]
extern "C" {
fn set_one_shot_callback(cb: ScopedClosure<dyn FnMut()>);
}
let cb = ScopedClosure::own(|| { /* ... */ });
set_one_shot_callback(cb); // Ownership transferred, no need to storeImplementations§
Source§impl<'a, T> ScopedClosure<'a, T>where
T: ?Sized + WasmClosure,
impl<'a, T> ScopedClosure<'a, T>where
T: ?Sized + WasmClosure,
Sourcepub fn as_js_value(&self) -> &JsValue
pub fn as_js_value(&self) -> &JsValue
Obtain a &JsValue reference for this closure
Source§impl<T> ScopedClosure<'static, T>where
T: ?Sized + WasmClosure,
Methods for creating and managing 'static closures.
impl<T> ScopedClosure<'static, T>where
T: ?Sized + WasmClosure,
Methods for creating and managing 'static closures.
These methods are only available on ScopedClosure<'static, T>
not on borrowed ScopedClosure<'a, T> where 'a is not 'static.
Sourcepub fn new<F>(t: F) -> Selfwhere
F: IntoWasmClosure<T> + 'static,
pub fn new<F>(t: F) -> Selfwhere
F: IntoWasmClosure<T> + 'static,
Creates a new owned 'static closure that aborts on panic.
Alias for own_aborting.
Note: Not unwind safe. Prefer own or own with
AssertUnwindSafe when possible.
Sourcepub fn own<F>(t: F) -> Selfwhere
F: IntoWasmClosure<T> + MaybeUnwindSafe + 'static,
pub fn own<F>(t: F) -> Selfwhere
F: IntoWasmClosure<T> + MaybeUnwindSafe + 'static,
Creates a new static owned ScopedClosure<'static, T> from the provided
Rust function, with panic unwind support.
The type parameter T determines whether the closure is Fn or FnMut.
Supports unwind via its UnwindSafe bound when building with panic=unwind.
When provided to a JS function as an own value, to be managed by the JS GC.
See borrow for creating a borrowed ScopedClosure with
an associated lifetime (defaults to immutable Fn).
Sourcepub fn own_aborting<F>(t: F) -> Selfwhere
F: IntoWasmClosure<T> + 'static,
pub fn own_aborting<F>(t: F) -> Selfwhere
F: IntoWasmClosure<T> + 'static,
Creates a new owned 'static closure that aborts on panic.
Unlike own, this version does NOT catch panics and does NOT
require UnwindSafe. If the closure panics, the process will abort.
The type parameter T determines whether the closure is Fn or FnMut.
When provided to a JS function as an own value, to be managed by the JS GC.
See borrow_aborting for creating a borrowed
ScopedClosure with an associated lifetime.
Note: Not unwind safe. Prefer own or own with
AssertUnwindSafe when possible.
Sourcepub fn wrap<F>(data: Box<F>) -> Selfwhere
F: IntoWasmClosure<T> + ?Sized,
pub fn wrap<F>(data: Box<F>) -> Selfwhere
F: IntoWasmClosure<T> + ?Sized,
A more direct version of Closure::new which creates a Closure from
a Box<dyn Fn>/Box<dyn FnMut>, which is how it’s kept internally.
This version does NOT catch panics. If the closure panics, the process will abort.
Note: Not unwind safe. Prefer wrap_assert_unwind_safe
when possible.
Sourcepub fn wrap_assert_unwind_safe<F>(data: Box<F>) -> Selfwhere
F: IntoWasmClosure<T> + ?Sized,
pub fn wrap_assert_unwind_safe<F>(data: Box<F>) -> Selfwhere
F: IntoWasmClosure<T> + ?Sized,
A more direct version of Closure::new which creates a Closure from
a Box<dyn Fn>/Box<dyn FnMut>, which is how it’s kept internally.
Safety: Unwind safety is assumed when using this function, like using
AssertUnwindSafe(...), this must be verified explicitly.
This version catches panics when unwinding is available.
Sourcepub fn borrow<'a, F>(t: &'a F) -> ScopedClosure<'a, F::Static>where
F: IntoWasmClosureRef<'a, T> + MaybeUnwindSafe + ?Sized,
pub fn borrow<'a, F>(t: &'a F) -> ScopedClosure<'a, F::Static>where
F: IntoWasmClosureRef<'a, T> + MaybeUnwindSafe + ?Sized,
Creates a scoped closure by borrowing an immutable Fn closure with
panic unwind support.
This is the recommended way to pass closures to JavaScript for immediate/
synchronous use. Unlike Closure::own, this does not require the closure
to be 'static, allowing you to capture references to local variables.
Use borrow_mut when you need to mutate captured state.
The returned ScopedClosure<'a, _> has lifetime 'a from the closure
reference, which means it cannot outlive the closure or any data the
closure captures.
Supports unwind via its UnwindSafe bound when building with panic=unwind.
The resulting closure can be upcasted to FnMut using upcast_ref.
§When to use scoped closures
Use ScopedClosure::borrow or ScopedClosure::borrow_mut when:
- JavaScript will call the closure immediately and not retain it
- You need to capture non-
'staticreferences - You want automatic cleanup when the
ScopedClosureis dropped
§Closure lifetime
The JavaScript function is only valid while the ScopedClosure exists.
Once dropped, the JavaScript function is invalidated. If JavaScript retains
a reference and calls it later, it will throw: “closure invoked recursively
or after being dropped”.
Rust’s borrow checker ensures ScopedClosure cannot outlive the closure’s
captured data, preventing use-after-free bugs.
§Example
use wasm_bindgen::prelude::*;
#[wasm_bindgen]
extern "C" {
fn call_with_value(cb: &ScopedClosure<dyn Fn(u32)>, value: u32);
fn call_fnmut(cb: &ScopedClosure<dyn FnMut(u32)>, value: u32);
}
let data = vec![1, 2, 3];
let f = |x| {
println!("data len: {}, x: {}", data.len(), x);
};
let closure = ScopedClosure::borrow(&f);
call_with_value(&closure, 42);
// Can also upcast to FnMut
call_fnmut(closure.upcast_ref(), 42);Sourcepub fn borrow_assert_unwind_safe<'a, F>(
t: &'a F,
) -> ScopedClosure<'a, F::Static>where
F: IntoWasmClosureRef<'a, T> + ?Sized,
pub fn borrow_assert_unwind_safe<'a, F>(
t: &'a F,
) -> ScopedClosure<'a, F::Static>where
F: IntoWasmClosureRef<'a, T> + ?Sized,
Like borrow, but catches panics without requiring MaybeUnwindSafe.
Safety: Unwind safety is assumed when using this function, like using
AssertUnwindSafe(...), this must be verified explicitly.
Sourcepub fn borrow_aborting<'a, F>(t: &'a F) -> ScopedClosure<'a, F::Static>where
F: IntoWasmClosureRef<'a, T> + ?Sized,
pub fn borrow_aborting<'a, F>(t: &'a F) -> ScopedClosure<'a, F::Static>where
F: IntoWasmClosureRef<'a, T> + ?Sized,
Like borrow, but does not catch panics.
If the closure panics, the process will abort. This variant does not
require UnwindSafe.
Note: Not unwind safe. Prefer borrow or
borrow_assert_unwind_safe when possible.
Sourcepub fn borrow_mut<'a, F>(t: &'a mut F) -> ScopedClosure<'a, F::Static>where
F: IntoWasmClosureRefMut<'a, T> + MaybeUnwindSafe + ?Sized,
pub fn borrow_mut<'a, F>(t: &'a mut F) -> ScopedClosure<'a, F::Static>where
F: IntoWasmClosureRefMut<'a, T> + MaybeUnwindSafe + ?Sized,
Creates a scoped closure by mutably borrowing a FnMut closure.
Use this for closures that need to mutate captured state. For closures that
don’t need mutation, prefer borrow which creates an immutable
Fn closure that is more likely to satisfy UnwindSafe automatically.
See borrow for full documentation on scoped closures.
§Example
use wasm_bindgen::prelude::*;
#[wasm_bindgen]
extern "C" {
fn call_three_times(cb: &ScopedClosure<dyn FnMut(u32)>);
}
let mut sum = 0;
let closure = ScopedClosure::borrow_mut(&mut |x: u32| {
sum += x;
});
call_three_times(&closure);
// closure dropped, `sum` is accessible again
assert_eq!(sum, 6); // 1 + 2 + 3Sourcepub fn borrow_mut_assert_unwind_safe<'a, F>(
t: &'a mut F,
) -> ScopedClosure<'a, F::Static>where
F: IntoWasmClosureRefMut<'a, T> + ?Sized,
pub fn borrow_mut_assert_unwind_safe<'a, F>(
t: &'a mut F,
) -> ScopedClosure<'a, F::Static>where
F: IntoWasmClosureRefMut<'a, T> + ?Sized,
Like borrow_mut, but catches panics without requiring MaybeUnwindSafe.
Safety: Unwind safety is assumed when using this function, like using
AssertUnwindSafe(...), this must be verified explicitly.
Sourcepub fn borrow_mut_aborting<'a, F>(t: &'a mut F) -> ScopedClosure<'a, F::Static>where
F: IntoWasmClosureRefMut<'a, T> + ?Sized,
pub fn borrow_mut_aborting<'a, F>(t: &'a mut F) -> ScopedClosure<'a, F::Static>where
F: IntoWasmClosureRefMut<'a, T> + ?Sized,
Like borrow_mut, but does not catch panics.
If the closure panics, the process will abort. This variant does not
require UnwindSafe.
Note: Not unwind safe. Prefer borrow_mut or
borrow_mut_assert_unwind_safe when possible.
Source§impl<T> ScopedClosure<'static, T>where
T: ?Sized + WasmClosure,
impl<T> ScopedClosure<'static, T>where
T: ?Sized + WasmClosure,
Sourcepub fn into_js_value(self) -> JsValue
pub fn into_js_value(self) -> JsValue
Release memory management of this closure from Rust to the JS GC.
When a Closure is dropped it will release the Rust memory and
invalidate the associated JS closure, but this isn’t always desired.
Some callbacks are alive for the entire duration of the program or for a
lifetime dynamically managed by the JS GC. This function can be used
to drop this Closure while keeping the associated JS function still
valid.
If the platform supports weak references, the Rust memory will be reclaimed when the JS closure is GC’d. If weak references is not supported, this can be dangerous if this function is called many times in an application because the memory leak will overwhelm the page quickly and crash the wasm.
§Safety Note
This method is only available on 'static closures. Calling it on a
borrowed ScopedClosure would be unsound because the closure data
would become invalid when the borrow ends.
Sourcepub fn forget(self)
pub fn forget(self)
Same as mem::forget(self).
This can be used to fully relinquish closure ownership to the JS.
§Safety Note
This method is only available on 'static closures. Calling it on a borrowed
ScopedClosure would be unsound because the closure data would become invalid
when the borrow ends.
Sourcepub fn once<F, A, R>(fn_once: F) -> Selfwhere
F: WasmClosureFnOnce<T, A, R> + MaybeUnwindSafe,
pub fn once<F, A, R>(fn_once: F) -> Selfwhere
F: WasmClosureFnOnce<T, A, R> + MaybeUnwindSafe,
Create a Closure from a function that can only be called once.
Since we have no way of enforcing that JS cannot attempt to call this
FnOne(A...) -> R more than once, this produces a Closure<dyn FnMut(A...) -> R> that will dynamically throw a JavaScript error if called more
than once.
§Example
use wasm_bindgen::prelude::*;
// Create an non-`Copy`, owned `String`.
let mut s = String::from("Hello");
// Close over `s`. Since `f` returns `s`, it is `FnOnce` and can only be
// called once. If it was called a second time, it wouldn't have any `s`
// to work with anymore!
let f = move || {
s += ", World!";
s
};
// Create a `Closure` from `f`. Note that the `Closure`'s type parameter
// is `FnMut`, even though `f` is `FnOnce`.
let closure: Closure<dyn FnMut() -> String> = Closure::once(f);Note: the A and R type parameters are here just for backward compat
and will be removed in the future.
Sourcepub fn once_wrap<F, A, R>(fn_once: F) -> Selfwhere
F: WasmClosureFnOnceAbort<T, A, R>,
pub fn once_wrap<F, A, R>(fn_once: F) -> Selfwhere
F: WasmClosureFnOnceAbort<T, A, R>,
Create a Closure from a function that can only be called once.
Unlike once, this version does NOT catch panics and does NOT require UnwindSafe.
If the closure panics, the process will abort.
Use this when:
- Your closure captures types that aren’t
UnwindSafe(likeRc<Cell<T>>) - You don’t need panic catching across the JS boundary
- You prefer abort-on-panic behavior
Since we have no way of enforcing that JS cannot attempt to call this
FnOnce(A...) -> R more than once, this produces a Closure<dyn FnMut(A...) -> R> that will dynamically throw a JavaScript error if called more
than once.
Note: Not unwind safe. Prefer once or once with
AssertUnwindSafe when possible.
Note: the A and R type parameters are here just for backward compat
and will be removed in the future.
Sourcepub fn once_into_js<F, A, R>(fn_once: F) -> JsValuewhere
F: WasmClosureFnOnce<T, A, R> + MaybeUnwindSafe,
pub fn once_into_js<F, A, R>(fn_once: F) -> JsValuewhere
F: WasmClosureFnOnce<T, A, R> + MaybeUnwindSafe,
Convert a FnOnce(A...) -> R into a JavaScript Function object.
If the JavaScript function is invoked more than once, it will throw an exception.
Unlike Closure::once, this does not return a Closure that can be
dropped before the function is invoked to deallocate the closure. The
only way the FnOnce is deallocated is by calling the JavaScript
function. If the JavaScript function is never called then the FnOnce
and everything it closes over will leak.
use wasm_bindgen::{prelude::*, JsCast};
let f = Closure::once_into_js(move || {
// ...
});
assert!(f.is_instance_of::<js_sys::Function>());Note: the A and R type parameters are here just for backward compat
and will be removed in the future.
Sourcepub fn once_into_js_wrap<F, A, R>(fn_once: F) -> JsValuewhere
F: WasmClosureFnOnceAbort<T, A, R>,
pub fn once_into_js_wrap<F, A, R>(fn_once: F) -> JsValuewhere
F: WasmClosureFnOnceAbort<T, A, R>,
Convert a FnOnce(A...) -> R into a JavaScript Function object.
Unlike once_into_js, this version does NOT catch panics and does NOT require UnwindSafe.
If the closure panics, the process will abort.
If the JavaScript function is invoked more than once, it will throw an exception.
Unlike Closure::once_aborting, this does not return a Closure that can be
dropped before the function is invoked to deallocate the closure. The
only way the FnOnce is deallocated is by calling the JavaScript
function. If the JavaScript function is never called then the FnOnce
and everything it closes over will leak.
Note: Not unwind safe. Prefer once_into_js or once_into_js with
AssertUnwindSafe when possible.
Note: the A and R type parameters are here just for backward compat
and will be removed in the future.
Trait Implementations§
Source§impl<T> Debug for ScopedClosure<'_, T>where
T: ?Sized,
impl<T> Debug for ScopedClosure<'_, T>where
T: ?Sized,
Source§impl<T: ?Sized> Drop for ScopedClosure<'_, T>
impl<T: ?Sized> Drop for ScopedClosure<'_, T>
Source§impl<T: ?Sized + WasmClosure> ErasableGeneric for ScopedClosure<'_, T>
impl<T: ?Sized + WasmClosure> ErasableGeneric for ScopedClosure<'_, T>
Source§type Repr = ScopedClosure<'static, dyn FnMut()>
type Repr = ScopedClosure<'static, dyn FnMut()>
Source§impl<T> IntoWasmAbi for &ScopedClosure<'_, T>where
T: WasmClosure + ?Sized,
impl<T> IntoWasmAbi for &ScopedClosure<'_, T>where
T: WasmClosure + ?Sized,
Source§impl<T> IntoWasmAbi for ScopedClosure<'static, T>where
T: WasmClosure + ?Sized,
'static closures can be passed by value to JS, transferring ownership.
impl<T> IntoWasmAbi for ScopedClosure<'static, T>where
T: WasmClosure + ?Sized,
'static closures can be passed by value to JS, transferring ownership.
This is useful for one-shot callbacks where you want JS to own the closure. The closure will be cleaned up by JS GC (if weak references are supported) or will leak (if weak references are not supported).
§Example
#[wasm_bindgen]
extern "C" {
fn set_one_shot_callback(cb: Closure<dyn FnMut()>);
}
let cb = Closure::new(|| { /* ... */ });
set_one_shot_callback(cb); // Ownership transferred to JS
// No need to store or forget the closureSource§impl<T> OptionIntoWasmAbi for &ScopedClosure<'_, T>where
T: WasmClosure + ?Sized,
impl<T> OptionIntoWasmAbi for &ScopedClosure<'_, T>where
T: WasmClosure + ?Sized,
Source§impl<T> OptionIntoWasmAbi for ScopedClosure<'static, T>where
T: WasmClosure + ?Sized,
impl<T> OptionIntoWasmAbi for ScopedClosure<'static, T>where
T: WasmClosure + ?Sized,
impl<T: ?Sized> Unpin for ScopedClosure<'_, T>
impl<'a, 'b, T1, T2> UpcastFrom<ScopedClosure<'a, T1>> for ScopedClosure<'b, T2>
Auto Trait Implementations§
impl<'a, T> Freeze for ScopedClosure<'a, T>where
T: ?Sized,
impl<'a, T> RefUnwindSafe for ScopedClosure<'a, T>where
T: RefUnwindSafe + ?Sized,
impl<'a, T> Send for ScopedClosure<'a, T>
impl<'a, T> Sync for ScopedClosure<'a, T>
impl<'a, T> UnsafeUnpin for ScopedClosure<'a, T>where
T: ?Sized,
impl<'a, T> UnwindSafe for ScopedClosure<'a, T>where
T: UnwindSafe + ?Sized,
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
Source§impl<T> ReturnWasmAbi for Twhere
T: IntoWasmAbi,
impl<T> ReturnWasmAbi for Twhere
T: IntoWasmAbi,
Source§type Abi = <T as IntoWasmAbi>::Abi
type Abi = <T as IntoWasmAbi>::Abi
IntoWasmAbi::AbiSource§fn return_abi(self) -> <T as ReturnWasmAbi>::Abi
fn return_abi(self) -> <T as ReturnWasmAbi>::Abi
IntoWasmAbi::into_abi, except that it may throw and never
return in the case of Err.