# Rumpk Adaptive I/O Governor
# War Mode (polling) ↔ Peace Mode (interrupts)

import ring

const
  POLL_BUDGET* = 2000           ## Cycles before switching to peace mode
  PEACE_TIMEOUT_NS* = 1_000_000 ## 1ms before checking again

type
  GovernorMode* = enum
    War,  ## High load: 100% CPU polling
    Peace ## Low load: Interrupt-driven

  IoGovernor*[T; N: static[int]] = object
    mode*: GovernorMode
    budget: int
    ring*: RingBuffer[T, N]

    # Callbacks (set by driver)
    hw_has_data*: proc(): bool {.nimcall.}
    hw_fetch*: proc(): T {.nimcall.}
    hw_enable_irq*: proc() {.nimcall.}
    hw_disable_irq*: proc() {.nimcall.}
    lwkt_yield*: proc() {.nimcall.}

proc init*[T; N: static[int]](gov: var IoGovernor[T, N]) =
  gov.mode = Peace
  gov.budget = POLL_BUDGET
  gov.ring.init()

proc tick*[T; N: static[int]](gov: var IoGovernor[T, N]) =
  ## Main driver loop iteration

  if gov.hw_has_data():
    # WAR MODE: Data available, stay aggressive
    let data = gov.hw_fetch()
    discard gov.ring.push(data)
    gov.budget = POLL_BUDGET
    gov.mode = War

  else:
    # Speculation window
    if gov.budget > 0:
      dec gov.budget
      # cpu_relax() equivalent - let other fibers run briefly

    else:
      # PEACE MODE: Budget exhausted, sleep
      gov.mode = Peace
      gov.hw_enable_irq()
      gov.lwkt_yield()

      # Woke up from interrupt
      gov.hw_disable_irq()
      gov.budget = POLL_BUDGET

proc run*[T; N: static[int]](gov: var IoGovernor[T, N]) {.noreturn.} =
  ## Infinite driver loop
  while true:
    gov.tick()
