///|
pub struct Subscription[Msg] {
priv node : SubscriptionNode[Msg]
}
///|
priv enum SubscriptionNode[Msg] {
SubscriptionNone
SubscriptionBatch(Array[Subscription[Msg]])
SubscriptionSource(SubscriptionSource[Msg])
}
///|
priv struct SubscriptionSource[Msg] {
key : String
kind : String
label : String
start : ((Msg) -> Unit) -> (() -> Unit)?
}
///|
pub struct SubscriptionRuntimeSource[Msg] {
priv source : SubscriptionSource[Msg]
}
///|
struct SubscriptionDescriptor {
key : String
kind : String
label : String
} derive(Eq, Debug, ToJson)
///|
pub fn SubscriptionDescriptor::key(self : SubscriptionDescriptor) -> String {
self.key
}
///|
pub fn SubscriptionDescriptor::kind(self : SubscriptionDescriptor) -> String {
self.kind
}
///|
pub fn SubscriptionDescriptor::label(self : SubscriptionDescriptor) -> String {
self.label
}
///|
pub fn[Msg] Subscription::none() -> Subscription[Msg] {
{ node: SubscriptionNone }
}
///|
pub fn[Msg] Subscription::batch(
subscriptions : Array[Subscription[Msg]],
) -> Subscription[Msg] {
{ node: SubscriptionBatch(subscriptions) }
}
///|
pub fn[Msg] Subscription::run(
key~ : String,
start~ : ((Msg) -> Unit) -> (() -> Unit)?,
kind? : String = "custom",
label? : String = "",
) -> Subscription[Msg] {
Subscription::listen(key~, start~, kind~, label~)
}
///|
pub fn[Msg] Subscription::listen(
key~ : String,
start~ : ((Msg) -> Unit) -> (() -> Unit)?,
kind? : String = "custom",
label? : String = "",
) -> Subscription[Msg] {
{ node: SubscriptionSource({ key, kind, label, start }) }
}
///|
pub fn[Msg] Subscription::timer(
key~ : String,
start~ : ((Msg) -> Unit) -> (() -> Unit)?,
label? : String = "",
) -> Subscription[Msg] {
Subscription::listen(key~, start~, kind="timer", label~)
}
///|
pub fn[Msg] Subscription::animation_tick(
key~ : String,
start~ : ((Msg) -> Unit) -> (() -> Unit)?,
label? : String = "",
) -> Subscription[Msg] {
Subscription::listen(key~, start~, kind="animation", label~)
}
///|
pub fn[Msg] Subscription::window_event(
key~ : String,
start~ : ((Msg) -> Unit) -> (() -> Unit)?,
label? : String = "",
) -> Subscription[Msg] {
Subscription::listen(key~, start~, kind="window-event", label~)
}
///|
pub fn[Msg] Subscription::host_event(
key~ : String,
start~ : ((Msg) -> Unit) -> (() -> Unit)?,
label? : String = "",
) -> Subscription[Msg] {
Subscription::listen(key~, start~, kind="host-event", label~)
}
///|
pub fn[Msg] Subscription::route_event(
key~ : String,
start~ : ((Msg) -> Unit) -> (() -> Unit)?,
label? : String = "",
) -> Subscription[Msg] {
Subscription::listen(key~, start~, kind="route-event", label~)
}
///|
pub fn[Msg, NextMsg] Subscription::map(
self : Subscription[Msg],
map : (Msg) -> NextMsg,
) -> Subscription[NextMsg] {
match self.node {
SubscriptionNone => Subscription::none()
SubscriptionBatch(subscriptions) =>
Subscription::batch(
subscriptions.map(subscription => subscription.map(map)),
)
SubscriptionSource(source) =>
Subscription::listen(
key=source.key,
kind=source.kind,
label=source.label,
start=dispatch => (source.start)(message => dispatch(map(message))),
)
}
}
///|
pub fn[Msg] Subscription::descriptors(
self : Subscription[Msg],
) -> Array[SubscriptionDescriptor] {
self.sources().map(source => source.descriptor())
}
///|
pub fn[Msg] Subscription::runtime_sources(
self : Subscription[Msg],
) -> Array[SubscriptionRuntimeSource[Msg]] {
self.sources().map(source => { source, })
}
///|
pub fn[Msg] SubscriptionRuntimeSource::key(
self : SubscriptionRuntimeSource[Msg],
) -> String {
self.source.key
}
///|
pub fn[Msg] SubscriptionRuntimeSource::kind(
self : SubscriptionRuntimeSource[Msg],
) -> String {
self.source.kind
}
///|
pub fn[Msg] SubscriptionRuntimeSource::label(
self : SubscriptionRuntimeSource[Msg],
) -> String {
self.source.label
}
///|
pub fn[Msg] SubscriptionRuntimeSource::descriptor(
self : SubscriptionRuntimeSource[Msg],
) -> SubscriptionDescriptor {
self.source.descriptor()
}
///|
pub fn[Msg] SubscriptionRuntimeSource::start(
self : SubscriptionRuntimeSource[Msg],
dispatch : (Msg) -> Unit,
) -> (() -> Unit)? {
(self.source.start)(dispatch)
}
///|
pub fn[Msg] Subscription::runtime_visit(
self : Subscription[Msg],
none : (Int) -> Unit,
batch : (Int, Int) -> Unit,
source : (Int, SubscriptionDescriptor) -> Unit,
) -> Unit {
self.runtime_visit_depth(0, none, batch, source)
}
///|
fn[Msg] Subscription::runtime_visit_depth(
self : Subscription[Msg],
depth : Int,
none : (Int) -> Unit,
batch : (Int, Int) -> Unit,
source : (Int, SubscriptionDescriptor) -> Unit,
) -> Unit {
match self.node {
SubscriptionNone => none(depth)
SubscriptionBatch(subscriptions) => {
batch(depth, subscriptions.length())
for subscription in subscriptions {
subscription.runtime_visit_depth(depth + 1, none, batch, source)
}
}
SubscriptionSource(subscription_source) =>
source(depth, subscription_source.descriptor())
}
}
///|
fn[Msg] Subscription::sources(
self : Subscription[Msg],
) -> Array[SubscriptionSource[Msg]] {
match self.node {
SubscriptionNone => []
SubscriptionBatch(subscriptions) => {
let sources : Array[SubscriptionSource[Msg]] = []
for subscription in subscriptions {
sources.append(subscription.sources())
}
sources
}
SubscriptionSource(source) => [source]
}
}
///|
fn[Msg] SubscriptionSource::descriptor(
self : SubscriptionSource[Msg],
) -> SubscriptionDescriptor {
{ key: self.key, kind: self.kind, label: self.label }
}