From 6b5376d756fc70567d377cba1c8545f8d2badb10 Mon Sep 17 00:00:00 2001 From: Jonas Kruckenberg Date: Tue, 1 Nov 2022 16:38:21 +0100 Subject: [PATCH] fix: use proper closures --- src/event.rs | 47 +++++++++++++++++++++++++++++++---------------- src/mocks.rs | 31 +++++++++++++++++++++---------- 2 files changed, 52 insertions(+), 26 deletions(-) diff --git a/src/event.rs b/src/event.rs index 73b0302..37cdb0f 100644 --- a/src/event.rs +++ b/src/event.rs @@ -1,6 +1,7 @@ use std::fmt::Debug; use serde::{de::DeserializeOwned, Deserialize, Serialize}; +use wasm_bindgen::{prelude::Closure, JsValue}; #[derive(Deserialize)] pub struct Event { @@ -69,11 +70,18 @@ pub async fn emit(event: &str, payload: &T) { /// /// Note that removing the listener is required if your listener goes out of scope e.g. the component is unmounted. #[inline(always)] -pub async fn listen(event: &str, handler: &dyn Fn(Event)) -> impl FnOnce() { - let unlisten = inner::listen(event, &|raw| { - handler(serde_wasm_bindgen::from_value(raw).unwrap()) - }) - .await; +pub async fn listen(event: &str, mut handler: H) -> impl FnOnce() +where + T: DeserializeOwned, + H: FnMut(Event) + 'static, +{ + let closure = Closure::::new(move |raw| { + (handler)(serde_wasm_bindgen::from_value(raw).unwrap()) + }); + + let unlisten = inner::listen(event, &closure).await; + + closure.forget(); let unlisten = js_sys::Function::from(unlisten); move || { @@ -107,14 +115,18 @@ pub async fn listen(event: &str, handler: &dyn Fn(Event) /// /// Note that removing the listener is required if your listener goes out of scope e.g. the component is unmounted. #[inline(always)] -pub async fn once( - event: &str, - handler: &mut dyn FnMut(Event), -) -> impl FnOnce() { - let unlisten = inner::once(event, &mut |raw| { - handler(serde_wasm_bindgen::from_value(raw).unwrap()) - }) - .await; +pub async fn once(event: &str, mut handler: H) -> impl FnOnce() +where + T: DeserializeOwned, + H: FnMut(Event) + 'static, +{ + let closure = Closure::::new(move |raw| { + (handler)(serde_wasm_bindgen::from_value(raw).unwrap()) + }); + + let unlisten = inner::once(event, &closure).await; + + closure.forget(); let unlisten = js_sys::Function::from(unlisten); move || { @@ -123,12 +135,15 @@ pub async fn once( } mod inner { - use wasm_bindgen::{prelude::wasm_bindgen, JsValue}; + use wasm_bindgen::{ + prelude::{wasm_bindgen, Closure}, + JsValue, + }; #[wasm_bindgen(module = "/dist/event.js")] extern "C" { pub async fn emit(event: &str, payload: JsValue); - pub async fn listen(event: &str, handler: &dyn Fn(JsValue)) -> JsValue; - pub async fn once(event: &str, handler: &mut dyn FnMut(JsValue)) -> JsValue; + pub async fn listen(event: &str, handler: &Closure) -> JsValue; + pub async fn once(event: &str, handler: &Closure) -> JsValue; } } diff --git a/src/mocks.rs b/src/mocks.rs index ff766ea..f8c4877 100644 --- a/src/mocks.rs +++ b/src/mocks.rs @@ -1,16 +1,13 @@ use js_sys::Array; -use wasm_bindgen::JsValue; +use wasm_bindgen::{prelude::Closure, JsValue}; /// Mocks the current window label /// In non-tauri context it is required to call this function///before* using the `@tauri-apps/api/window` module. -/// +/// /// This function only mocks the *presence* of a window, /// window properties (e.g. width and height) can be mocked like regular IPC calls using the `mockIPC` function. pub fn mock_window(current: &str) { - inner::mockWindows( - current, - JsValue::UNDEFINED, - ) + inner::mockWindows(current, JsValue::UNDEFINED) } /// Mocks many window labels. @@ -31,8 +28,19 @@ pub fn mock_windows(current: &str, additional_windows: &[&str]) { /// Intercepts all IPC requests with the given mock handler. /// /// This function can be used when testing tauri frontend applications or when running the frontend in a Node.js context during static site generation. -pub fn mock_ipc(handler: &dyn Fn(JsValue)) { - inner::mockIPC(handler); +pub fn mock_ipc(mut handler: H) +where + H: FnMut(String, JsValue) -> Result + 'static, + R: Into, + E: Into, +{ + let closure = Closure:: Result>::new( + move |cmd, payload| (handler)(cmd, payload).map(Into::into).map_err(Into::into), + ); + + inner::mockIPC(&closure); + + closure.forget(); } /// Clears mocked functions/data injected by the other functions in this module. @@ -42,13 +50,16 @@ pub fn clear_mocks() { } mod inner { - use wasm_bindgen::{prelude::wasm_bindgen, JsValue}; + use wasm_bindgen::{ + prelude::{wasm_bindgen, Closure}, + JsValue, + }; #[wasm_bindgen(module = "/dist/mocks.js")] extern "C" { #[wasm_bindgen(variadic)] pub fn mockWindows(current: &str, rest: JsValue); - pub fn mockIPC(handler: &dyn Fn(JsValue)); + pub fn mockIPC(handler: &Closure Result>); pub fn clearMocks(); } }