(import (scheme base))

(include "tmc-part4.scm")

(define N 2)

;; ringbuffer helpers ----
(define (bufx i)
  (cons 'buf (modulo i N)))

(define (buf-ref i)
  (READ (bufx i)))

(define (buf-set! i v)
  (WRITE (bufx i) v))

;; initialization ----
(INIT 'head 0)
(INIT 'tail 0)

;; The following (do ...) form is equivalent to
;;    `for (i = 0; i < N; i++)`
(do ((i 0 (+ i 1))) ((= i N))
    (INIT (bufx i) 'EMPTY))


;; ring buffer implementation ----
(define (ring-enq v)
  (let ((tail (READ 'tail))
        (head (READ 'head)))
    (if (= (- tail head) N)
        'FULL
        (begin
          (buf-set! tail v)
          (WRITE 'tail (+ tail 1))
          'OK))))

(define (ring-deq)
  (let ((head (READ 'head))
        (tail (READ 'tail)))
    (if (= (- tail head) 0)
        (values 'EMPTY #f)
        (let ((val (buf-ref head)))
          (WRITE 'head (+ head 1))
          (values 'OK val)))))

;; client code ----
(define (producer)
  (ring-enq 1)
  (ring-enq 2)
  (ring-enq 3))

(define (consumer)
  (let loop ((expected 1))
    (let-values (((status val) (ring-deq)))
      (when (eq? status 'OK)
        (ASSERT (= val expected) "FIFO order")
        (loop (+ expected 1))))))

;; spawn tasks and explore
(SPAWN producer)
(SPAWN consumer)
(EXPLORE)

