///|
fn[Msg] ProgramRuntimeDiagnostics::start_effect_task(
self : ProgramRuntimeDiagnostics,
descriptor : @core.EffectDescriptor,
start : ((Msg) -> Unit) -> (() -> Unit)?,
dispatch : (Msg) -> Unit,
) -> Unit {
self.cancel_effect_tasks_replaced_by_descriptor(descriptor)
let token = self.next_effect_task_value
self.next_effect_task_value = self.next_effect_task_value + 1
let active = Ref(true)
let cancel : Ref[(() -> Unit)?] = Ref(None)
self.active_effect_tasks.push({ token, descriptor, active, cancel, })
self.started_effect_task_count = self.started_effect_task_count + 1
self.effect_task_lifecycle.push({
key: descriptor.key(),
kind: descriptor.kind(),
label: descriptor.label(),
status: EffectTaskActive,
cancel_reason: None,
})
let cleanup = start(message => {
if active.val {
active.val = false
ignore(self.complete_effect_task(token))
dispatch(message)
} else {
self.record_ignored_effect_task_dispatch()
}
})
cancel.val = cleanup
if cleanup is None && active.val {
active.val = false
ignore(self.complete_effect_task(token))
}
}
///|
fn ProgramRuntimeDiagnostics::complete_effect_task(
self : ProgramRuntimeDiagnostics,
token : Int,
) -> Bool {
let mut completed : ActiveProgramEffectTask? = None
let remaining : Array[ActiveProgramEffectTask] = []
for task in self.active_effect_tasks {
match completed {
None =>
if task.token == token {
completed = Some(task)
} else {
remaining.push(task)
}
Some(_) => remaining.push(task)
}
}
self.active_effect_tasks = remaining
match completed {
Some(task) => {
self.completed_effect_task_count = self.completed_effect_task_count + 1
self.effect_task_lifecycle.push({
key: task.descriptor.key(),
kind: task.descriptor.kind(),
label: task.descriptor.label(),
status: EffectTaskCompleted,
cancel_reason: None,
})
true
}
None => false
}
}
///|
fn ProgramRuntimeDiagnostics::cancel_effect_tasks_replaced_by_descriptor(
self : ProgramRuntimeDiagnostics,
descriptor : @core.EffectDescriptor,
) -> Unit {
let remaining : Array[ActiveProgramEffectTask] = []
for task in self.active_effect_tasks {
if task.descriptor.key() == descriptor.key() {
let reason = if task.descriptor.kind() == descriptor.kind() {
EffectTaskCancelReason::EffectTaskKeyChanged
} else {
EffectTaskKindChanged
}
if task.descriptor.kind() != descriptor.kind() ||
task.descriptor.label() != descriptor.label() {
self.record_effect_task_key_supersession(task.descriptor, descriptor)
}
self.cancel_effect_task(task, reason)
} else {
remaining.push(task)
}
}
self.active_effect_tasks = remaining
}
///|
fn ProgramRuntimeDiagnostics::cancel_all_effect_tasks(
self : ProgramRuntimeDiagnostics,
reason : EffectTaskCancelReason,
) -> Unit {
for task in self.active_effect_tasks {
self.cancel_effect_task(task, reason)
}
self.active_effect_tasks = []
}
///|
fn ProgramRuntimeDiagnostics::cancel_effect_task(
self : ProgramRuntimeDiagnostics,
task : ActiveProgramEffectTask,
reason : EffectTaskCancelReason,
) -> Unit {
task.active.val = false
match task.cancel.val {
Some(cancel) => cancel()
None => ()
}
self.cancelled_effect_task_count = self.cancelled_effect_task_count + 1
self.effect_task_lifecycle.push({
key: task.descriptor.key(),
kind: task.descriptor.kind(),
label: task.descriptor.label(),
status: EffectTaskCancelled,
cancel_reason: Some(reason),
})
}