use crate::*;
fn ensure_dispatch_callback() {
let window_value: Window = match window() {
Some(w) => w,
None => return,
};
let key: JsValue = JsValue::from_str(EUV_DISPATCH);
if Reflect::get(&window_value, &key)
.unwrap_or(JsValue::UNDEFINED)
.is_undefined()
{
let closure: closure::Closure<dyn FnMut()> = closure::Closure::wrap(Box::new(|| {
SCHEDULED.store(false, Ordering::Relaxed);
dispatch_signal_update_callbacks();
}));
let _ = Reflect::set(&window_value, &key, closure.as_ref());
closure.forget();
}
}
pub fn schedule_signal_update() {
if SCHEDULED.load(Ordering::Relaxed) || SUPPRESS_SCHEDULE.load(Ordering::Relaxed) {
return;
}
SCHEDULED.store(true, Ordering::Relaxed);
mark_all_slots_dirty();
let window_option: Option<Window> = window();
if window_option.is_none() {
SCHEDULED.store(false, Ordering::Relaxed);
return;
}
ensure_dispatch_callback();
let window_value: Window = match window_option {
Some(w) => w,
None => {
SCHEDULED.store(false, Ordering::Relaxed);
return;
}
};
let dispatch_fn: JsValue =
Reflect::get(&window_value, &JsValue::from_str(EUV_DISPATCH)).unwrap_or(JsValue::UNDEFINED);
if dispatch_fn.is_undefined() {
SCHEDULED.store(false, Ordering::Relaxed);
return;
}
let raf_val: JsValue = Reflect::get(&window_value, &JsValue::from_str(REQUEST_ANIMATION_FRAME))
.unwrap_or(JsValue::UNDEFINED);
if raf_val.is_undefined() {
let queue_microtask_val: JsValue =
Reflect::get(&window_value, &JsValue::from_str(QUEUE_MICROTASK))
.unwrap_or(JsValue::UNDEFINED);
if queue_microtask_val.is_undefined() {
SCHEDULED.store(false, Ordering::Relaxed);
return;
}
let queue_microtask: Function = queue_microtask_val.into();
let _ = queue_microtask.call1(&JsValue::NULL, &dispatch_fn);
return;
}
let raf: Function = raf_val.into();
let _ = raf.call1(&JsValue::NULL, &dispatch_fn);
}
pub fn batch_updates<F, R>(callback: F) -> R
where
F: FnOnce() -> R,
{
let previous: bool = SUPPRESS_SCHEDULE.load(Ordering::Relaxed);
SUPPRESS_SCHEDULE.store(true, Ordering::Relaxed);
let result: R = callback();
SUPPRESS_SCHEDULE.store(previous, Ordering::Relaxed);
result
}
pub(crate) fn subscribe_attr_signal<F>(attr_signal: Signal<String>, compute: F)
where
F: Fn() -> String + 'static,
{
let signal_key: usize = attr_signal.get_inner();
let callback: Box<dyn FnMut()> = Box::new(move || {
let new_value: String = compute();
attr_signal.set_silent(new_value);
});
register_attr_signal_listener(signal_key, callback);
}
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> = Signal::create(initial);
let string_signal_clone: Signal<String> = string_signal;
source.replace_subscribe({
let source_inner: Signal<bool> = source;
move || {
let new_value: String = source_inner.get().to_string();
string_signal_clone.set_silent(new_value);
}
});
AttributeValue::Signal(string_signal)
}
#[allow(static_mut_refs)]
pub(crate) fn current_hook_context_mut() -> &'static mut Option<HookContextRc> {
unsafe { &mut *CURRENT_HOOK_CONTEXT.get_0().get() }
}
#[allow(static_mut_refs)]
pub(crate) fn current_hook_context() -> &'static Option<HookContextRc> {
unsafe { &*CURRENT_HOOK_CONTEXT.get_0().get() }
}