1//! Support for long-lived closures in `wasm-bindgen`
2//!
3//! This module defines the `Closure` type which is used to pass "owned
4//! closures" from Rust to JS. Some more details can be found on the `Closure`
5//! type itself.
6
7#![allow(clippy::fn_to_numeric_cast)]
8
9use std::fmt;
10use std::mem::{self, ManuallyDrop};
11use std::prelude::v1::*;
12
13use crate::convert::*;
14use crate::describe::*;
15use crate::throw_str;
16use crate::JsValue;
17use crate::UnwrapThrowExt;
18
19/// A handle to both a closure in Rust as well as JS closure which will invoke
20/// the Rust closure.
21///
22/// A `Closure` is the primary way that a `'static` lifetime closure is
23/// transferred from Rust to JS. `Closure` currently requires that the closures
24/// it's created with have the `'static` lifetime in Rust for soundness reasons.
25///
26/// This type is a "handle" in the sense that whenever it is dropped it will
27/// invalidate the JS closure that it refers to. Any usage of the closure in JS
28/// after the `Closure` has been dropped will raise an exception. It's then up
29/// to you to arrange for `Closure` to be properly deallocate at an appropriate
30/// location in your program.
31///
32/// The type parameter on `Closure` is the type of closure that this represents.
33/// Currently this can only be the `Fn` and `FnMut` traits with up to 7
34/// arguments (and an optional return value).
35///
36/// # Examples
37///
38/// Here are a number of examples of using `Closure`.
39///
40/// ## Using the `setInterval` API
41///
42/// Sample usage of `Closure` to invoke the `setInterval` API.
43///
44/// ```rust,no_run
45/// use wasm_bindgen::prelude::*;
46///
47/// #[wasm_bindgen]
48/// extern "C" {
49/// fn setInterval(closure: &Closure<dyn FnMut()>, time: u32) -> i32;
50/// fn clearInterval(id: i32);
51///
52/// #[wasm_bindgen(js_namespace = console)]
53/// fn log(s: &str);
54/// }
55///
56/// #[wasm_bindgen]
57/// pub struct IntervalHandle {
58/// interval_id: i32,
59/// _closure: Closure<dyn FnMut()>,
60/// }
61///
62/// impl Drop for IntervalHandle {
63/// fn drop(&mut self) {
64/// clearInterval(self.interval_id);
65/// }
66/// }
67///
68/// #[wasm_bindgen]
69/// pub fn run() -> IntervalHandle {
70/// // First up we use `Closure::new` to wrap up a Rust closure and create
71/// // a JS closure.
72/// let cb = Closure::new(|| {
73/// log("interval elapsed!");
74/// });
75///
76/// // Next we pass this via reference to the `setInterval` function, and
77/// // `setInterval` gets a handle to the corresponding JS closure.
78/// let interval_id = setInterval(&cb, 1_000);
79///
80/// // If we were to drop `cb` here it would cause an exception to be raised
81/// // whenever the interval elapses. Instead we *return* our handle back to JS
82/// // so JS can decide when to cancel the interval and deallocate the closure.
83/// IntervalHandle {
84/// interval_id,
85/// _closure: cb,
86/// }
87/// }
88/// ```
89///
90/// ## Casting a `Closure` to a `js_sys::Function`
91///
92/// This is the same `setInterval` example as above, except it is using
93/// `web_sys` (which uses `js_sys::Function` for callbacks) instead of manually
94/// writing bindings to `setInterval` and other Web APIs.
95///
96/// ```rust,ignore
97/// use wasm_bindgen::JsCast;
98///
99/// #[wasm_bindgen]
100/// pub struct IntervalHandle {
101/// interval_id: i32,
102/// _closure: Closure<dyn FnMut()>,
103/// }
104///
105/// impl Drop for IntervalHandle {
106/// fn drop(&mut self) {
107/// let window = web_sys::window().unwrap();
108/// window.clear_interval_with_handle(self.interval_id);
109/// }
110/// }
111///
112/// #[wasm_bindgen]
113/// pub fn run() -> Result<IntervalHandle, JsValue> {
114/// let cb = Closure::new(|| {
115/// web_sys::console::log_1(&"interval elapsed!".into());
116/// });
117///
118/// let window = web_sys::window().unwrap();
119/// let interval_id = window.set_interval_with_callback_and_timeout_and_arguments_0(
120/// // Note this method call, which uses `as_ref()` to get a `JsValue`
121/// // from our `Closure` which is then converted to a `&Function`
122/// // using the `JsCast::unchecked_ref` function.
123/// cb.as_ref().unchecked_ref(),
124/// 1_000,
125/// )?;
126///
127/// // Same as above.
128/// Ok(IntervalHandle {
129/// interval_id,
130/// _closure: cb,
131/// })
132/// }
133/// ```
134///
135/// ## Using `FnOnce` and `Closure::once` with `requestAnimationFrame`
136///
137/// Because `requestAnimationFrame` only calls its callback once, we can use
138/// `FnOnce` and `Closure::once` with it.
139///
140/// ```rust,no_run
141/// use wasm_bindgen::prelude::*;
142///
143/// #[wasm_bindgen]
144/// extern "C" {
145/// fn requestAnimationFrame(closure: &Closure<dyn FnMut()>) -> u32;
146/// fn cancelAnimationFrame(id: u32);
147///
148/// #[wasm_bindgen(js_namespace = console)]
149/// fn log(s: &str);
150/// }
151///
152/// #[wasm_bindgen]
153/// pub struct AnimationFrameHandle {
154/// animation_id: u32,
155/// _closure: Closure<dyn FnMut()>,
156/// }
157///
158/// impl Drop for AnimationFrameHandle {
159/// fn drop(&mut self) {
160/// cancelAnimationFrame(self.animation_id);
161/// }
162/// }
163///
164/// // A type that will log a message when it is dropped.
165/// struct LogOnDrop(&'static str);
166/// impl Drop for LogOnDrop {
167/// fn drop(&mut self) {
168/// log(self.0);
169/// }
170/// }
171///
172/// #[wasm_bindgen]
173/// pub fn run() -> AnimationFrameHandle {
174/// // We are using `Closure::once` which takes a `FnOnce`, so the function
175/// // can drop and/or move things that it closes over.
176/// let fired = LogOnDrop("animation frame fired or canceled");
177/// let cb = Closure::once(move || drop(fired));
178///
179/// // Schedule the animation frame!
180/// let animation_id = requestAnimationFrame(&cb);
181///
182/// // Again, return a handle to JS, so that the closure is not dropped
183/// // immediately and JS can decide whether to cancel the animation frame.
184/// AnimationFrameHandle {
185/// animation_id,
186/// _closure: cb,
187/// }
188/// }
189/// ```
190///
191/// ## Converting `FnOnce`s directly into JavaScript Functions with `Closure::once_into_js`
192///
193/// If we don't want to allow a `FnOnce` to be eagerly dropped (maybe because we
194/// just want it to drop after it is called and don't care about cancellation)
195/// then we can use the `Closure::once_into_js` function.
196///
197/// This is the same `requestAnimationFrame` example as above, but without
198/// supporting early cancellation.
199///
200/// ```
201/// use wasm_bindgen::prelude::*;
202///
203/// #[wasm_bindgen]
204/// extern "C" {
205/// // We modify the binding to take an untyped `JsValue` since that is what
206/// // is returned by `Closure::once_into_js`.
207/// //
208/// // If we were using the `web_sys` binding for `requestAnimationFrame`,
209/// // then the call sites would cast the `JsValue` into a `&js_sys::Function`
210/// // using `f.unchecked_ref::<js_sys::Function>()`. See the `web_sys`
211/// // example above for details.
212/// fn requestAnimationFrame(callback: JsValue);
213///
214/// #[wasm_bindgen(js_namespace = console)]
215/// fn log(s: &str);
216/// }
217///
218/// // A type that will log a message when it is dropped.
219/// struct LogOnDrop(&'static str);
220/// impl Drop for LogOnDrop {
221/// fn drop(&mut self) {
222/// log(self.0);
223/// }
224/// }
225///
226/// #[wasm_bindgen]
227/// pub fn run() {
228/// // We are using `Closure::once_into_js` which takes a `FnOnce` and
229/// // converts it into a JavaScript function, which is returned as a
230/// // `JsValue`.
231/// let fired = LogOnDrop("animation frame fired");
232/// let cb = Closure::once_into_js(move || drop(fired));
233///
234/// // Schedule the animation frame!
235/// requestAnimationFrame(cb);
236///
237/// // No need to worry about whether or not we drop a `Closure`
238/// // here or return some sort of handle to JS!
239/// }
240/// ```
241pub struct Closure<T: ?Sized> {
242 js: ManuallyDrop<JsValue>,
243 data: ManuallyDrop<Box<T>>,
244}
245
246union FatPtr<T: ?Sized> {
247 ptr: *mut T,
248 fields: (usize, usize),
249}
250
251impl<T> Closure<T>
252where
253 T: ?Sized + WasmClosure,
254{
255 /// Creates a new instance of `Closure` from the provided Rust function.
256 ///
257 /// Note that the closure provided here, `F`, has a few requirements
258 /// associated with it:
259 ///
260 /// * It must implement `Fn` or `FnMut` (for `FnOnce` functions see
261 /// `Closure::once` and `Closure::once_into_js`).
262 ///
263 /// * It must be `'static`, aka no stack references (use the `move`
264 /// keyword).
265 ///
266 /// * It can have at most 7 arguments.
267 ///
268 /// * Its arguments and return values are all types that can be shared with
269 /// JS (i.e. have `#[wasm_bindgen]` annotations or are simple numbers,
270 /// etc.)
271 pub fn new<F>(t: F) -> Closure<T>
272 where
273 F: IntoWasmClosure<T> + 'static,
274 {
275 Closure::wrap(Box::new(t).unsize())
276 }
277
278 /// A more direct version of `Closure::new` which creates a `Closure` from
279 /// a `Box<dyn Fn>`/`Box<dyn FnMut>`, which is how it's kept internally.
280 pub fn wrap(mut data: Box<T>) -> Closure<T> {
281 assert_eq!(mem::size_of::<*const T>(), mem::size_of::<FatPtr<T>>());
282 let (a, b) = unsafe {
283 FatPtr {
284 ptr: &mut *data as *mut T,
285 }
286 .fields
287 };
288
289 // Here we need to create a `JsValue` with the data and `T::invoke()`
290 // function pointer. To do that we... take a few unconventional turns.
291 // In essence what happens here is this:
292 //
293 // 1. First up, below we call a function, `breaks_if_inlined`. This
294 // function, as the name implies, does not work if it's inlined.
295 // More on that in a moment.
296 // 2. This function internally calls a special import recognized by the
297 // `wasm-bindgen` CLI tool, `__wbindgen_describe_closure`. This
298 // imported symbol is similar to `__wbindgen_describe` in that it's
299 // not intended to show up in the final binary but it's an
300 // intermediate state for a `wasm-bindgen` binary.
301 // 3. The `__wbindgen_describe_closure` import is namely passed a
302 // descriptor function, monomorphized for each invocation.
303 //
304 // Most of this doesn't actually make sense to happen at runtime! The
305 // real magic happens when `wasm-bindgen` comes along and updates our
306 // generated code. When `wasm-bindgen` runs it performs a few tasks:
307 //
308 // * First, it finds all functions that call
309 // `__wbindgen_describe_closure`. These are all `breaks_if_inlined`
310 // defined below as the symbol isn't called anywhere else.
311 // * Next, `wasm-bindgen` executes the `breaks_if_inlined`
312 // monomorphized functions, passing it dummy arguments. This will
313 // execute the function just enough to invoke the special import,
314 // namely telling us about the function pointer that is the describe
315 // shim.
316 // * This knowledge is then used to actually find the descriptor in the
317 // function table which is then executed to figure out the signature
318 // of the closure.
319 // * Finally, and probably most heinously, the call to
320 // `breaks_if_inlined` is rewritten to call an otherwise globally
321 // imported function. This globally imported function will generate
322 // the `JsValue` for this closure specialized for the signature in
323 // question.
324 //
325 // Later on `wasm-gc` will clean up all the dead code and ensure that
326 // we don't actually call `__wbindgen_describe_closure` at runtime. This
327 // means we will end up not actually calling `breaks_if_inlined` in the
328 // final binary, all calls to that function should be pruned.
329 //
330 // See crates/cli-support/src/js/closures.rs for a more information
331 // about what's going on here.
332
333 extern "C" fn describe<T: WasmClosure + ?Sized>() {
334 inform(CLOSURE);
335 T::describe()
336 }
337
338 #[inline(never)]
339 unsafe fn breaks_if_inlined<T: WasmClosure + ?Sized>(a: usize, b: usize) -> u32 {
340 super::__wbindgen_describe_closure(a as u32, b as u32, describe::<T> as u32)
341 }
342
343 let idx = unsafe { breaks_if_inlined::<T>(a, b) };
344
345 Closure {
346 js: ManuallyDrop::new(JsValue::_new(idx)),
347 data: ManuallyDrop::new(data),
348 }
349 }
350
351 /// Release memory management of this closure from Rust to the JS GC.
352 ///
353 /// When a `Closure` is dropped it will release the Rust memory and
354 /// invalidate the associated JS closure, but this isn't always desired.
355 /// Some callbacks are alive for the entire duration of the program or for a
356 /// lifetime dynamically managed by the JS GC. This function can be used
357 /// to drop this `Closure` while keeping the associated JS function still
358 /// valid.
359 ///
360 /// If the platform supports weak references, the Rust memory will be
361 /// reclaimed when the JS closure is GC'd. If weak references is not
362 /// supported, this can be dangerous if this function is called many times
363 /// in an application because the memory leak will overwhelm the page
364 /// quickly and crash the wasm.
365 pub fn into_js_value(self) -> JsValue {
366 let idx = self.js.idx;
367 mem::forget(self);
368 JsValue::_new(idx)
369 }
370
371 /// Same as `into_js_value`, but doesn't return a value.
372 pub fn forget(self) {
373 drop(self.into_js_value());
374 }
375}
376
377// NB: we use a specific `T` for this `Closure<T>` impl block to avoid every
378// call site having to provide an explicit, turbo-fished type like
379// `Closure::<dyn FnOnce()>::once(...)`.
380impl Closure<dyn FnOnce()> {
381 /// Create a `Closure` from a function that can only be called once.
382 ///
383 /// Since we have no way of enforcing that JS cannot attempt to call this
384 /// `FnOne(A...) -> R` more than once, this produces a `Closure<dyn FnMut(A...)
385 /// -> R>` that will dynamically throw a JavaScript error if called more
386 /// than once.
387 ///
388 /// # Example
389 ///
390 /// ```rust,no_run
391 /// use wasm_bindgen::prelude::*;
392 ///
393 /// // Create an non-`Copy`, owned `String`.
394 /// let mut s = String::from("Hello");
395 ///
396 /// // Close over `s`. Since `f` returns `s`, it is `FnOnce` and can only be
397 /// // called once. If it was called a second time, it wouldn't have any `s`
398 /// // to work with anymore!
399 /// let f = move || {
400 /// s += ", World!";
401 /// s
402 /// };
403 ///
404 /// // Create a `Closure` from `f`. Note that the `Closure`'s type parameter
405 /// // is `FnMut`, even though `f` is `FnOnce`.
406 /// let closure: Closure<dyn FnMut() -> String> = Closure::once(f);
407 /// ```
408 pub fn once<F, A, R>(fn_once: F) -> Closure<F::FnMut>
409 where
410 F: 'static + WasmClosureFnOnce<A, R>,
411 {
412 Closure::wrap(fn_once.into_fn_mut())
413 }
414
415 /// Convert a `FnOnce(A...) -> R` into a JavaScript `Function` object.
416 ///
417 /// If the JavaScript function is invoked more than once, it will throw an
418 /// exception.
419 ///
420 /// Unlike `Closure::once`, this does *not* return a `Closure` that can be
421 /// dropped before the function is invoked to deallocate the closure. The
422 /// only way the `FnOnce` is deallocated is by calling the JavaScript
423 /// function. If the JavaScript function is never called then the `FnOnce`
424 /// and everything it closes over will leak.
425 ///
426 /// ```rust,ignore
427 /// use wasm_bindgen::{prelude::*, JsCast};
428 ///
429 /// let f = Closure::once_into_js(move || {
430 /// // ...
431 /// });
432 ///
433 /// assert!(f.is_instance_of::<js_sys::Function>());
434 /// ```
435 pub fn once_into_js<F, A, R>(fn_once: F) -> JsValue
436 where
437 F: 'static + WasmClosureFnOnce<A, R>,
438 {
439 fn_once.into_js_function()
440 }
441}
442
443/// A trait for converting an `FnOnce(A...) -> R` into a `FnMut(A...) -> R` that
444/// will throw if ever called more than once.
445#[doc(hidden)]
446pub trait WasmClosureFnOnce<A, R>: 'static {
447 type FnMut: ?Sized + 'static + WasmClosure;
448
449 fn into_fn_mut(self) -> Box<Self::FnMut>;
450
451 fn into_js_function(self) -> JsValue;
452}
453
454impl<T: ?Sized> AsRef<JsValue> for Closure<T> {
455 fn as_ref(&self) -> &JsValue {
456 &self.js
457 }
458}
459
460impl<T> WasmDescribe for Closure<T>
461where
462 T: WasmClosure + ?Sized,
463{
464 fn describe() {
465 inform(EXTERNREF);
466 }
467}
468
469// `Closure` can only be passed by reference to imports.
470impl<'a, T> IntoWasmAbi for &'a Closure<T>
471where
472 T: WasmClosure + ?Sized,
473{
474 type Abi = u32;
475
476 fn into_abi(self) -> u32 {
477 (&*self.js).into_abi()
478 }
479}
480
481impl<'a, T> OptionIntoWasmAbi for &'a Closure<T>
482where
483 T: WasmClosure + ?Sized,
484{
485 fn none() -> Self::Abi {
486 0
487 }
488}
489
490fn _check() {
491 fn _assert<T: IntoWasmAbi>() {}
492 _assert::<&Closure<dyn Fn()>>();
493 _assert::<&Closure<dyn Fn(String)>>();
494 _assert::<&Closure<dyn Fn() -> String>>();
495 _assert::<&Closure<dyn FnMut()>>();
496 _assert::<&Closure<dyn FnMut(String)>>();
497 _assert::<&Closure<dyn FnMut() -> String>>();
498}
499
500impl<T> fmt::Debug for Closure<T>
501where
502 T: ?Sized,
503{
504 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
505 write!(f, "Closure {{ ... }}")
506 }
507}
508
509impl<T> Drop for Closure<T>
510where
511 T: ?Sized,
512{
513 fn drop(&mut self) {
514 unsafe {
515 // this will implicitly drop our strong reference in addition to
516 // invalidating all future invocations of the closure
517 if super::__wbindgen_cb_drop(self.js.idx) != 0 {
518 ManuallyDrop::drop(&mut self.data);
519 }
520 }
521 }
522}
523
524/// An internal trait for the `Closure` type.
525///
526/// This trait is not stable and it's not recommended to use this in bounds or
527/// implement yourself.
528#[doc(hidden)]
529pub unsafe trait WasmClosure {
530 fn describe();
531}
532
533/// An internal trait for the `Closure` type.
534///
535/// This trait is not stable and it's not recommended to use this in bounds or
536/// implement yourself.
537#[doc(hidden)]
538pub trait IntoWasmClosure<T: ?Sized> {
539 fn unsize(self: Box<Self>) -> Box<T>;
540}
541
542// The memory safety here in these implementations below is a bit tricky. We
543// want to be able to drop the `Closure` object from within the invocation of a
544// `Closure` for cases like promises. That means that while it's running we
545// might drop the `Closure`, but that shouldn't invalidate the environment yet.
546//
547// Instead what we do is to wrap closures in `Rc` variables. The main `Closure`
548// has a strong reference count which keeps the trait object alive. Each
549// invocation of a closure then *also* clones this and gets a new reference
550// count. When the closure returns it will release the reference count.
551//
552// This means that if the main `Closure` is dropped while it's being invoked
553// then destruction is deferred until execution returns. Otherwise it'll
554// deallocate data immediately.
555
556macro_rules! doit {
557 ($(
558 ($($var:ident $arg1:ident $arg2:ident $arg3:ident $arg4:ident)*)
559 )*) => ($(
560 unsafe impl<$($var,)* R> WasmClosure for dyn Fn($($var),*) -> R + 'static
561 where $($var: FromWasmAbi + 'static,)*
562 R: ReturnWasmAbi + 'static,
563 {
564 fn describe() {
565 #[allow(non_snake_case)]
566 unsafe extern "C" fn invoke<$($var: FromWasmAbi,)* R: ReturnWasmAbi>(
567 a: usize,
568 b: usize,
569 $(
570 $arg1: <$var::Abi as WasmAbi>::Prim1,
571 $arg2: <$var::Abi as WasmAbi>::Prim2,
572 $arg3: <$var::Abi as WasmAbi>::Prim3,
573 $arg4: <$var::Abi as WasmAbi>::Prim4,
574 )*
575 ) -> WasmRet<R::Abi> {
576 if a == 0 {
577 throw_str("closure invoked after being dropped");
578 }
579 // Make sure all stack variables are converted before we
580 // convert `ret` as it may throw (for `Result`, for
581 // example)
582 let ret = {
583 let f: *const dyn Fn($($var),*) -> R =
584 FatPtr { fields: (a, b) }.ptr;
585 $(
586 let $var = <$var as FromWasmAbi>::from_abi($var::Abi::join($arg1, $arg2, $arg3, $arg4));
587 )*
588 (*f)($($var),*)
589 };
590 ret.return_abi().into()
591 }
592
593 inform(invoke::<$($var,)* R> as u32);
594
595 unsafe extern fn destroy<$($var: FromWasmAbi,)* R: ReturnWasmAbi>(
596 a: usize,
597 b: usize,
598 ) {
599 // This can be called by the JS glue in erroneous situations
600 // such as when the closure has already been destroyed. If
601 // that's the case let's not make things worse by
602 // segfaulting and/or asserting, so just ignore null
603 // pointers.
604 if a == 0 {
605 return;
606 }
607 drop(Box::from_raw(FatPtr::<dyn Fn($($var,)*) -> R> {
608 fields: (a, b)
609 }.ptr));
610 }
611 inform(destroy::<$($var,)* R> as u32);
612
613 <&Self>::describe();
614 }
615 }
616
617 unsafe impl<$($var,)* R> WasmClosure for dyn FnMut($($var),*) -> R + 'static
618 where $($var: FromWasmAbi + 'static,)*
619 R: ReturnWasmAbi + 'static,
620 {
621 fn describe() {
622 #[allow(non_snake_case)]
623 unsafe extern "C" fn invoke<$($var: FromWasmAbi,)* R: ReturnWasmAbi>(
624 a: usize,
625 b: usize,
626 $(
627 $arg1: <$var::Abi as WasmAbi>::Prim1,
628 $arg2: <$var::Abi as WasmAbi>::Prim2,
629 $arg3: <$var::Abi as WasmAbi>::Prim3,
630 $arg4: <$var::Abi as WasmAbi>::Prim4,
631 )*
632 ) -> WasmRet<R::Abi> {
633 if a == 0 {
634 throw_str("closure invoked recursively or after being dropped");
635 }
636 // Make sure all stack variables are converted before we
637 // convert `ret` as it may throw (for `Result`, for
638 // example)
639 let ret = {
640 let f: *const dyn FnMut($($var),*) -> R =
641 FatPtr { fields: (a, b) }.ptr;
642 let f = f as *mut dyn FnMut($($var),*) -> R;
643 $(
644 let $var = <$var as FromWasmAbi>::from_abi($var::Abi::join($arg1, $arg2, $arg3, $arg4));
645 )*
646 (*f)($($var),*)
647 };
648 ret.return_abi().into()
649 }
650
651 inform(invoke::<$($var,)* R> as u32);
652
653 unsafe extern fn destroy<$($var: FromWasmAbi,)* R: ReturnWasmAbi>(
654 a: usize,
655 b: usize,
656 ) {
657 // See `Fn()` above for why we simply return
658 if a == 0 {
659 return;
660 }
661 drop(Box::from_raw(FatPtr::<dyn FnMut($($var,)*) -> R> {
662 fields: (a, b)
663 }.ptr));
664 }
665 inform(destroy::<$($var,)* R> as u32);
666
667 <&mut Self>::describe();
668 }
669 }
670
671 #[allow(non_snake_case, unused_parens)]
672 impl<T, $($var,)* R> WasmClosureFnOnce<($($var),*), R> for T
673 where T: 'static + FnOnce($($var),*) -> R,
674 $($var: FromWasmAbi + 'static,)*
675 R: ReturnWasmAbi + 'static
676 {
677 type FnMut = dyn FnMut($($var),*) -> R;
678
679 fn into_fn_mut(self) -> Box<Self::FnMut> {
680 let mut me = Some(self);
681 Box::new(move |$($var),*| {
682 let me = me.take().expect_throw("FnOnce called more than once");
683 me($($var),*)
684 })
685 }
686
687 fn into_js_function(self) -> JsValue {
688 use std::rc::Rc;
689 use crate::__rt::WasmRefCell;
690
691 let mut me = Some(self);
692
693 let rc1 = Rc::new(WasmRefCell::new(None));
694 let rc2 = rc1.clone();
695
696 let closure = Closure::wrap(Box::new(move |$($var),*| {
697 // Invoke ourself and get the result.
698 let me = me.take().expect_throw("FnOnce called more than once");
699 let result = me($($var),*);
700
701 // And then drop the `Rc` holding this function's `Closure`
702 // alive.
703 debug_assert_eq!(Rc::strong_count(&rc2), 1);
704 let option_closure = rc2.borrow_mut().take();
705 debug_assert!(option_closure.is_some());
706 drop(option_closure);
707
708 result
709 }) as Box<dyn FnMut($($var),*) -> R>);
710
711 let js_val = closure.as_ref().clone();
712
713 *rc1.borrow_mut() = Some(closure);
714 debug_assert_eq!(Rc::strong_count(&rc1), 2);
715 drop(rc1);
716
717 js_val
718 }
719 }
720
721 impl<T, $($var,)* R> IntoWasmClosure<dyn FnMut($($var),*) -> R> for T
722 where T: 'static + FnMut($($var),*) -> R,
723 $($var: FromWasmAbi + 'static,)*
724 R: ReturnWasmAbi + 'static,
725 {
726 fn unsize(self: Box<Self>) -> Box<dyn FnMut($($var),*) -> R> { self }
727 }
728
729 impl<T, $($var,)* R> IntoWasmClosure<dyn Fn($($var),*) -> R> for T
730 where T: 'static + Fn($($var),*) -> R,
731 $($var: FromWasmAbi + 'static,)*
732 R: ReturnWasmAbi + 'static,
733 {
734 fn unsize(self: Box<Self>) -> Box<dyn Fn($($var),*) -> R> { self }
735 }
736 )*)
737}
738
739doit! {
740 ()
741 (A a1 a2 a3 a4)
742 (A a1 a2 a3 a4 B b1 b2 b3 b4)
743 (A a1 a2 a3 a4 B b1 b2 b3 b4 C c1 c2 c3 c4)
744 (A a1 a2 a3 a4 B b1 b2 b3 b4 C c1 c2 c3 c4 D d1 d2 d3 d4)
745 (A a1 a2 a3 a4 B b1 b2 b3 b4 C c1 c2 c3 c4 D d1 d2 d3 d4 E e1 e2 e3 e4)
746 (A a1 a2 a3 a4 B b1 b2 b3 b4 C c1 c2 c3 c4 D d1 d2 d3 d4 E e1 e2 e3 e4 F f1 f2 f3 f4)
747 (A a1 a2 a3 a4 B b1 b2 b3 b4 C c1 c2 c3 c4 D d1 d2 d3 d4 E e1 e2 e3 e4 F f1 f2 f3 f4 G g1 g2 g3 g4)
748 (A a1 a2 a3 a4 B b1 b2 b3 b4 C c1 c2 c3 c4 D d1 d2 d3 d4 E e1 e2 e3 e4 F f1 f2 f3 f4 G g1 g2 g3 g4 H h1 h2 h3 h4)
749}
750
751// Copy the above impls down here for where there's only one argument and it's a
752// reference. We could add more impls for more kinds of references, but it
753// becomes a combinatorial explosion quickly. Let's see how far we can get with
754// just this one! Maybe someone else can figure out voodoo so we don't have to
755// duplicate.
756
757unsafe impl<A, R> WasmClosure for dyn Fn(&A) -> R
758where
759 A: RefFromWasmAbi,
760 R: ReturnWasmAbi + 'static,
761{
762 fn describe() {
763 #[allow(non_snake_case)]
764 unsafe extern "C" fn invoke<A: RefFromWasmAbi, R: ReturnWasmAbi>(
765 a: usize,
766 b: usize,
767 arg1: <A::Abi as WasmAbi>::Prim1,
768 arg2: <A::Abi as WasmAbi>::Prim2,
769 arg3: <A::Abi as WasmAbi>::Prim3,
770 arg4: <A::Abi as WasmAbi>::Prim4,
771 ) -> WasmRet<R::Abi> {
772 if a == 0 {
773 throw_str("closure invoked after being dropped");
774 }
775 // Make sure all stack variables are converted before we
776 // convert `ret` as it may throw (for `Result`, for
777 // example)
778 let ret = {
779 let f: *const dyn Fn(&A) -> R = FatPtr { fields: (a, b) }.ptr;
780 let arg = <A as RefFromWasmAbi>::ref_from_abi(A::Abi::join(arg1, arg2, arg3, arg4));
781 (*f)(&*arg)
782 };
783 ret.return_abi().into()
784 }
785
786 inform(invoke::<A, R> as u32);
787
788 unsafe extern "C" fn destroy<A: RefFromWasmAbi, R: ReturnWasmAbi>(a: usize, b: usize) {
789 // See `Fn()` above for why we simply return
790 if a == 0 {
791 return;
792 }
793 drop(Box::from_raw(
794 FatPtr::<dyn Fn(&A) -> R> { fields: (a, b) }.ptr,
795 ));
796 }
797 inform(destroy::<A, R> as u32);
798
799 <&Self>::describe();
800 }
801}
802
803unsafe impl<A, R> WasmClosure for dyn FnMut(&A) -> R
804where
805 A: RefFromWasmAbi,
806 R: ReturnWasmAbi + 'static,
807{
808 fn describe() {
809 #[allow(non_snake_case)]
810 unsafe extern "C" fn invoke<A: RefFromWasmAbi, R: ReturnWasmAbi>(
811 a: usize,
812 b: usize,
813 arg1: <A::Abi as WasmAbi>::Prim1,
814 arg2: <A::Abi as WasmAbi>::Prim2,
815 arg3: <A::Abi as WasmAbi>::Prim3,
816 arg4: <A::Abi as WasmAbi>::Prim4,
817 ) -> WasmRet<R::Abi> {
818 if a == 0 {
819 throw_str("closure invoked recursively or after being dropped");
820 }
821 // Make sure all stack variables are converted before we
822 // convert `ret` as it may throw (for `Result`, for
823 // example)
824 let ret = {
825 let f: *const dyn FnMut(&A) -> R = FatPtr { fields: (a, b) }.ptr;
826 let f = f as *mut dyn FnMut(&A) -> R;
827 let arg = <A as RefFromWasmAbi>::ref_from_abi(A::Abi::join(arg1, arg2, arg3, arg4));
828 (*f)(&*arg)
829 };
830 ret.return_abi().into()
831 }
832
833 inform(invoke::<A, R> as u32);
834
835 unsafe extern "C" fn destroy<A: RefFromWasmAbi, R: ReturnWasmAbi>(a: usize, b: usize) {
836 // See `Fn()` above for why we simply return
837 if a == 0 {
838 return;
839 }
840 drop(Box::from_raw(
841 FatPtr::<dyn FnMut(&A) -> R> { fields: (a, b) }.ptr,
842 ));
843 }
844 inform(destroy::<A, R> as u32);
845
846 <&mut Self>::describe();
847 }
848}
849
850#[allow(non_snake_case)]
851impl<T, A, R> WasmClosureFnOnce<(&A,), R> for T
852where
853 T: 'static + FnOnce(&A) -> R,
854 A: RefFromWasmAbi + 'static,
855 R: ReturnWasmAbi + 'static,
856{
857 type FnMut = dyn FnMut(&A) -> R;
858
859 fn into_fn_mut(self) -> Box<Self::FnMut> {
860 let mut me = Some(self);
861 Box::new(move |arg| {
862 let me = me.take().expect_throw("FnOnce called more than once");
863 me(arg)
864 })
865 }
866
867 fn into_js_function(self) -> JsValue {
868 use crate::__rt::WasmRefCell;
869 use std::rc::Rc;
870
871 let mut me = Some(self);
872
873 let rc1 = Rc::new(WasmRefCell::new(None));
874 let rc2 = rc1.clone();
875
876 let closure = Closure::wrap(Box::new(move |arg: &A| {
877 // Invoke ourself and get the result.
878 let me = me.take().expect_throw("FnOnce called more than once");
879 let result = me(arg);
880
881 // And then drop the `Rc` holding this function's `Closure`
882 // alive.
883 debug_assert_eq!(Rc::strong_count(&rc2), 1);
884 let option_closure = rc2.borrow_mut().take();
885 debug_assert!(option_closure.is_some());
886 drop(option_closure);
887
888 result
889 }) as Box<dyn FnMut(&A) -> R>);
890
891 let js_val = closure.as_ref().clone();
892
893 *rc1.borrow_mut() = Some(closure);
894 debug_assert_eq!(Rc::strong_count(&rc1), 2);
895 drop(rc1);
896
897 js_val
898 }
899}
900