use crate::{error::Error, plugin_listener_handle::PluginListenerHandle};
use js_sys::Promise;
use serde::{Deserialize, Serialize};
use serde_with::skip_serializing_none;
use std::{future::Future, sync::Arc};
use wasm_bindgen::{prelude::Closure, JsValue};
use wasm_bindgen_futures::JsFuture;
#[skip_serializing_none]
#[derive(Clone, Default, Debug, PartialEq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase", default)]
pub struct InnerError {
pub message: String,
}
#[derive(Clone, Default, Debug, PartialEq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase", default)]
pub struct JsException {
pub message: String,
}
pub async fn run_unit_unit<Fut: Future<Output = Result<(), JsValue>>, F: Fn() -> Fut>(
f: F,
) -> Result<(), Error> {
Ok(f().await?)
}
pub async fn run_unit_value<
'de,
O: serde::de::DeserializeOwned,
Fut: Future<Output = Result<JsValue, JsValue>>,
F: Fn() -> Fut,
>(
f: F,
) -> Result<O, Error> {
let js_value = f().await?;
let o: O =
serde_wasm_bindgen::from_value(js_value).map_err(|e| Error::deserializing::<O>(e))?;
Ok(o)
}
pub async fn run_value_unit<
I: serde::Serialize,
Fut: Future<Output = Result<(), JsValue>>,
F: Fn(JsValue) -> Fut,
>(
i: impl Into<I>,
f: F,
) -> Result<(), Error> {
let i = i.into();
let js_value: JsValue =
serde_wasm_bindgen::to_value(&i).map_err(|e| Error::serializing::<I>(e))?;
Ok(f(js_value).await?)
}
pub fn run_value_unit_sync<
I: serde::Serialize,
F: Fn(JsValue) -> Result<(), JsValue>,
>(
i: impl Into<I>,
f: F,
) -> Result<(), Error> {
let i = i.into();
let js_value: JsValue =
serde_wasm_bindgen::to_value(&i).map_err(|e| Error::serializing::<I>(e))?;
Ok(f(js_value)?)
}
pub async fn run_value_value<
'de,
O: serde::de::DeserializeOwned,
I: serde::Serialize,
Fut: Future<Output = Result<JsValue, JsValue>>,
F: Fn(JsValue) -> Fut,
>(
i: impl Into<I>,
f: F,
) -> Result<O, Error> {
let i = i.into();
let js_input_value: JsValue =
serde_wasm_bindgen::to_value(&i).map_err(|e| Error::serializing::<I>(e))?;
let js_output_value = f(js_input_value).await?;
let o: O = serde_wasm_bindgen::from_value(js_output_value)
.map_err(|e| Error::deserializing::<O>(e))?;
Ok(o)
}
pub async fn listen_async<T: serde::de::DeserializeOwned, F: Fn(T) + 'static>(
func: F,
name: &'static str,
add_listener: impl Fn(&str, &Closure<dyn Fn(JsValue)>) -> JsValue,
) -> Result<PluginListenerHandle, Error> {
let func2 = move |js_value: JsValue| {
let jv = js_value.clone();
match serde_wasm_bindgen::from_value(js_value).map_err(|e| Error::deserializing::<T>(e)) {
Ok(schema) => func(schema),
Err(err) => {
println!("Notification deserialize error: {err} js_value: {jv:?}")
},
}
};
let closure = Arc::new(Closure::new(func2));
let js_value = add_listener(name, closure.as_ref());
let promise = Promise::resolve(&js_value);
let future = JsFuture::from(promise);
let handle = future.await?;
Ok(PluginListenerHandle::new(closure, handle))
}