fix: use proper closures

This commit is contained in:
Jonas Kruckenberg 2022-11-01 16:38:21 +01:00
parent 65334ebb8b
commit 6b5376d756
2 changed files with 52 additions and 26 deletions

View file

@ -1,6 +1,7 @@
use std::fmt::Debug; use std::fmt::Debug;
use serde::{de::DeserializeOwned, Deserialize, Serialize}; use serde::{de::DeserializeOwned, Deserialize, Serialize};
use wasm_bindgen::{prelude::Closure, JsValue};
#[derive(Deserialize)] #[derive(Deserialize)]
pub struct Event<T> { pub struct Event<T> {
@ -69,11 +70,18 @@ pub async fn emit<T: Serialize>(event: &str, payload: &T) {
/// ///
/// Note that removing the listener is required if your listener goes out of scope e.g. the component is unmounted. /// Note that removing the listener is required if your listener goes out of scope e.g. the component is unmounted.
#[inline(always)] #[inline(always)]
pub async fn listen<T: DeserializeOwned>(event: &str, handler: &dyn Fn(Event<T>)) -> impl FnOnce() { pub async fn listen<T, H>(event: &str, mut handler: H) -> impl FnOnce()
let unlisten = inner::listen(event, &|raw| { where
handler(serde_wasm_bindgen::from_value(raw).unwrap()) T: DeserializeOwned,
}) H: FnMut(Event<T>) + 'static,
.await; {
let closure = Closure::<dyn FnMut(JsValue)>::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); let unlisten = js_sys::Function::from(unlisten);
move || { move || {
@ -107,14 +115,18 @@ pub async fn listen<T: DeserializeOwned>(event: &str, handler: &dyn Fn(Event<T>)
/// ///
/// Note that removing the listener is required if your listener goes out of scope e.g. the component is unmounted. /// Note that removing the listener is required if your listener goes out of scope e.g. the component is unmounted.
#[inline(always)] #[inline(always)]
pub async fn once<T: DeserializeOwned>( pub async fn once<T, H>(event: &str, mut handler: H) -> impl FnOnce()
event: &str, where
handler: &mut dyn FnMut(Event<T>), T: DeserializeOwned,
) -> impl FnOnce() { H: FnMut(Event<T>) + 'static,
let unlisten = inner::once(event, &mut |raw| { {
handler(serde_wasm_bindgen::from_value(raw).unwrap()) let closure = Closure::<dyn FnMut(JsValue)>::new(move |raw| {
}) (handler)(serde_wasm_bindgen::from_value(raw).unwrap())
.await; });
let unlisten = inner::once(event, &closure).await;
closure.forget();
let unlisten = js_sys::Function::from(unlisten); let unlisten = js_sys::Function::from(unlisten);
move || { move || {
@ -123,12 +135,15 @@ pub async fn once<T: DeserializeOwned>(
} }
mod inner { mod inner {
use wasm_bindgen::{prelude::wasm_bindgen, JsValue}; use wasm_bindgen::{
prelude::{wasm_bindgen, Closure},
JsValue,
};
#[wasm_bindgen(module = "/dist/event.js")] #[wasm_bindgen(module = "/dist/event.js")]
extern "C" { extern "C" {
pub async fn emit(event: &str, payload: JsValue); pub async fn emit(event: &str, payload: JsValue);
pub async fn listen(event: &str, handler: &dyn Fn(JsValue)) -> JsValue; pub async fn listen(event: &str, handler: &Closure<dyn FnMut(JsValue)>) -> JsValue;
pub async fn once(event: &str, handler: &mut dyn FnMut(JsValue)) -> JsValue; pub async fn once(event: &str, handler: &Closure<dyn FnMut(JsValue)>) -> JsValue;
} }
} }

View file

@ -1,5 +1,5 @@
use js_sys::Array; use js_sys::Array;
use wasm_bindgen::JsValue; use wasm_bindgen::{prelude::Closure, JsValue};
/// Mocks the current window label /// Mocks the current window label
/// In non-tauri context it is required to call this function///before* using the `@tauri-apps/api/window` module. /// In non-tauri context it is required to call this function///before* using the `@tauri-apps/api/window` module.
@ -7,10 +7,7 @@ use wasm_bindgen::JsValue;
/// This function only mocks the *presence* of a window, /// 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. /// window properties (e.g. width and height) can be mocked like regular IPC calls using the `mockIPC` function.
pub fn mock_window(current: &str) { pub fn mock_window(current: &str) {
inner::mockWindows( inner::mockWindows(current, JsValue::UNDEFINED)
current,
JsValue::UNDEFINED,
)
} }
/// Mocks many window labels. /// 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. /// 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. /// 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)) { pub fn mock_ipc<H, R, E>(mut handler: H)
inner::mockIPC(handler); where
H: FnMut(String, JsValue) -> Result<R, E> + 'static,
R: Into<JsValue>,
E: Into<JsValue>,
{
let closure = Closure::<dyn FnMut(String, JsValue) -> Result<JsValue, JsValue>>::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. /// Clears mocked functions/data injected by the other functions in this module.
@ -42,13 +50,16 @@ pub fn clear_mocks() {
} }
mod inner { mod inner {
use wasm_bindgen::{prelude::wasm_bindgen, JsValue}; use wasm_bindgen::{
prelude::{wasm_bindgen, Closure},
JsValue,
};
#[wasm_bindgen(module = "/dist/mocks.js")] #[wasm_bindgen(module = "/dist/mocks.js")]
extern "C" { extern "C" {
#[wasm_bindgen(variadic)] #[wasm_bindgen(variadic)]
pub fn mockWindows(current: &str, rest: JsValue); pub fn mockWindows(current: &str, rest: JsValue);
pub fn mockIPC(handler: &dyn Fn(JsValue)); pub fn mockIPC(handler: &Closure<dyn FnMut(String, JsValue) -> Result<JsValue, JsValue>>);
pub fn clearMocks(); pub fn clearMocks();
} }
} }