use crate::*;
fn ensure_dispatch_callback() {
let window_value: Window = match window() {
Some(window_instance) => window_instance,
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(window_instance) => window_instance,
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 request_animation_frame_value: JsValue =
Reflect::get(&window_value, &JsValue::from_str(REQUEST_ANIMATION_FRAME))
.unwrap_or(JsValue::UNDEFINED);
if request_animation_frame_value.is_undefined() {
let queue_microtask_value: JsValue =
Reflect::get(&window_value, &JsValue::from_str(QUEUE_MICROTASK))
.unwrap_or(JsValue::UNDEFINED);
if queue_microtask_value.is_undefined() {
SCHEDULED.store(false, Ordering::Relaxed);
return;
}
let queue_microtask: Function = queue_microtask_value.into();
let _ = queue_microtask.call1(&JsValue::NULL, &dispatch_fn);
return;
}
let request_animation_frame: Function = request_animation_frame_value.into();
let _ = request_animation_frame.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,
{
register_attr_signal_listener(
attr_signal.get_inner(),
Box::new(move || {
attr_signal.set_silent(compute());
}),
);
}
pub(crate) fn bool_signal_to_string_attribute_value(source: Signal<bool>) -> AttributeValue {
let string_signal: Signal<String> = Signal::create(source.get().to_string());
let string_signal_clone: Signal<String> = string_signal;
source.replace_subscribe({
let source_inner: Signal<bool> = source;
move || {
string_signal_clone.set_silent(source_inner.get().to_string());
}
});
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() }
}