///|
fn ProgramRuntimeDiagnostics::record_subscription_plan(
self : ProgramRuntimeDiagnostics,
summary : SubscriptionPlanSummary,
) -> Unit {
self.subscription_plan_count = self.subscription_plan_count + 1
self.record_duplicate_subscription_keys(summary.duplicate_keys)
self.last_subscription_plan_summary = summary
}
///|
fn ProgramRuntimeDiagnostics::record_duplicate_subscription_keys(
self : ProgramRuntimeDiagnostics,
keys : Array[String],
) -> Unit {
for key in keys {
if !self.duplicate_subscription_keys.any(existing => existing == key) {
self.duplicate_subscription_keys.push(key)
}
}
}
///|
fn ProgramRuntimeDiagnostics::record_ignored_subscription_dispatch(
self : ProgramRuntimeDiagnostics,
) -> Unit {
self.ignored_subscription_dispatch_count = self.ignored_subscription_dispatch_count +
1
}
///|
fn[Msg] ProgramRuntimeDiagnostics::sync_subscriptions(
self : ProgramRuntimeDiagnostics,
subscription : @core.Subscription[Msg],
dispatch : (Msg) -> Unit,
) -> Unit {
self.record_subscription_plan(subscription_plan_summary(subscription))
let next : Array[ActiveProgramSubscription] = []
let seen_keys : Array[String] = []
for active in self.active_subscriptions {
active.reused = false
}
for source in subscription.runtime_sources() {
if seen_keys.any(key => key == source.key()) {
self.duplicate_subscription_key_count = self.duplicate_subscription_key_count +
1
continue
}
seen_keys.push(source.key())
match self.reusable_subscription(source.key(), source.kind()) {
Some(active) => {
active.reused = true
active.kind = source.kind()
active.label = source.label()
active.descriptor = source.descriptor()
self.reused_subscription_count = self.reused_subscription_count + 1
next.push(active)
}
None => next.push(self.start_subscription(source, dispatch))
}
}
for active in self.active_subscriptions {
if !active.reused {
self.cancel_subscription(active, subscription_cancel_reason(active, next))
}
}
self.active_subscriptions = next
}
///|
fn ProgramRuntimeDiagnostics::cancel_all_subscriptions(
self : ProgramRuntimeDiagnostics,
reason : SubscriptionCancelReason,
) -> Unit {
for active in self.active_subscriptions {
self.cancel_subscription(active, reason)
}
self.active_subscriptions = []
}
///|
fn ProgramRuntimeDiagnostics::reusable_subscription(
self : ProgramRuntimeDiagnostics,
key : String,
kind : String,
) -> ActiveProgramSubscription? {
for active in self.active_subscriptions {
if !active.reused && active.key == key && active.kind == kind {
return Some(active)
}
}
None
}
///|
fn subscription_cancel_reason(
active : ActiveProgramSubscription,
next : Array[ActiveProgramSubscription],
) -> SubscriptionCancelReason {
if next.any(subscription => subscription.key == active.key) {
SubscriptionKindChanged
} else {
SubscriptionKeyChanged
}
}
///|
fn[Msg] ProgramRuntimeDiagnostics::start_subscription(
self : ProgramRuntimeDiagnostics,
source : @core.SubscriptionRuntimeSource[Msg],
dispatch : (Msg) -> Unit,
) -> ActiveProgramSubscription {
let active = Ref(true)
let cancel = source.start(message => {
if active.val {
dispatch(message)
} else {
self.record_ignored_subscription_dispatch()
}
})
self.started_subscription_count = self.started_subscription_count + 1
self.subscription_lifecycle.push({
key: source.key(),
kind: source.kind(),
label: source.label(),
status: SubscriptionActive,
cancel_reason: None,
})
{
key: source.key(),
kind: source.kind(),
label: source.label(),
descriptor: source.descriptor(),
active,
cancel,
reused: true,
}
}
///|
fn ProgramRuntimeDiagnostics::cancel_subscription(
self : ProgramRuntimeDiagnostics,
active : ActiveProgramSubscription,
reason : SubscriptionCancelReason,
) -> Unit {
active.active.val = false
match active.cancel {
Some(cancel) => cancel()
None => ()
}
self.cancelled_subscription_count = self.cancelled_subscription_count + 1
self.subscription_lifecycle.push({
key: active.key,
kind: active.kind,
label: active.label,
status: SubscriptionCancelled,
cancel_reason: Some(reason),
})
}
///|
fn ProgramRuntimeDiagnostics::active_subscription_kind_counts(
self : ProgramRuntimeDiagnostics,
) -> Array[SubscriptionKindCount] {
let counts : Array[SubscriptionKindCount] = []
for active in self.active_subscriptions {
let mut found = false
for index, count in counts {
if count.kind == active.kind {
counts[index] = { ..count, count: count.count + 1, }
found = true
}
}
if !found {
counts.push({ kind: active.kind, count: 1, })
}
}
counts
}