Fix: channels now support drain-after-close (close! marks closed, <! returns nil on exhausted closed channel, >! rejects on closed)
This commit is contained in:
+8
-2
@@ -10,6 +10,7 @@ type
|
||||
Channel* = ref object
|
||||
buf: Deque[CljVal]
|
||||
capacity: int # 0 = unbuffered
|
||||
closed*: bool
|
||||
|
||||
var channelRegistry* = initTable[string, Channel]()
|
||||
var channelCounter*: int64 = 0
|
||||
@@ -1074,7 +1075,7 @@ proc evalList(items: seq[CljVal], env: Env): EvalResult =
|
||||
channelCounter += 1
|
||||
let id = "chan_" & $channelCounter
|
||||
let cap = if args.len > 0 and args[0].kind == ckInt: args[0].intVal.int else: 0
|
||||
let ch = Channel(buf: initDeque[CljVal](), capacity: cap)
|
||||
let ch = Channel(buf: initDeque[CljVal](), capacity: cap, closed: false)
|
||||
channelRegistry[id] = ch
|
||||
return EvalResult(ok: true, value: cljString(id))
|
||||
|
||||
@@ -1083,6 +1084,8 @@ proc evalList(items: seq[CljVal], env: Env): EvalResult =
|
||||
if args[0].kind != ckString or not channelRegistry.hasKey(args[0].strVal):
|
||||
return EvalResult(ok: false, error: "put!/<! requires a channel")
|
||||
let ch = channelRegistry[args[0].strVal]
|
||||
if ch.closed:
|
||||
return EvalResult(ok: false, error: "Channel is closed")
|
||||
if ch.capacity > 0 and ch.buf.len >= ch.capacity:
|
||||
return EvalResult(ok: false, error: "Channel buffer full")
|
||||
ch.buf.addLast(args[1])
|
||||
@@ -1094,6 +1097,8 @@ proc evalList(items: seq[CljVal], env: Env): EvalResult =
|
||||
return EvalResult(ok: false, error: "take!/<! requires a channel")
|
||||
let ch = channelRegistry[args[0].strVal]
|
||||
if ch.buf.len == 0:
|
||||
if ch.closed:
|
||||
return EvalResult(ok: true, value: cljNil())
|
||||
return EvalResult(ok: true, value: cljNil())
|
||||
return EvalResult(ok: true, value: ch.buf.popFirst())
|
||||
|
||||
@@ -1101,7 +1106,8 @@ proc evalList(items: seq[CljVal], env: Env): EvalResult =
|
||||
numArgs(1)
|
||||
if args[0].kind != ckString or not channelRegistry.hasKey(args[0].strVal):
|
||||
return EvalResult(ok: false, error: "close! requires a channel")
|
||||
channelRegistry.del(args[0].strVal)
|
||||
let ch = channelRegistry[args[0].strVal]
|
||||
ch.closed = true
|
||||
return EvalResult(ok: true, value: cljNil())
|
||||
|
||||
of "go":
|
||||
|
||||
Reference in New Issue
Block a user