///|
pub(all) struct StateSlot[T] {
mut value : T
mut version : Int
mut listeners : Array[StateListener]
}
///|
pub(all) struct StateListener {
mut active : Bool
callback : () -> Unit
}
///|
pub(all) struct StateSubscription {
listener : StateListener
}
///|
pub fn[T] StateSlot::new(value : T) -> StateSlot[T] {
{ value, version: 0, listeners: [] }
}
///|
pub fn[T] StateSlot::get(self : StateSlot[T]) -> T {
self.value
}
///|
pub fn[T] StateSlot::set(self : StateSlot[T], value : T) -> Unit {
self.value = value
self.version = self.version + 1
self.notify()
}
///|
pub fn[T] StateSlot::update(
self : StateSlot[T],
f : (T) -> T raise?,
) -> Unit raise? {
self.set(f(self.value))
}
///|
pub fn[T] StateSlot::subscribe(
self : StateSlot[T],
callback : () -> Unit,
) -> StateSubscription {
self.prune_inactive_listeners()
let listener = StateListener::new(callback)
self.listeners.push(listener)
{ listener, }
}
///|
fn[T] StateSlot::notify(self : StateSlot[T]) -> Unit {
for listener in self.listeners {
if listener.active {
(listener.callback)()
}
}
}
///|
fn[T] StateSlot::prune_inactive_listeners(self : StateSlot[T]) -> Unit {
self.listeners = self.listeners.filter(listener => listener.active)
}
///|
pub fn StateListener::new(callback : () -> Unit) -> StateListener {
{ active: true, callback }
}
///|
pub fn StateSubscription::cancel(self : StateSubscription) -> Unit {
self.listener.active = false
}
///|
pub fn StateSubscription::is_active(self : StateSubscription) -> Bool {
self.listener.active
}