2018-04-06 08:49:21 -07:00
|
|
|
//! Support for long-lived closures in `wasm-bindgen`
|
|
|
|
//!
|
|
|
|
//! This module defines the `Closure` type which is used to pass "owned
|
|
|
|
//! closures" from Rust to JS. Some more details can be found on the `Closure`
|
|
|
|
//! type itself.
|
|
|
|
|
2019-03-29 09:07:42 +01:00
|
|
|
use std::fmt;
|
2018-08-19 14:45:59 -07:00
|
|
|
#[cfg(feature = "nightly")]
|
2018-04-06 08:49:21 -07:00
|
|
|
use std::marker::Unsize;
|
2018-04-14 09:13:07 -07:00
|
|
|
use std::mem::{self, ManuallyDrop};
|
2018-04-19 13:08:54 -07:00
|
|
|
use std::prelude::v1::*;
|
2018-04-05 18:25:22 -07:00
|
|
|
|
2019-03-26 08:00:16 -07:00
|
|
|
use crate::convert::*;
|
|
|
|
use crate::describe::*;
|
|
|
|
use crate::throw_str;
|
|
|
|
use crate::JsValue;
|
|
|
|
use crate::UnwrapThrowExt;
|
2018-04-05 18:25:22 -07:00
|
|
|
|
2018-04-06 08:49:21 -07:00
|
|
|
/// A handle to both a closure in Rust as well as JS closure which will invoke
|
|
|
|
/// the Rust closure.
|
|
|
|
///
|
|
|
|
/// A `Closure` is the primary way that a `'static` lifetime closure is
|
|
|
|
/// transferred from Rust to JS. `Closure` currently requires that the closures
|
|
|
|
/// it's created with have the `'static` lifetime in Rust for soundness reasons.
|
|
|
|
///
|
|
|
|
/// This type is a "handle" in the sense that whenever it is dropped it will
|
|
|
|
/// invalidate the JS closure that it refers to. Any usage of the closure in JS
|
|
|
|
/// after the `Closure` has been dropped will raise an exception. It's then up
|
|
|
|
/// to you to arrange for `Closure` to be properly deallocate at an appropriate
|
|
|
|
/// location in your program.
|
|
|
|
///
|
|
|
|
/// The type parameter on `Closure` is the type of closure that this represents.
|
|
|
|
/// Currently this can only be the `Fn` and `FnMut` traits with up to 7
|
|
|
|
/// arguments (and an optional return value). The arguments/return value of the
|
|
|
|
/// trait must be numbers like `u32` for now, although this restriction may be
|
|
|
|
/// lifted in the future!
|
|
|
|
///
|
2019-02-20 10:48:01 -08:00
|
|
|
/// # Examples
|
|
|
|
///
|
|
|
|
/// Here are a number of examples of using `Closure`.
|
|
|
|
///
|
|
|
|
/// ## Using the `setInterval` API
|
2018-04-06 08:49:21 -07:00
|
|
|
///
|
2019-02-20 10:48:01 -08:00
|
|
|
/// Sample usage of `Closure` to invoke the `setInterval` API.
|
2018-09-17 14:33:22 -07:00
|
|
|
///
|
2018-04-06 08:49:21 -07:00
|
|
|
/// ```rust,no_run
|
2019-02-20 10:48:01 -08:00
|
|
|
/// use wasm_bindgen::prelude::*;
|
|
|
|
///
|
2018-04-06 08:49:21 -07:00
|
|
|
/// #[wasm_bindgen]
|
2018-11-27 12:27:00 -08:00
|
|
|
/// extern "C" {
|
2019-02-20 10:48:01 -08:00
|
|
|
/// fn setInterval(closure: &Closure<FnMut()>, time: u32) -> i32;
|
|
|
|
/// fn clearInterval(id: i32);
|
2018-04-06 08:49:21 -07:00
|
|
|
///
|
|
|
|
/// #[wasm_bindgen(js_namespace = console)]
|
|
|
|
/// fn log(s: &str);
|
|
|
|
/// }
|
|
|
|
///
|
|
|
|
/// #[wasm_bindgen]
|
2019-02-20 10:48:01 -08:00
|
|
|
/// pub struct IntervalHandle {
|
|
|
|
/// interval_id: i32,
|
|
|
|
/// _closure: Closure<FnMut()>,
|
|
|
|
/// }
|
|
|
|
///
|
|
|
|
/// impl Drop for IntervalHandle {
|
|
|
|
/// fn drop(&mut self) {
|
|
|
|
/// clearInterval(self.interval_id);
|
|
|
|
/// }
|
|
|
|
/// }
|
2018-04-06 08:49:21 -07:00
|
|
|
///
|
|
|
|
/// #[wasm_bindgen]
|
2019-02-20 10:48:01 -08:00
|
|
|
/// pub fn run() -> IntervalHandle {
|
2018-09-17 14:33:22 -07:00
|
|
|
/// // First up we use `Closure::wrap` to wrap up a Rust closure and create
|
2018-12-30 10:14:07 +01:00
|
|
|
/// // a JS closure.
|
2019-02-20 10:48:01 -08:00
|
|
|
/// let cb = Closure::wrap(Box::new(|| {
|
|
|
|
/// log("interval elapsed!");
|
2018-09-17 14:33:22 -07:00
|
|
|
/// }) as Box<FnMut()>);
|
2018-04-06 08:49:21 -07:00
|
|
|
///
|
2019-02-20 10:48:01 -08:00
|
|
|
/// // Next we pass this via reference to the `setInterval` function, and
|
|
|
|
/// // `setInterval` gets a handle to the corresponding JS closure.
|
|
|
|
/// let interval_id = setInterval(&cb, 1_000);
|
2018-04-06 08:49:21 -07:00
|
|
|
///
|
|
|
|
/// // If we were to drop `cb` here it would cause an exception to be raised
|
2019-02-20 10:48:01 -08:00
|
|
|
/// // whenever the interval elapses. Instead we *return* our handle back to JS
|
|
|
|
/// // so JS can decide when to cancel the interval and deallocate the closure.
|
|
|
|
/// IntervalHandle {
|
|
|
|
/// interval_id,
|
|
|
|
/// _closure: cb,
|
|
|
|
/// }
|
2018-04-06 08:49:21 -07:00
|
|
|
/// }
|
|
|
|
/// ```
|
2018-09-17 14:33:22 -07:00
|
|
|
///
|
2019-02-20 10:48:01 -08:00
|
|
|
/// ## Casting a `Closure` to a `js_sys::Function`
|
2018-09-17 14:33:22 -07:00
|
|
|
///
|
2019-02-20 10:48:01 -08:00
|
|
|
/// This is the same `setInterval` example as above, except it is using
|
|
|
|
/// `web_sys` (which uses `js_sys::Function` for callbacks) instead of manually
|
|
|
|
/// writing bindings to `setInterval` and other Web APIs.
|
2018-09-17 14:33:22 -07:00
|
|
|
///
|
2019-02-20 10:48:01 -08:00
|
|
|
/// ```rust,ignore
|
2018-09-17 14:33:22 -07:00
|
|
|
/// use wasm_bindgen::JsCast;
|
|
|
|
///
|
|
|
|
/// #[wasm_bindgen]
|
2019-02-20 10:48:01 -08:00
|
|
|
/// pub struct IntervalHandle {
|
|
|
|
/// interval_id: i32,
|
|
|
|
/// _closure: Closure<FnMut()>,
|
|
|
|
/// }
|
|
|
|
///
|
|
|
|
/// impl Drop for IntervalHandle {
|
|
|
|
/// fn drop(&mut self) {
|
|
|
|
/// let window = web_sys::window().unwrap();
|
|
|
|
/// window.clear_interval_with_handle(self.interval_id);
|
|
|
|
/// }
|
|
|
|
/// }
|
2018-09-17 14:33:22 -07:00
|
|
|
///
|
|
|
|
/// #[wasm_bindgen]
|
2019-02-20 10:48:01 -08:00
|
|
|
/// pub fn run() -> Result<IntervalHandle, JsValue> {
|
|
|
|
/// let cb = Closure::wrap(Box::new(|| {
|
|
|
|
/// web_sys::console::log_1(&"inverval elapsed!".into());
|
2018-09-17 14:33:22 -07:00
|
|
|
/// }) as Box<FnMut()>);
|
|
|
|
///
|
|
|
|
/// let window = web_sys::window().unwrap();
|
2019-02-20 10:48:01 -08:00
|
|
|
/// let interval_id = window.set_interval_with_callback_and_timeout_and_arguments_0(
|
2018-09-17 14:33:22 -07:00
|
|
|
/// // Note this method call, which uses `as_ref()` to get a `JsValue`
|
|
|
|
/// // from our `Closure` which is then converted to a `&Function`
|
|
|
|
/// // using the `JsCast::unchecked_ref` function.
|
2019-03-27 13:03:50 +01:00
|
|
|
/// cb.as_ref().unchecked_ref(),
|
2018-09-17 14:33:22 -07:00
|
|
|
/// 1_000,
|
2019-02-20 10:48:01 -08:00
|
|
|
/// )?;
|
2018-09-17 14:33:22 -07:00
|
|
|
///
|
2019-02-20 10:48:01 -08:00
|
|
|
/// // Same as above.
|
|
|
|
/// Ok(IntervalHandle {
|
|
|
|
/// interval_id,
|
|
|
|
/// _closure: cb,
|
|
|
|
/// })
|
|
|
|
/// }
|
|
|
|
/// ```
|
|
|
|
///
|
|
|
|
/// ## Using `FnOnce` and `Closure::once` with `requestAnimationFrame`
|
|
|
|
///
|
|
|
|
/// Because `requestAnimationFrame` only calls its callback once, we can use
|
|
|
|
/// `FnOnce` and `Closure::once` with it.
|
|
|
|
///
|
|
|
|
/// ```rust,no_run
|
|
|
|
/// use wasm_bindgen::prelude::*;
|
|
|
|
///
|
|
|
|
/// #[wasm_bindgen]
|
|
|
|
/// extern "C" {
|
|
|
|
/// fn requestAnimationFrame(closure: &Closure<FnMut()>) -> u32;
|
|
|
|
/// fn cancelAnimationFrame(id: u32);
|
|
|
|
///
|
|
|
|
/// #[wasm_bindgen(js_namespace = console)]
|
|
|
|
/// fn log(s: &str);
|
|
|
|
/// }
|
|
|
|
///
|
|
|
|
/// #[wasm_bindgen]
|
|
|
|
/// pub struct AnimationFrameHandle {
|
|
|
|
/// animation_id: u32,
|
|
|
|
/// _closure: Closure<FnMut()>,
|
|
|
|
/// }
|
|
|
|
///
|
|
|
|
/// impl Drop for AnimationFrameHandle {
|
|
|
|
/// fn drop(&mut self) {
|
|
|
|
/// cancelAnimationFrame(self.animation_id);
|
|
|
|
/// }
|
|
|
|
/// }
|
|
|
|
///
|
|
|
|
/// // A type that will log a message when it is dropped.
|
|
|
|
/// struct LogOnDrop(&'static str);
|
|
|
|
/// impl Drop for LogOnDrop {
|
|
|
|
/// fn drop(&mut self) {
|
|
|
|
/// log(self.0);
|
|
|
|
/// }
|
|
|
|
/// }
|
|
|
|
///
|
|
|
|
/// #[wasm_bindgen]
|
|
|
|
/// pub fn run() -> AnimationFrameHandle {
|
|
|
|
/// // We are using `Closure::once` which takes a `FnOnce`, so the function
|
|
|
|
/// // can drop and/or move things that it closes over.
|
|
|
|
/// let fired = LogOnDrop("animation frame fired or canceled");
|
|
|
|
/// let cb = Closure::once(move || drop(fired));
|
|
|
|
///
|
|
|
|
/// // Schedule the animation frame!
|
|
|
|
/// let animation_id = requestAnimationFrame(&cb);
|
|
|
|
///
|
|
|
|
/// // Again, return a handle to JS, so that the closure is not dropped
|
|
|
|
/// // immediately and JS can decide whether to cancel the animation frame.
|
|
|
|
/// AnimationFrameHandle {
|
|
|
|
/// animation_id,
|
|
|
|
/// _closure: cb,
|
|
|
|
/// }
|
|
|
|
/// }
|
|
|
|
/// ```
|
|
|
|
///
|
|
|
|
/// ## Converting `FnOnce`s directly into JavaScript Functions with `Closure::once_into_js`
|
|
|
|
///
|
|
|
|
/// If we don't want to allow a `FnOnce` to be eagerly dropped (maybe because we
|
|
|
|
/// just want it to drop after it is called and don't care about cancellation)
|
|
|
|
/// then we can use the `Closure::once_into_js` function.
|
|
|
|
///
|
|
|
|
/// This is the same `requestAnimationFrame` example as above, but without
|
|
|
|
/// supporting early cancellation.
|
|
|
|
///
|
|
|
|
/// ```
|
|
|
|
/// use wasm_bindgen::prelude::*;
|
|
|
|
///
|
|
|
|
/// #[wasm_bindgen]
|
|
|
|
/// extern "C" {
|
|
|
|
/// // We modify the binding to take an untyped `JsValue` since that is what
|
|
|
|
/// // is returned by `Closure::once_into_js`.
|
|
|
|
/// //
|
|
|
|
/// // If we were using the `web_sys` binding for `requestAnimationFrame`,
|
|
|
|
/// // then the call sites would cast the `JsValue` into a `&js_sys::Function`
|
|
|
|
/// // using `f.unchecked_ref::<js_sys::Function>()`. See the `web_sys`
|
|
|
|
/// // example above for details.
|
|
|
|
/// fn requestAnimationFrame(callback: JsValue);
|
|
|
|
///
|
|
|
|
/// #[wasm_bindgen(js_namespace = console)]
|
|
|
|
/// fn log(s: &str);
|
|
|
|
/// }
|
|
|
|
///
|
|
|
|
/// // A type that will log a message when it is dropped.
|
|
|
|
/// struct LogOnDrop(&'static str);
|
|
|
|
/// impl Drop for LogOnDrop {
|
|
|
|
/// fn drop(&mut self) {
|
|
|
|
/// log(self.0);
|
|
|
|
/// }
|
|
|
|
/// }
|
|
|
|
///
|
|
|
|
/// #[wasm_bindgen]
|
|
|
|
/// pub fn run() {
|
|
|
|
/// // We are using `Closure::once_into_js` which takes a `FnOnce` and
|
|
|
|
/// // converts it into a JavaScript function, which is returned as a
|
|
|
|
/// // `JsValue`.
|
|
|
|
/// let fired = LogOnDrop("animation frame fired");
|
|
|
|
/// let cb = Closure::once_into_js(move || drop(fired));
|
|
|
|
///
|
|
|
|
/// // Schedule the animation frame!
|
|
|
|
/// requestAnimationFrame(cb);
|
|
|
|
///
|
|
|
|
/// // No need to worry about whether or not we drop a `Closure`
|
|
|
|
/// // here or return some sort of handle to JS!
|
2018-09-17 14:33:22 -07:00
|
|
|
/// }
|
|
|
|
/// ```
|
2018-04-14 09:13:07 -07:00
|
|
|
pub struct Closure<T: ?Sized> {
|
2018-09-05 23:59:49 -07:00
|
|
|
js: ManuallyDrop<JsValue>,
|
2018-09-24 15:10:58 -07:00
|
|
|
data: ManuallyDrop<Box<T>>,
|
|
|
|
}
|
|
|
|
|
|
|
|
union FatPtr<T: ?Sized> {
|
|
|
|
ptr: *mut T,
|
|
|
|
fields: (usize, usize),
|
2018-04-06 08:49:21 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
impl<T> Closure<T>
|
2019-02-20 10:48:01 -08:00
|
|
|
where
|
|
|
|
T: ?Sized + WasmClosure,
|
2018-04-06 08:49:21 -07:00
|
|
|
{
|
2019-02-20 10:48:01 -08:00
|
|
|
/// A more ergonomic version of `Closure::wrap` that does the boxing and
|
|
|
|
/// cast to trait object for you.
|
2018-09-17 13:15:13 -07:00
|
|
|
///
|
|
|
|
/// *This method requires the `nightly` feature of the `wasm-bindgen` crate
|
|
|
|
/// to be enabled, meaning this is a nightly-only API. Users on stable
|
|
|
|
/// should use `Closure::wrap`.*
|
2018-08-19 14:45:59 -07:00
|
|
|
#[cfg(feature = "nightly")]
|
2018-04-06 08:49:21 -07:00
|
|
|
pub fn new<F>(t: F) -> Closure<T>
|
2019-02-20 10:48:01 -08:00
|
|
|
where
|
|
|
|
F: Unsize<T> + 'static,
|
2018-04-06 08:49:21 -07:00
|
|
|
{
|
2018-04-14 09:13:07 -07:00
|
|
|
Closure::wrap(Box::new(t) as Box<T>)
|
2018-04-06 08:49:21 -07:00
|
|
|
}
|
|
|
|
|
2019-02-20 10:48:01 -08:00
|
|
|
/// Creates a new instance of `Closure` from the provided boxed Rust
|
|
|
|
/// function.
|
2018-04-06 08:49:21 -07:00
|
|
|
///
|
2019-02-20 10:48:01 -08:00
|
|
|
/// Note that the closure provided here, `Box<T>`, has a few requirements
|
|
|
|
/// associated with it:
|
|
|
|
///
|
|
|
|
/// * It must implement `Fn` or `FnMut` (for `FnOnce` functions see
|
|
|
|
/// `Closure::once` and `Closure::once_into_js`).
|
|
|
|
///
|
|
|
|
/// * It must be `'static`, aka no stack references (use the `move`
|
|
|
|
/// keyword).
|
|
|
|
///
|
|
|
|
/// * It can have at most 7 arguments.
|
|
|
|
///
|
|
|
|
/// * Its arguments and return values are all types that can be shared with
|
|
|
|
/// JS (i.e. have `#[wasm_bindgen]` annotations or are simple numbers,
|
|
|
|
/// etc.)
|
2018-09-24 15:10:58 -07:00
|
|
|
pub fn wrap(mut data: Box<T>) -> Closure<T> {
|
|
|
|
assert_eq!(mem::size_of::<*const T>(), mem::size_of::<FatPtr<T>>());
|
|
|
|
let (a, b) = unsafe {
|
2019-02-20 10:48:01 -08:00
|
|
|
FatPtr {
|
|
|
|
ptr: &mut *data as *mut T,
|
|
|
|
}
|
|
|
|
.fields
|
2018-09-24 15:10:58 -07:00
|
|
|
};
|
2018-09-05 23:59:49 -07:00
|
|
|
|
|
|
|
// Here we need to create a `JsValue` with the data and `T::invoke()`
|
|
|
|
// function pointer. To do that we... take a few unconventional turns.
|
|
|
|
// In essence what happens here is this:
|
|
|
|
//
|
|
|
|
// 1. First up, below we call a function, `breaks_if_inlined`. This
|
|
|
|
// function, as the name implies, does not work if it's inlined.
|
|
|
|
// More on that in a moment.
|
|
|
|
// 2. This function internally calls a special import recognized by the
|
|
|
|
// `wasm-bindgen` CLI tool, `__wbindgen_describe_closure`. This
|
|
|
|
// imported symbol is similar to `__wbindgen_describe` in that it's
|
|
|
|
// not intended to show up in the final binary but it's an
|
|
|
|
// intermediate state for a `wasm-bindgen` binary.
|
|
|
|
// 3. The `__wbindgen_describe_closure` import is namely passed a
|
|
|
|
// descriptor function, monomorphized for each invocation.
|
|
|
|
//
|
|
|
|
// Most of this doesn't actually make sense to happen at runtime! The
|
|
|
|
// real magic happens when `wasm-bindgen` comes along and updates our
|
|
|
|
// generated code. When `wasm-bindgen` runs it performs a few tasks:
|
|
|
|
//
|
|
|
|
// * First, it finds all functions that call
|
|
|
|
// `__wbindgen_describe_closure`. These are all `breaks_if_inlined`
|
|
|
|
// defined below as the symbol isn't called anywhere else.
|
|
|
|
// * Next, `wasm-bindgen` executes the `breaks_if_inlined`
|
|
|
|
// monomorphized functions, passing it dummy arguments. This will
|
|
|
|
// execute the function just enough to invoke the special import,
|
|
|
|
// namely telling us about the function pointer that is the describe
|
|
|
|
// shim.
|
|
|
|
// * This knowledge is then used to actually find the descriptor in the
|
|
|
|
// function table which is then executed to figure out the signature
|
|
|
|
// of the closure.
|
|
|
|
// * Finally, and probably most heinously, the call to
|
|
|
|
// `breaks_if_inlined` is rewritten to call an otherwise globally
|
|
|
|
// imported function. This globally imported function will generate
|
|
|
|
// the `JsValue` for this closure specialized for the signature in
|
|
|
|
// question.
|
|
|
|
//
|
|
|
|
// Later on `wasm-gc` will clean up all the dead code and ensure that
|
|
|
|
// we don't actually call `__wbindgen_describe_closure` at runtime. This
|
|
|
|
// means we will end up not actually calling `breaks_if_inlined` in the
|
|
|
|
// final binary, all calls to that function should be pruned.
|
|
|
|
//
|
|
|
|
// See crates/cli-support/src/js/closures.rs for a more information
|
|
|
|
// about what's going on here.
|
|
|
|
|
2018-11-27 12:27:00 -08:00
|
|
|
extern "C" fn describe<T: WasmClosure + ?Sized>() {
|
2018-09-05 23:59:49 -07:00
|
|
|
inform(CLOSURE);
|
|
|
|
T::describe()
|
|
|
|
}
|
|
|
|
|
|
|
|
#[inline(never)]
|
2019-02-20 10:48:01 -08:00
|
|
|
unsafe fn breaks_if_inlined<T: WasmClosure + ?Sized>(a: usize, b: usize) -> u32 {
|
|
|
|
super::__wbindgen_describe_closure(a as u32, b as u32, describe::<T> as u32)
|
2018-09-05 23:59:49 -07:00
|
|
|
}
|
|
|
|
|
2019-02-20 10:48:01 -08:00
|
|
|
let idx = unsafe { breaks_if_inlined::<T>(a, b) };
|
2018-09-05 23:59:49 -07:00
|
|
|
|
2018-04-14 09:13:07 -07:00
|
|
|
Closure {
|
2018-10-10 12:50:54 -07:00
|
|
|
js: ManuallyDrop::new(JsValue::_new(idx)),
|
2018-09-24 15:10:58 -07:00
|
|
|
data: ManuallyDrop::new(data),
|
2018-04-06 08:49:21 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Leaks this `Closure` to ensure it remains valid for the duration of the
|
|
|
|
/// entire program.
|
|
|
|
///
|
|
|
|
/// > **Note**: this function will leak memory. It should be used sparingly
|
|
|
|
/// > to ensure the memory leak doesn't affect the program too much.
|
|
|
|
///
|
|
|
|
/// When a `Closure` is dropped it will invalidate the associated JS
|
|
|
|
/// closure, but this isn't always desired. Some callbacks are alive for
|
|
|
|
/// the entire duration of the program, so this can be used to conveniently
|
|
|
|
/// leak this instance of `Closure` while performing as much internal
|
|
|
|
/// cleanup as it can.
|
|
|
|
pub fn forget(self) {
|
|
|
|
unsafe {
|
2018-10-01 15:37:15 -07:00
|
|
|
super::__wbindgen_cb_forget(self.js.idx);
|
|
|
|
mem::forget(self);
|
2018-04-06 08:49:21 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-02-20 10:48:01 -08:00
|
|
|
// NB: we use a specific `T` for this `Closure<T>` impl block to avoid every
|
|
|
|
// call site having to provide an explicit, turbo-fished type like
|
|
|
|
// `Closure::<FnOnce()>::once(...)`.
|
2019-06-03 08:26:14 -07:00
|
|
|
impl Closure<dyn FnOnce()> {
|
2019-02-20 10:48:01 -08:00
|
|
|
/// 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<FnMut(A...)
|
|
|
|
/// -> R>` that will dynamically throw a JavaScript error if called more
|
|
|
|
/// than once.
|
|
|
|
///
|
|
|
|
/// # Example
|
|
|
|
///
|
|
|
|
/// ```rust,no_run
|
|
|
|
/// 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<FnMut() -> String> = Closure::once(f);
|
|
|
|
/// ```
|
|
|
|
pub fn once<F, A, R>(fn_once: F) -> Closure<F::FnMut>
|
|
|
|
where
|
|
|
|
F: 'static + WasmClosureFnOnce<A, R>,
|
|
|
|
{
|
|
|
|
Closure::wrap(fn_once.into_fn_mut())
|
|
|
|
}
|
|
|
|
|
|
|
|
/// 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.
|
|
|
|
///
|
|
|
|
/// ```rust,ignore
|
|
|
|
/// use js_sys;
|
|
|
|
/// use wasm_bindgen::{prelude::*, JsCast};
|
|
|
|
///
|
|
|
|
/// let f = Closure::once_into_js(move || {
|
|
|
|
/// // ...
|
|
|
|
/// });
|
|
|
|
///
|
|
|
|
/// assert!(f.is_instance_of::<js_sys::Function>());
|
|
|
|
/// ```
|
|
|
|
pub fn once_into_js<F, A, R>(fn_once: F) -> JsValue
|
|
|
|
where
|
|
|
|
F: 'static + WasmClosureFnOnce<A, R>,
|
|
|
|
{
|
|
|
|
fn_once.into_js_function()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// A trait for converting an `FnOnce(A...) -> R` into a `FnMut(A...) -> R` that
|
|
|
|
/// will throw if ever called more than once.
|
|
|
|
#[doc(hidden)]
|
|
|
|
pub trait WasmClosureFnOnce<A, R>: 'static {
|
|
|
|
type FnMut: ?Sized + 'static + WasmClosure;
|
|
|
|
|
|
|
|
fn into_fn_mut(self) -> Box<Self::FnMut>;
|
|
|
|
|
|
|
|
fn into_js_function(self) -> JsValue;
|
|
|
|
}
|
|
|
|
|
2018-09-06 16:18:24 -07:00
|
|
|
impl<T: ?Sized> AsRef<JsValue> for Closure<T> {
|
2018-09-05 23:59:49 -07:00
|
|
|
fn as_ref(&self) -> &JsValue {
|
|
|
|
&self.js
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
Overhaul how type information gets to the CLI
This commit is a complete overhaul of how the `#[wasm_bindgen]` macro
communicates type information to the CLI tool, and it's done in a somewhat...
unconventional fashion.
Today we've got a problem where the generated JS needs to understand the types
of each function exported or imported. This understanding is what enables it to
generate the appropriate JS wrappers and such. We want to, however, be quite
flexible and extensible in types that are supported across the boundary, which
means that internally we rely on the trait system to resolve what's what.
Communicating the type information historically was done by creating a four byte
"descriptor" and using associated type projections to communicate that to the
CLI tool. Unfortunately four bytes isn't a lot of space to cram information like
arguments to a generic function, tuple types, etc. In general this just wasn't
flexible enough and the way custom references were treated was also already a
bit of a hack.
This commit takes a radical step of creating a **descriptor function** for each
function imported/exported. The really crazy part is that the `wasm-bindgen` CLI
tool now embeds a wasm interpreter and executes these functions when the CLI
tool is invoked. By allowing arbitrary functions to get executed it's now *much*
easier to inform `wasm-bindgen` about complicated structures of types. Rest
assured though that all these descriptor functions are automatically unexported
and gc'd away, so this should not have any impact on binary sizes
A new internal trait, `WasmDescribe`, is added to represent a description of all
types, sort of like a serialization of the structure of a type that
`wasm-bindgen` can understand. This works by calling a special exported function
with a `u32` value a bunch of times. This means that when we run a descriptor we
effectively get a `Vec<u32>` in the `wasm-bindgen` CLI tool. This list of
integers can then be parsed into a rich `enum` for the JS generation to work
with.
This commit currently only retains feature parity with the previous
implementation. I hope to soon solve issues like #123, #104, and #111 with this
support.
2018-04-13 07:33:46 -07:00
|
|
|
impl<T> WasmDescribe for Closure<T>
|
2019-02-20 10:48:01 -08:00
|
|
|
where
|
|
|
|
T: WasmClosure + ?Sized,
|
Overhaul how type information gets to the CLI
This commit is a complete overhaul of how the `#[wasm_bindgen]` macro
communicates type information to the CLI tool, and it's done in a somewhat...
unconventional fashion.
Today we've got a problem where the generated JS needs to understand the types
of each function exported or imported. This understanding is what enables it to
generate the appropriate JS wrappers and such. We want to, however, be quite
flexible and extensible in types that are supported across the boundary, which
means that internally we rely on the trait system to resolve what's what.
Communicating the type information historically was done by creating a four byte
"descriptor" and using associated type projections to communicate that to the
CLI tool. Unfortunately four bytes isn't a lot of space to cram information like
arguments to a generic function, tuple types, etc. In general this just wasn't
flexible enough and the way custom references were treated was also already a
bit of a hack.
This commit takes a radical step of creating a **descriptor function** for each
function imported/exported. The really crazy part is that the `wasm-bindgen` CLI
tool now embeds a wasm interpreter and executes these functions when the CLI
tool is invoked. By allowing arbitrary functions to get executed it's now *much*
easier to inform `wasm-bindgen` about complicated structures of types. Rest
assured though that all these descriptor functions are automatically unexported
and gc'd away, so this should not have any impact on binary sizes
A new internal trait, `WasmDescribe`, is added to represent a description of all
types, sort of like a serialization of the structure of a type that
`wasm-bindgen` can understand. This works by calling a special exported function
with a `u32` value a bunch of times. This means that when we run a descriptor we
effectively get a `Vec<u32>` in the `wasm-bindgen` CLI tool. This list of
integers can then be parsed into a rich `enum` for the JS generation to work
with.
This commit currently only retains feature parity with the previous
implementation. I hope to soon solve issues like #123, #104, and #111 with this
support.
2018-04-13 07:33:46 -07:00
|
|
|
{
|
|
|
|
fn describe() {
|
2018-09-05 23:59:49 -07:00
|
|
|
inform(ANYREF);
|
Overhaul how type information gets to the CLI
This commit is a complete overhaul of how the `#[wasm_bindgen]` macro
communicates type information to the CLI tool, and it's done in a somewhat...
unconventional fashion.
Today we've got a problem where the generated JS needs to understand the types
of each function exported or imported. This understanding is what enables it to
generate the appropriate JS wrappers and such. We want to, however, be quite
flexible and extensible in types that are supported across the boundary, which
means that internally we rely on the trait system to resolve what's what.
Communicating the type information historically was done by creating a four byte
"descriptor" and using associated type projections to communicate that to the
CLI tool. Unfortunately four bytes isn't a lot of space to cram information like
arguments to a generic function, tuple types, etc. In general this just wasn't
flexible enough and the way custom references were treated was also already a
bit of a hack.
This commit takes a radical step of creating a **descriptor function** for each
function imported/exported. The really crazy part is that the `wasm-bindgen` CLI
tool now embeds a wasm interpreter and executes these functions when the CLI
tool is invoked. By allowing arbitrary functions to get executed it's now *much*
easier to inform `wasm-bindgen` about complicated structures of types. Rest
assured though that all these descriptor functions are automatically unexported
and gc'd away, so this should not have any impact on binary sizes
A new internal trait, `WasmDescribe`, is added to represent a description of all
types, sort of like a serialization of the structure of a type that
`wasm-bindgen` can understand. This works by calling a special exported function
with a `u32` value a bunch of times. This means that when we run a descriptor we
effectively get a `Vec<u32>` in the `wasm-bindgen` CLI tool. This list of
integers can then be parsed into a rich `enum` for the JS generation to work
with.
This commit currently only retains feature parity with the previous
implementation. I hope to soon solve issues like #123, #104, and #111 with this
support.
2018-04-13 07:33:46 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-04-06 08:49:21 -07:00
|
|
|
// `Closure` can only be passed by reference to imports.
|
2018-04-13 22:58:35 -07:00
|
|
|
impl<'a, T> IntoWasmAbi for &'a Closure<T>
|
2019-02-20 10:48:01 -08:00
|
|
|
where
|
|
|
|
T: WasmClosure + ?Sized,
|
2018-04-06 08:49:21 -07:00
|
|
|
{
|
|
|
|
type Abi = u32;
|
|
|
|
|
2019-06-25 05:08:50 -07:00
|
|
|
fn into_abi(self) -> u32 {
|
|
|
|
(&*self.js).into_abi()
|
2018-04-06 08:49:21 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-04-14 09:13:07 -07:00
|
|
|
fn _check() {
|
|
|
|
fn _assert<T: IntoWasmAbi>() {}
|
2019-06-03 08:26:14 -07:00
|
|
|
_assert::<&Closure<dyn Fn()>>();
|
|
|
|
_assert::<&Closure<dyn Fn(String)>>();
|
|
|
|
_assert::<&Closure<dyn Fn() -> String>>();
|
|
|
|
_assert::<&Closure<dyn FnMut()>>();
|
|
|
|
_assert::<&Closure<dyn FnMut(String)>>();
|
|
|
|
_assert::<&Closure<dyn FnMut() -> String>>();
|
2018-04-14 09:13:07 -07:00
|
|
|
}
|
|
|
|
|
2019-03-29 09:07:42 +01:00
|
|
|
impl<T> fmt::Debug for Closure<T>
|
|
|
|
where
|
|
|
|
T: ?Sized,
|
|
|
|
{
|
|
|
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
|
|
|
write!(f, "Closure {{ ... }}")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-04-06 08:49:21 -07:00
|
|
|
impl<T> Drop for Closure<T>
|
2019-02-20 10:48:01 -08:00
|
|
|
where
|
|
|
|
T: ?Sized,
|
2018-04-06 08:49:21 -07:00
|
|
|
{
|
|
|
|
fn drop(&mut self) {
|
|
|
|
unsafe {
|
2018-09-05 23:59:49 -07:00
|
|
|
// this will implicitly drop our strong reference in addition to
|
|
|
|
// invalidating all future invocations of the closure
|
2018-09-24 15:10:58 -07:00
|
|
|
if super::__wbindgen_cb_drop(self.js.idx) != 0 {
|
|
|
|
ManuallyDrop::drop(&mut self.data);
|
|
|
|
}
|
2018-04-06 08:49:21 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// An internal trait for the `Closure` type.
|
|
|
|
///
|
|
|
|
/// This trait is not stable and it's not recommended to use this in bounds or
|
|
|
|
/// implement yourself.
|
2018-06-15 09:33:19 -07:00
|
|
|
#[doc(hidden)]
|
2019-04-01 11:00:09 -07:00
|
|
|
pub unsafe trait WasmClosure {
|
2018-04-14 09:13:07 -07:00
|
|
|
fn describe();
|
2018-04-05 18:25:22 -07:00
|
|
|
}
|
|
|
|
|
2018-08-01 15:52:24 -05:00
|
|
|
// The memory safety here in these implementations below is a bit tricky. We
|
|
|
|
// want to be able to drop the `Closure` object from within the invocation of a
|
|
|
|
// `Closure` for cases like promises. That means that while it's running we
|
|
|
|
// might drop the `Closure`, but that shouldn't invalidate the environment yet.
|
|
|
|
//
|
|
|
|
// Instead what we do is to wrap closures in `Rc` variables. The main `Closure`
|
|
|
|
// has a strong reference count which keeps the trait object alive. Each
|
|
|
|
// invocation of a closure then *also* clones this and gets a new reference
|
|
|
|
// count. When the closure returns it will release the reference count.
|
|
|
|
//
|
|
|
|
// This means that if the main `Closure` is dropped while it's being invoked
|
|
|
|
// then destruction is deferred until execution returns. Otherwise it'll
|
|
|
|
// deallocate data immediately.
|
|
|
|
|
2018-04-05 18:25:22 -07:00
|
|
|
macro_rules! doit {
|
|
|
|
($(
|
2018-04-14 09:13:07 -07:00
|
|
|
($($var:ident)*)
|
2018-04-05 18:25:22 -07:00
|
|
|
)*) => ($(
|
2019-06-03 08:26:14 -07:00
|
|
|
unsafe impl<$($var,)* R> WasmClosure for dyn Fn($($var),*) -> R + 'static
|
2018-04-14 09:13:07 -07:00
|
|
|
where $($var: FromWasmAbi + 'static,)*
|
2018-09-17 18:26:45 -07:00
|
|
|
R: ReturnWasmAbi + 'static,
|
Overhaul how type information gets to the CLI
This commit is a complete overhaul of how the `#[wasm_bindgen]` macro
communicates type information to the CLI tool, and it's done in a somewhat...
unconventional fashion.
Today we've got a problem where the generated JS needs to understand the types
of each function exported or imported. This understanding is what enables it to
generate the appropriate JS wrappers and such. We want to, however, be quite
flexible and extensible in types that are supported across the boundary, which
means that internally we rely on the trait system to resolve what's what.
Communicating the type information historically was done by creating a four byte
"descriptor" and using associated type projections to communicate that to the
CLI tool. Unfortunately four bytes isn't a lot of space to cram information like
arguments to a generic function, tuple types, etc. In general this just wasn't
flexible enough and the way custom references were treated was also already a
bit of a hack.
This commit takes a radical step of creating a **descriptor function** for each
function imported/exported. The really crazy part is that the `wasm-bindgen` CLI
tool now embeds a wasm interpreter and executes these functions when the CLI
tool is invoked. By allowing arbitrary functions to get executed it's now *much*
easier to inform `wasm-bindgen` about complicated structures of types. Rest
assured though that all these descriptor functions are automatically unexported
and gc'd away, so this should not have any impact on binary sizes
A new internal trait, `WasmDescribe`, is added to represent a description of all
types, sort of like a serialization of the structure of a type that
`wasm-bindgen` can understand. This works by calling a special exported function
with a `u32` value a bunch of times. This means that when we run a descriptor we
effectively get a `Vec<u32>` in the `wasm-bindgen` CLI tool. This list of
integers can then be parsed into a rich `enum` for the JS generation to work
with.
This commit currently only retains feature parity with the previous
implementation. I hope to soon solve issues like #123, #104, and #111 with this
support.
2018-04-13 07:33:46 -07:00
|
|
|
{
|
2018-04-14 09:13:07 -07:00
|
|
|
fn describe() {
|
2018-08-01 15:52:24 -05:00
|
|
|
#[allow(non_snake_case)]
|
2018-11-27 12:27:00 -08:00
|
|
|
unsafe extern "C" fn invoke<$($var: FromWasmAbi,)* R: ReturnWasmAbi>(
|
2018-09-24 15:10:58 -07:00
|
|
|
a: usize,
|
|
|
|
b: usize,
|
2018-08-01 15:52:24 -05:00
|
|
|
$($var: <$var as FromWasmAbi>::Abi),*
|
2018-09-17 18:26:45 -07:00
|
|
|
) -> <R as ReturnWasmAbi>::Abi {
|
2018-09-24 15:10:58 -07:00
|
|
|
if a == 0 {
|
2018-09-17 18:26:45 -07:00
|
|
|
throw_str("closure invoked recursively or destroyed already");
|
2018-08-01 15:52:24 -05:00
|
|
|
}
|
2018-09-17 18:26:45 -07:00
|
|
|
// Make sure all stack variables are converted before we
|
|
|
|
// convert `ret` as it may throw (for `Result`, for
|
|
|
|
// example)
|
|
|
|
let ret = {
|
2019-06-03 08:26:14 -07:00
|
|
|
let f: *const dyn Fn($($var),*) -> R =
|
2018-09-24 15:10:58 -07:00
|
|
|
FatPtr { fields: (a, b) }.ptr;
|
2018-09-17 18:26:45 -07:00
|
|
|
$(
|
2019-06-25 05:08:50 -07:00
|
|
|
let $var = <$var as FromWasmAbi>::from_abi($var);
|
2018-09-17 18:26:45 -07:00
|
|
|
)*
|
2018-09-24 15:10:58 -07:00
|
|
|
(*f)($($var),*)
|
2018-09-17 18:26:45 -07:00
|
|
|
};
|
2019-06-25 05:08:50 -07:00
|
|
|
ret.return_abi()
|
2018-08-01 15:52:24 -05:00
|
|
|
}
|
2018-09-24 15:10:58 -07:00
|
|
|
|
2018-11-29 12:01:16 -08:00
|
|
|
inform(invoke::<$($var,)* R> as u32);
|
|
|
|
|
|
|
|
unsafe extern fn destroy<$($var: FromWasmAbi,)* R: ReturnWasmAbi>(
|
2018-09-24 15:10:58 -07:00
|
|
|
a: usize,
|
|
|
|
b: usize,
|
|
|
|
) {
|
2019-05-13 07:22:33 -07:00
|
|
|
// This can be called by the JS glue in erroneous situations
|
|
|
|
// such as when the closure has already been destroyed. If
|
|
|
|
// that's the case let's not make things worse by
|
|
|
|
// segfaulting and/or asserting, so just ignore null
|
|
|
|
// pointers.
|
|
|
|
if a == 0 {
|
|
|
|
return;
|
|
|
|
}
|
2019-06-03 08:26:14 -07:00
|
|
|
drop(Box::from_raw(FatPtr::<dyn Fn($($var,)*) -> R> {
|
2018-09-24 15:10:58 -07:00
|
|
|
fields: (a, b)
|
|
|
|
}.ptr));
|
|
|
|
}
|
2018-11-29 12:01:16 -08:00
|
|
|
inform(destroy::<$($var,)* R> as u32);
|
|
|
|
|
|
|
|
<&Self>::describe();
|
2018-09-24 15:10:58 -07:00
|
|
|
}
|
2018-04-05 18:25:22 -07:00
|
|
|
}
|
2018-08-01 15:52:24 -05:00
|
|
|
|
2019-06-03 08:26:14 -07:00
|
|
|
unsafe impl<$($var,)* R> WasmClosure for dyn FnMut($($var),*) -> R + 'static
|
2018-04-14 09:13:07 -07:00
|
|
|
where $($var: FromWasmAbi + 'static,)*
|
2018-09-17 18:26:45 -07:00
|
|
|
R: ReturnWasmAbi + 'static,
|
Overhaul how type information gets to the CLI
This commit is a complete overhaul of how the `#[wasm_bindgen]` macro
communicates type information to the CLI tool, and it's done in a somewhat...
unconventional fashion.
Today we've got a problem where the generated JS needs to understand the types
of each function exported or imported. This understanding is what enables it to
generate the appropriate JS wrappers and such. We want to, however, be quite
flexible and extensible in types that are supported across the boundary, which
means that internally we rely on the trait system to resolve what's what.
Communicating the type information historically was done by creating a four byte
"descriptor" and using associated type projections to communicate that to the
CLI tool. Unfortunately four bytes isn't a lot of space to cram information like
arguments to a generic function, tuple types, etc. In general this just wasn't
flexible enough and the way custom references were treated was also already a
bit of a hack.
This commit takes a radical step of creating a **descriptor function** for each
function imported/exported. The really crazy part is that the `wasm-bindgen` CLI
tool now embeds a wasm interpreter and executes these functions when the CLI
tool is invoked. By allowing arbitrary functions to get executed it's now *much*
easier to inform `wasm-bindgen` about complicated structures of types. Rest
assured though that all these descriptor functions are automatically unexported
and gc'd away, so this should not have any impact on binary sizes
A new internal trait, `WasmDescribe`, is added to represent a description of all
types, sort of like a serialization of the structure of a type that
`wasm-bindgen` can understand. This works by calling a special exported function
with a `u32` value a bunch of times. This means that when we run a descriptor we
effectively get a `Vec<u32>` in the `wasm-bindgen` CLI tool. This list of
integers can then be parsed into a rich `enum` for the JS generation to work
with.
This commit currently only retains feature parity with the previous
implementation. I hope to soon solve issues like #123, #104, and #111 with this
support.
2018-04-13 07:33:46 -07:00
|
|
|
{
|
2018-04-14 09:13:07 -07:00
|
|
|
fn describe() {
|
2018-08-01 15:52:24 -05:00
|
|
|
#[allow(non_snake_case)]
|
2018-11-27 12:27:00 -08:00
|
|
|
unsafe extern "C" fn invoke<$($var: FromWasmAbi,)* R: ReturnWasmAbi>(
|
2018-09-24 15:10:58 -07:00
|
|
|
a: usize,
|
|
|
|
b: usize,
|
2018-08-01 15:52:24 -05:00
|
|
|
$($var: <$var as FromWasmAbi>::Abi),*
|
2018-09-17 18:26:45 -07:00
|
|
|
) -> <R as ReturnWasmAbi>::Abi {
|
2018-09-24 15:10:58 -07:00
|
|
|
if a == 0 {
|
2018-09-17 18:26:45 -07:00
|
|
|
throw_str("closure invoked recursively or destroyed already");
|
2018-08-01 15:52:24 -05:00
|
|
|
}
|
2018-09-17 18:26:45 -07:00
|
|
|
// Make sure all stack variables are converted before we
|
|
|
|
// convert `ret` as it may throw (for `Result`, for
|
|
|
|
// example)
|
|
|
|
let ret = {
|
2019-06-03 08:26:14 -07:00
|
|
|
let f: *const dyn FnMut($($var),*) -> R =
|
2018-09-24 15:10:58 -07:00
|
|
|
FatPtr { fields: (a, b) }.ptr;
|
2019-06-03 08:26:14 -07:00
|
|
|
let f = f as *mut dyn FnMut($($var),*) -> R;
|
2018-09-17 18:26:45 -07:00
|
|
|
$(
|
2019-06-25 05:08:50 -07:00
|
|
|
let $var = <$var as FromWasmAbi>::from_abi($var);
|
2018-09-17 18:26:45 -07:00
|
|
|
)*
|
2018-09-24 15:10:58 -07:00
|
|
|
(*f)($($var),*)
|
2018-09-17 18:26:45 -07:00
|
|
|
};
|
2019-06-25 05:08:50 -07:00
|
|
|
ret.return_abi()
|
2018-08-01 15:52:24 -05:00
|
|
|
}
|
2018-09-24 15:10:58 -07:00
|
|
|
|
2018-11-29 12:01:16 -08:00
|
|
|
inform(invoke::<$($var,)* R> as u32);
|
|
|
|
|
|
|
|
unsafe extern fn destroy<$($var: FromWasmAbi,)* R: ReturnWasmAbi>(
|
2018-09-24 15:10:58 -07:00
|
|
|
a: usize,
|
|
|
|
b: usize,
|
|
|
|
) {
|
2019-05-13 07:22:33 -07:00
|
|
|
// See `Fn()` above for why we simply return
|
|
|
|
if a == 0 {
|
|
|
|
return;
|
|
|
|
}
|
2019-06-03 08:26:14 -07:00
|
|
|
drop(Box::from_raw(FatPtr::<dyn FnMut($($var,)*) -> R> {
|
2018-09-24 15:10:58 -07:00
|
|
|
fields: (a, b)
|
|
|
|
}.ptr));
|
|
|
|
}
|
2018-11-29 12:01:16 -08:00
|
|
|
inform(destroy::<$($var,)* R> as u32);
|
|
|
|
|
|
|
|
<&mut Self>::describe();
|
2018-09-24 15:10:58 -07:00
|
|
|
}
|
2018-04-05 18:25:22 -07:00
|
|
|
}
|
2019-02-20 10:48:01 -08:00
|
|
|
|
|
|
|
#[allow(non_snake_case)]
|
|
|
|
impl<T, $($var,)* R> WasmClosureFnOnce<($($var),*), R> for T
|
|
|
|
where T: 'static + FnOnce($($var),*) -> R,
|
|
|
|
$($var: FromWasmAbi + 'static,)*
|
|
|
|
R: ReturnWasmAbi + 'static
|
|
|
|
{
|
2019-06-03 08:26:14 -07:00
|
|
|
type FnMut = dyn FnMut($($var),*) -> R;
|
2019-02-20 10:48:01 -08:00
|
|
|
|
|
|
|
fn into_fn_mut(self) -> Box<Self::FnMut> {
|
|
|
|
let mut me = Some(self);
|
|
|
|
Box::new(move |$($var),*| {
|
|
|
|
let me = me.take().expect_throw("FnOnce called more than once");
|
|
|
|
me($($var),*)
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
fn into_js_function(self) -> JsValue {
|
|
|
|
use std::rc::Rc;
|
2019-03-26 08:00:16 -07:00
|
|
|
use crate::__rt::WasmRefCell;
|
2019-02-20 10:48:01 -08:00
|
|
|
|
|
|
|
let mut me = Some(self);
|
|
|
|
|
|
|
|
let rc1 = Rc::new(WasmRefCell::new(None));
|
|
|
|
let rc2 = rc1.clone();
|
|
|
|
|
|
|
|
let closure = Closure::wrap(Box::new(move |$($var),*| {
|
|
|
|
// Invoke ourself and get the result.
|
|
|
|
let me = me.take().expect_throw("FnOnce called more than once");
|
|
|
|
let result = me($($var),*);
|
|
|
|
|
|
|
|
// And then drop the `Rc` holding this function's `Closure`
|
|
|
|
// alive.
|
|
|
|
debug_assert_eq!(Rc::strong_count(&rc2), 1);
|
|
|
|
let option_closure = rc2.borrow_mut().take();
|
|
|
|
debug_assert!(option_closure.is_some());
|
|
|
|
drop(option_closure);
|
|
|
|
|
|
|
|
result
|
2019-06-03 08:26:14 -07:00
|
|
|
}) as Box<dyn FnMut($($var),*) -> R>);
|
2019-02-20 10:48:01 -08:00
|
|
|
|
|
|
|
let js_val = closure.as_ref().clone();
|
|
|
|
|
|
|
|
*rc1.borrow_mut() = Some(closure);
|
|
|
|
debug_assert_eq!(Rc::strong_count(&rc1), 2);
|
|
|
|
drop(rc1);
|
|
|
|
|
|
|
|
js_val
|
|
|
|
}
|
|
|
|
}
|
2018-04-05 18:25:22 -07:00
|
|
|
)*)
|
|
|
|
}
|
|
|
|
|
|
|
|
doit! {
|
2018-04-14 09:13:07 -07:00
|
|
|
()
|
|
|
|
(A)
|
|
|
|
(A B)
|
|
|
|
(A B C)
|
|
|
|
(A B C D)
|
|
|
|
(A B C D E)
|
|
|
|
(A B C D E F)
|
|
|
|
(A B C D E F G)
|
2019-02-17 11:00:52 -06:00
|
|
|
(A B C D E F G H)
|
2018-04-05 18:25:22 -07:00
|
|
|
}
|
2019-04-01 11:00:09 -07:00
|
|
|
|
|
|
|
// Copy the above impls down here for where there's only one argument and it's a
|
|
|
|
// reference. We could add more impls for more kinds of references, but it
|
|
|
|
// becomes a combinatorial explosion quickly. Let's see how far we can get with
|
|
|
|
// just this one! Maybe someone else can figure out voodoo so we don't have to
|
|
|
|
// duplicate.
|
|
|
|
|
2019-06-03 08:26:14 -07:00
|
|
|
unsafe impl<A, R> WasmClosure for dyn Fn(&A) -> R
|
2019-04-01 11:00:09 -07:00
|
|
|
where A: RefFromWasmAbi,
|
|
|
|
R: ReturnWasmAbi + 'static,
|
|
|
|
{
|
|
|
|
fn describe() {
|
|
|
|
#[allow(non_snake_case)]
|
|
|
|
unsafe extern "C" fn invoke<A: RefFromWasmAbi, R: ReturnWasmAbi>(
|
|
|
|
a: usize,
|
|
|
|
b: usize,
|
|
|
|
arg: <A as RefFromWasmAbi>::Abi,
|
|
|
|
) -> <R as ReturnWasmAbi>::Abi {
|
|
|
|
if a == 0 {
|
|
|
|
throw_str("closure invoked recursively or destroyed already");
|
|
|
|
}
|
|
|
|
// Make sure all stack variables are converted before we
|
|
|
|
// convert `ret` as it may throw (for `Result`, for
|
|
|
|
// example)
|
|
|
|
let ret = {
|
2019-06-03 08:26:14 -07:00
|
|
|
let f: *const dyn Fn(&A) -> R =
|
2019-04-01 11:00:09 -07:00
|
|
|
FatPtr { fields: (a, b) }.ptr;
|
2019-06-25 05:08:50 -07:00
|
|
|
let arg = <A as RefFromWasmAbi>::ref_from_abi(arg);
|
2019-04-01 11:00:09 -07:00
|
|
|
(*f)(&*arg)
|
|
|
|
};
|
2019-06-25 05:08:50 -07:00
|
|
|
ret.return_abi()
|
2019-04-01 11:00:09 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
inform(invoke::<A, R> as u32);
|
|
|
|
|
|
|
|
unsafe extern fn destroy<A: RefFromWasmAbi, R: ReturnWasmAbi>(
|
|
|
|
a: usize,
|
|
|
|
b: usize,
|
|
|
|
) {
|
2019-05-13 07:22:33 -07:00
|
|
|
// See `Fn()` above for why we simply return
|
|
|
|
if a == 0 {
|
|
|
|
return;
|
|
|
|
}
|
2019-06-03 08:26:14 -07:00
|
|
|
drop(Box::from_raw(FatPtr::<dyn Fn(&A) -> R> {
|
2019-04-01 11:00:09 -07:00
|
|
|
fields: (a, b)
|
|
|
|
}.ptr));
|
|
|
|
}
|
|
|
|
inform(destroy::<A, R> as u32);
|
|
|
|
|
|
|
|
<&Self>::describe();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-06-03 08:26:14 -07:00
|
|
|
unsafe impl<A, R> WasmClosure for dyn FnMut(&A) -> R
|
2019-04-01 11:00:09 -07:00
|
|
|
where A: RefFromWasmAbi,
|
|
|
|
R: ReturnWasmAbi + 'static,
|
|
|
|
{
|
|
|
|
fn describe() {
|
|
|
|
#[allow(non_snake_case)]
|
|
|
|
unsafe extern "C" fn invoke<A: RefFromWasmAbi, R: ReturnWasmAbi>(
|
|
|
|
a: usize,
|
|
|
|
b: usize,
|
|
|
|
arg: <A as RefFromWasmAbi>::Abi,
|
|
|
|
) -> <R as ReturnWasmAbi>::Abi {
|
|
|
|
if a == 0 {
|
|
|
|
throw_str("closure invoked recursively or destroyed already");
|
|
|
|
}
|
|
|
|
// Make sure all stack variables are converted before we
|
|
|
|
// convert `ret` as it may throw (for `Result`, for
|
|
|
|
// example)
|
|
|
|
let ret = {
|
2019-06-03 08:26:14 -07:00
|
|
|
let f: *const dyn FnMut(&A) -> R =
|
2019-04-01 11:00:09 -07:00
|
|
|
FatPtr { fields: (a, b) }.ptr;
|
2019-06-03 08:26:14 -07:00
|
|
|
let f = f as *mut dyn FnMut(&A) -> R;
|
2019-06-25 05:08:50 -07:00
|
|
|
let arg = <A as RefFromWasmAbi>::ref_from_abi(arg);
|
2019-04-01 11:00:09 -07:00
|
|
|
(*f)(&*arg)
|
|
|
|
};
|
2019-06-25 05:08:50 -07:00
|
|
|
ret.return_abi()
|
2019-04-01 11:00:09 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
inform(invoke::<A, R> as u32);
|
|
|
|
|
|
|
|
unsafe extern fn destroy<A: RefFromWasmAbi, R: ReturnWasmAbi>(
|
|
|
|
a: usize,
|
|
|
|
b: usize,
|
|
|
|
) {
|
2019-05-13 07:22:33 -07:00
|
|
|
// See `Fn()` above for why we simply return
|
|
|
|
if a == 0 {
|
|
|
|
return;
|
|
|
|
}
|
2019-06-03 08:26:14 -07:00
|
|
|
drop(Box::from_raw(FatPtr::<dyn FnMut(&A) -> R> {
|
2019-04-01 11:00:09 -07:00
|
|
|
fields: (a, b)
|
|
|
|
}.ptr));
|
|
|
|
}
|
|
|
|
inform(destroy::<A, R> as u32);
|
|
|
|
|
|
|
|
<&mut Self>::describe();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[allow(non_snake_case)]
|
|
|
|
impl<T, A, R> WasmClosureFnOnce<(&A,), R> for T
|
|
|
|
where T: 'static + FnOnce(&A) -> R,
|
|
|
|
A: RefFromWasmAbi + 'static,
|
|
|
|
R: ReturnWasmAbi + 'static
|
|
|
|
{
|
2019-06-03 08:26:14 -07:00
|
|
|
type FnMut = dyn FnMut(&A) -> R;
|
2019-04-01 11:00:09 -07:00
|
|
|
|
|
|
|
fn into_fn_mut(self) -> Box<Self::FnMut> {
|
|
|
|
let mut me = Some(self);
|
|
|
|
Box::new(move |arg| {
|
|
|
|
let me = me.take().expect_throw("FnOnce called more than once");
|
|
|
|
me(arg)
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
fn into_js_function(self) -> JsValue {
|
|
|
|
use std::rc::Rc;
|
|
|
|
use crate::__rt::WasmRefCell;
|
|
|
|
|
|
|
|
let mut me = Some(self);
|
|
|
|
|
|
|
|
let rc1 = Rc::new(WasmRefCell::new(None));
|
|
|
|
let rc2 = rc1.clone();
|
|
|
|
|
|
|
|
let closure = Closure::wrap(Box::new(move |arg: &A| {
|
|
|
|
// Invoke ourself and get the result.
|
|
|
|
let me = me.take().expect_throw("FnOnce called more than once");
|
|
|
|
let result = me(arg);
|
|
|
|
|
|
|
|
// And then drop the `Rc` holding this function's `Closure`
|
|
|
|
// alive.
|
|
|
|
debug_assert_eq!(Rc::strong_count(&rc2), 1);
|
|
|
|
let option_closure = rc2.borrow_mut().take();
|
|
|
|
debug_assert!(option_closure.is_some());
|
|
|
|
drop(option_closure);
|
|
|
|
|
|
|
|
result
|
2019-06-03 08:26:14 -07:00
|
|
|
}) as Box<dyn FnMut(&A) -> R>);
|
2019-04-01 11:00:09 -07:00
|
|
|
|
|
|
|
let js_val = closure.as_ref().clone();
|
|
|
|
|
|
|
|
*rc1.borrow_mut() = Some(closure);
|
|
|
|
debug_assert_eq!(Rc::strong_count(&rc1), 2);
|
|
|
|
drop(rc1);
|
|
|
|
|
|
|
|
js_val
|
|
|
|
}
|
|
|
|
}
|