plushie/runtime_core
Shared pure functions used by both BEAM and JS runtimes.
These functions contain the core logic for the Elm update loop: event coalescing, subscription key generation, window detection, window prop extraction, and Event -> msg mapping.
Extracting these into a shared module eliminates duplication between runtime.gleam (OTP actor) and runtime_web.gleam (callback-driven JS loop).
Values
pub fn coalesce_key(ev: event.Event) -> option.Option(String)
Determine the coalesce key for an event, if coalescable.
High-frequency events (mouse moves, sensor resizes) are deferred and only the latest value per key is kept. Returns None for events that should be dispatched immediately.
pub fn derive_all(
tree_node: node.Node,
) -> #(dict.Dict(String, widget.RegistryEntry), set.Set(String))
Derive both the widget registry and window set from a single tree walk.
Prefer using the registry and windows returned by
tree.normalize_view / tree.normalize_with_memo which accumulate
both during normalization at no extra cost. This function exists
for cases where only a pre-normalized tree is available.
pub fn describe_diagnostic(diag: event.Diagnostic) -> String
Short human-readable rendering of a typed diagnostic variant, used for log lines. Matches the tag the renderer emits on the wire so log scraping and telemetry stay consistent.
pub fn detect_windows(tree_node: node.Node) -> set.Set(String)
Detect window nodes in the tree.
Searches the entire tree recursively, matching the renderer’s behavior. Nested window nodes inside containers or layout widgets are properly detected.
pub const dispatch_depth_limit: Int
Maximum synchronous Command.dispatch chain depth before the
runtime guard fires.
Command.dispatch schedules a follow-up msg back through the
runtime; a pathological update that keeps returning another
dispatch would fill the mailbox (BEAM) or pump the microtask
queue (JS) indefinitely. Past this cap, the runtime drops the
command and emits a typed DispatchLoopExceeded diagnostic so
the loop is visible.
pub fn extract_window_props(
tree_node: node.Node,
window_id: String,
) -> dict.Dict(String, node.PropValue)
Extract the tracked window props from a window node found in the tree.
pub fn find_window_node(
tree_node: node.Node,
window_id: String,
) -> option.Option(node.Node)
Recursively search the tree for a window node with the given ID.
pub fn map_event(
app: app.App(model, msg),
event: event.Event,
) -> msg
Map a wire Event to the app’s msg type.
For simple() apps (on_event=None), msg is Event and we coerce
directly. For application() apps, the on_event callback maps
Event -> msg.
pub fn resolve_dispatch(
result: widget.DispatchResult,
) -> option.Option(event.Event)
Resolve a canvas widget dispatch result into an optional event for the app. Canvas-internal events that passed through widget handlers without being intercepted are auto-consumed so they don’t leak to the app’s update function.
Dispatched(None): consumed by a handlerDispatched(Some(ev)): passed through; auto-consume if event passed through all handlersBypassed(ev): no handlers in scope; always deliver
pub fn subscription_key_string(
sub: subscription.Subscription,
) -> String
Convert a Subscription to a unique string key for diffing.
Timer subscriptions are keyed by interval + tag. Renderer subscriptions are keyed by kind + window_id.
pub const window_prop_keys: List(String)
Window prop keys tracked for lifecycle sync. When a window node has any of these props and they change, an update op is sent.