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 handler
  • Dispatched(Some(ev)): passed through; auto-consume if event passed through all handlers
  • Bypassed(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.

Search Document