; Benchmark scaffold fixture for local-machine enum-struct-payload timing
; comparisons only. Keep LOOP_COUNT and EXPECTED_CHECKSUM aligned with the
; C/Rust/Python fixtures. The runner supplies the loop count through stdin or
; argv so native compilers cannot fold the benchmark loop into a constant
; answer.

(module main)

(struct Packet
  (digits (array i32 8)))

(enum PacketState
  Missing
  (Live Packet)
  (Cached Packet))

(fn loop_count () -> i32
  1000000)

(fn expected_checksum () -> i32
  3500013)

(fn parse_stdin_loop_count () -> (result i32 i32)
  (let input (result string i32) (std.io.read_stdin_result))
  (match input
    ((ok text)
      (std.string.parse_i32_result text))
    ((err code)
      (err i32 i32 code))))

(fn parse_arg_loop_count () -> (result i32 i32)
  (std.string.parse_i32_result (std.process.arg 1)))

(fn configured_stdin_loop_count () -> i32
  (let parsed_stdin (result i32 i32) (parse_stdin_loop_count))
  (if (is_ok parsed_stdin)
    (unwrap_ok parsed_stdin)
    (loop_count)))

(fn configured_loop_count () -> i32
  (let parsed_arg (result i32 i32) (parse_arg_loop_count))
  (if (is_ok parsed_arg)
    (unwrap_ok parsed_arg)
    (configured_stdin_loop_count)))

(fn live_digits () -> (array i32 8)
  (array i32 2 7 1 8 2 8 1 8))

(fn cached_digits () -> (array i32 8)
  (array i32 1 6 1 8 0 3 4 5))

(fn live_state () -> PacketState
  (PacketState.Live (Packet (digits (live_digits)))))

(fn cached_state () -> PacketState
  (PacketState.Cached (Packet (digits (cached_digits)))))

(fn select_state ((i i32) (live PacketState) (cached PacketState)) -> PacketState
  (if (= (% i 2) 0)
    live
    cached))

(fn state_digit ((state PacketState) (i i32)) -> i32
  (match state
    ((PacketState.Missing)
      0)
    ((PacketState.Live payload)
      (index (. payload digits) i))
    ((PacketState.Cached payload)
      (index (. payload digits) i))))

(fn enum_struct_payload_loop ((limit i32)) -> i32
  (let live PacketState (live_state))
  (let cached PacketState (cached_state))
  (var i i32 0)
  (var acc i32 13)
  (while (< i limit)
    (set acc (+ acc (state_digit (select_state i live cached) (% i 8))))
    (set acc (if (> acc 1000000000)
      (- acc 1000000000)
      acc))
    (set i (+ i 1)))
  acc)

(fn main () -> i32
  (let result i32 (enum_struct_payload_loop (configured_loop_count)))
  (std.io.print_i32 result)
  (if (= result (expected_checksum))
    0
    1))

(test "enum struct payload loop checksum is deterministic"
  (= (enum_struct_payload_loop (loop_count)) (expected_checksum)))
