https://heycam.github.io/webidl/#idl-callback-functions
Example:
callback AsyncOperationCallback = void (DOMString status);
interface AsyncOperations {
void performOperation(AsyncOperationCallback whenFinished);
};
Should probably translate these into FnMove(...) -> ... since we can't be sure about the way the interfaces might use the callbacks.
What's an FnMove? Did you mean FnMut?
Woops, yeah just meant that we have to give up ownership of anything the function closes over and move it into the function.
@fitzgen Right, stdweb handles that by requiring callbacks to be 'static, which seems to work well.
For anything that needs 'static then this translates in wasm-bindgen to &Closure<FnMut(...)>, but anything that doesn't need 'static this'll translate to a usual &mut FnMut(...)
I'm trying to get my head around this.
Let's take a specific example (window.setTimeout, and window.cancelTimeout).
Here's the relevant webidl
callback Function = any(any... arguments);
[Throws]
long setTimeout(Function handler, optional long timeout = 0, any... arguments);
void clearTimeout(optional long handle = 0);
And we want to generate the equivalent of
#[wasm_bindgen]
extern {
fn setTimeout(handler: &Closure<FnMut()>, timeout: u32) -> f64;
fn clearTimeout(handle: f64);
}
Note this is a start, but not finished generation, because the FnMut should be able to return anything (not just void), and take any arguments, passable as a third parameter. However, I think these restrictions are not limiting, at least in the short term.
So it looks like we don't actually generate anything for Function (apart from maybe a type alias?), but use that information to generate signatures for functions (in this case in the WindowOrWorkerGlobalScope mixin).
I'm just seeing if others agree this is the correct approach before I do any work.
EDIT: Also we have to assume that the function will be called more than once, and we don't know when the function might be called, so we have to insist it is heap-allocated (Closure<..>).
I think this feature is blocked on #503 because the current impl for variadic (assume one arg) is incompatible with this construct, we the default should probably be no args.
For arguments to imported JS functions, I believe we want to use Closure<FnMut(...) -> ...>.
For returned values from imported JS functions/getters, I believe we want to use js_sys::Function.
@fitzgen and I had a good talk about this today, and the conclusions were:
js_sys::Function.Closure<T>, to get the underlying JsValue (which is actually a js_sys::Function but will need a cast)JsValue corresponding to &mut FnMut(..) (or something equivalent)The actual method of acquiring a JsValue from Closure<T> will require mega-hacks that's not worth going into here, but I'll look into the implementation tomorrow.
Next, we should provide the ability, from a Closure
, to get the underlying JsValue (which is actually a js_sys::Function but will need a cast)
For context, the reason why it needs to be a JsValue instead of a js_sys::Function is because js_sys is a downstream crate that depends on wasm-bindgen, and wasm-bindgen doesn't have access to that type.
Alternatively, we could move js_sys::Function into wasm_bindgen and then re-export it again in js_sys.
Let's get something working first and then think about it. Likely it won't matter since everyone will be using web_sys for callbacks which can do the casting under the covers.
I've added support for this in https://github.com/rustwasm/wasm-bindgen/pull/796