use crate::*;
#[cfg(target_arch = "wasm32")]
pub(crate) fn dispatch_signal_update() {
if let Some(win) = window() {
let event: Event = Event::new("__euv_signal_update__").unwrap();
let _ = win.dispatch_event(&event);
}
}
pub(crate) fn schedule_signal_update() {
if SCHEDULED.load(Ordering::Relaxed) {
return;
}
SCHEDULED.store(true, Ordering::Relaxed);
#[cfg(target_arch = "wasm32")]
{
let win: Option<Window> = window();
if win.is_none() {
SCHEDULED.store(false, Ordering::Relaxed);
return;
}
let promise: js_sys::Promise = js_sys::Promise::resolve(&wasm_bindgen::JsValue::NULL);
let closure: wasm_bindgen::closure::Closure<dyn FnMut(wasm_bindgen::JsValue)> =
wasm_bindgen::closure::Closure::wrap(Box::new(move |_value: wasm_bindgen::JsValue| {
SCHEDULED.store(false, Ordering::Relaxed);
dispatch_signal_update();
}));
let _ = promise.then(&closure);
closure.forget();
}
#[cfg(not(target_arch = "wasm32"))]
{
SCHEDULED.store(false, Ordering::Relaxed);
}
}
pub fn trigger_update() {
schedule_signal_update();
}
fn get_current_hook_context() -> HookContext {
unsafe { HookContext::from_inner(CURRENT_HOOK_CONTEXT) }
}
pub fn with_hook_context<F, R>(context: HookContext, f: F) -> R
where
F: FnOnce() -> R,
{
let previous: *mut HookContextInner = unsafe { CURRENT_HOOK_CONTEXT };
unsafe {
CURRENT_HOOK_CONTEXT = context.inner;
}
let result: R = f();
unsafe {
CURRENT_HOOK_CONTEXT = previous;
}
result
}
pub fn create_hook_context() -> HookContext {
let ctx: Box<HookContextInner> = Box::default();
HookContext::from_inner(Box::leak(ctx) as *mut HookContextInner)
}
pub fn use_signal<T, F>(init: F) -> Signal<T>
where
T: Clone + PartialEq + 'static,
F: FnOnce() -> T,
{
let mut ctx: HookContext = get_current_hook_context();
let index: usize = ctx.get_hook_index();
ctx.set_hook_index(index + 1_usize);
if index < ctx.get_hooks().len()
&& let Some(existing) = ctx.get_hooks()[index].downcast_ref::<Signal<T>>()
{
return *existing;
}
let signal: Signal<T> = {
let boxed: Box<SignalInner<T>> = Box::new(SignalInner::new(init()));
Signal::from_inner(Box::leak(boxed) as *mut SignalInner<T>)
};
if index < ctx.get_hooks().len() {
ctx.get_mut_hooks()[index] = Box::new(signal);
} else {
ctx.get_mut_hooks().push(Box::new(signal));
}
signal
}
pub(crate) fn bool_signal_to_string_attribute_value(source: Signal<bool>) -> AttributeValue {
let initial: String = source.get().to_string();
let string_signal: Signal<String> = {
let inner: SignalInner<String> = SignalInner::new(initial);
let boxed: Box<SignalInner<String>> = Box::new(inner);
Signal::from_inner(Box::leak(boxed) as *mut SignalInner<String>)
};
let string_signal_clone: Signal<String> = string_signal;
source.subscribe({
let source_inner: Signal<bool> = source;
move || {
let new_value: String = source_inner.get().to_string();
string_signal_clone.set(new_value);
}
});
AttributeValue::Signal(string_signal)
}