use crate::UseWebLockOptions;
use std::future::Future;
use thiserror::Error;
use wasm_bindgen::JsValue;
pub use web_sys::LockMode;
pub async fn use_web_lock<C, F, R>(name: &str, callback: C) -> Result<R, UseWebLockError>
where
C: FnOnce(web_sys::Lock) -> F + 'static,
F: Future<Output = R>,
R: 'static,
{
use_web_lock_with_options(name, callback, UseWebLockOptions::default()).await
}
pub async fn use_web_lock_with_options<C, F, R>(
name: &str,
callback: C,
options: UseWebLockOptions,
) -> Result<R, UseWebLockError>
where
C: FnOnce(web_sys::Lock) -> F + 'static,
F: Future<Output = R>,
R: 'static,
{
#[cfg(feature = "ssr")]
{
let _ = name;
let _ = callback;
let _ = options;
Err(UseWebLockError::Server)
}
#[cfg(not(feature = "ssr"))]
{
use crate::js_fut;
use leptos::prelude::window;
use std::sync::{Arc, Mutex};
use wasm_bindgen::JsCast;
use wasm_bindgen::closure::Closure;
use wasm_bindgen_futures::future_to_promise;
let ret_value = Arc::new(Mutex::new(None));
let handler = Closure::once(Box::new({
let ret_value = Arc::clone(&ret_value);
move |lock| {
future_to_promise(async move {
let ret = callback(lock).await;
ret_value.lock().expect("Lock failed").replace(ret);
Ok(JsValue::null())
})
}
}) as Box<dyn FnOnce(web_sys::Lock) -> _>)
.into_js_value();
let lock_promise = window().navigator().locks().request_with_options(
name,
&options.to_web_sys(),
handler.unchecked_ref(),
);
js_fut!(lock_promise)
.await
.map(move |_| {
Arc::into_inner(ret_value)
.expect("Arc has more than one reference still")
.into_inner()
.expect("Lock failed")
.expect("Return value was None")
})
.map_err(UseWebLockError::Failed)
}
}
#[derive(Error, Debug)]
pub enum UseWebLockError {
#[error("Lock cannot be acquired on the server")]
Server,
#[error("Lock failed")]
Failed(JsValue),
}