;; lib/go/sched.sx — Go scheduler primitives: channels + goroutines.
;;
;; This is **the independent implementation** referenced by
;; plans/lib-guest-scheduler.md. The shape that emerges here informs
;; the eventual sister kit; this file's structures are the Phase 5
;; "first-consumer" cut.
;;
;; v0 concurrency model — IMPORTANT
;;
;; SX has no first-class continuations exposed to guest code, so we
;; can't suspend a goroutine mid-statement. v0 runs `go f()` SYNCHRO-
;; NOUSLY (it's an immediate call whose return value is dropped). This
;; preserves the right semantics for patterns where the spawned
;; goroutine simply pushes to a channel that the main goroutine then
;; receives — because the spawned goroutine runs to completion first
;; and leaves the value in the channel buffer.
;;
;; True preemption with blocking sends/recvs is a Phase 5b refinement.
;; The sister-plan diary tracks the design insight (single
;; sched-spawn primitive, channel-op direction tag) so the eventual
;; kit doesn't bake in v0's synchronous limitation.
;;
;; Channel representation
;;
;;   (list :go-chan ACCESSORS-FN-LIST)
;;
;; ACCESSORS-FN-LIST is a list of closures sharing a mutable buffer
;; and a closed flag. The closures expose:
;;   index 1: send-fn     — (lambda (val) ...)
;;   index 2: recv-fn     — (lambda () val-or-:empty)
;;   index 3: closed?-fn  — (lambda () bool)
;;   index 4: close!-fn   — (lambda () ...)
;;
;; Channel identity: distinct calls to go-make-chan produce closures
;; with distinct identity — `(= ch1 ch2)` is false for distinct
;; channels, matching Go spec § Channel types.

(define
  go-make-chan
  (fn
    ()
    (let
      ((buf (list)) (closed false))
      (list
        :go-chan (fn (v) (append! buf v) nil)
        (fn
          ()
          (cond
            (= (len buf) 0)
            :empty :else
            (let ((v (first buf))) (set! buf (rest buf)) v)))
        (fn () closed)
        (fn () (set! closed true) nil)
        (fn () (len buf))))))

(define
  go-chan?
  (fn
    (v)
    (and (list? v) (not (= (len v) 0)) (= (first v) :go-chan))))

(define go-chan-send! (fn (ch val) ((nth ch 1) val)))
(define go-chan-recv! (fn (ch) ((nth ch 2))))
(define go-chan-closed? (fn (ch) ((nth ch 3))))
(define go-chan-close! (fn (ch) ((nth ch 4))))
(define go-chan-len    (fn (ch) ((nth ch 5))))
