// Watch - Advanced signal utilities
// Watch a computed expression and run callback when it changes
///|
/// Watch a computed expression and run callback when it changes.
/// Returns a dispose function.
/// The callback receives (newValue, oldValue).
pub fn[T : Eq] watch(source : () -> T, callback : (T, T) -> Unit) -> () -> Unit {
let prev_value : Ref[T?] = Ref::new(None)
render_effect(fn() {
let new_value = source()
match prev_value.val {
Some(old) =>
if old != new_value {
callback(new_value, old)
prev_value.val = Some(new_value)
}
None => prev_value.val = Some(new_value)
}
})
}
///|
/// Watch with immediate execution (runs callback on first value too).
/// The callback receives (newValue, oldValue?) where oldValue is None on first run.
pub fn[T : Eq] watch_immediate(
source : () -> T,
callback : (T, T?) -> Unit,
) -> () -> Unit {
let prev_value : Ref[T?] = Ref::new(None)
render_effect(fn() {
let new_value = source()
match prev_value.val {
Some(old) =>
if old != new_value {
callback(new_value, Some(old))
prev_value.val = Some(new_value)
}
None => {
callback(new_value, None)
prev_value.val = Some(new_value)
}
}
})
}
///|
/// Create a signal that holds the previous value of another signal.
/// Returns a getter function for the previous value (None on first read).
pub fn[T] previous(sig : Signal[T]) -> () -> T? {
let prev : Ref[T?] = Ref::new(None)
let current : Ref[T?] = Ref::new(None)
let _ = render_effect(fn() {
let new_val = sig.get()
prev.val = current.val
current.val = Some(new_val)
})
fn() { prev.val }
}
///|
/// Create a signal that holds the previous value with initial value.
/// Unlike `previous`, this returns a plain T instead of T?.
pub fn[T] previous_with_initial(sig : Signal[T], initial : T) -> () -> T {
let prev : Ref[T] = Ref::new(initial)
let current : Ref[T?] = Ref::new(None)
let _ = render_effect(fn() {
let new_val = sig.get()
match current.val {
Some(curr) => prev.val = curr
None => ()
}
current.val = Some(new_val)
})
fn() { prev.val }
}