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
|
Channel* = ref object
|
||||||
buf: Deque[CljVal]
|
buf: Deque[CljVal]
|
||||||
capacity: int # 0 = unbuffered
|
capacity: int # 0 = unbuffered
|
||||||
|
closed*: bool
|
||||||
|
|
||||||
var channelRegistry* = initTable[string, Channel]()
|
var channelRegistry* = initTable[string, Channel]()
|
||||||
var channelCounter*: int64 = 0
|
var channelCounter*: int64 = 0
|
||||||
@@ -1074,7 +1075,7 @@ proc evalList(items: seq[CljVal], env: Env): EvalResult =
|
|||||||
channelCounter += 1
|
channelCounter += 1
|
||||||
let id = "chan_" & $channelCounter
|
let id = "chan_" & $channelCounter
|
||||||
let cap = if args.len > 0 and args[0].kind == ckInt: args[0].intVal.int else: 0
|
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
|
channelRegistry[id] = ch
|
||||||
return EvalResult(ok: true, value: cljString(id))
|
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):
|
if args[0].kind != ckString or not channelRegistry.hasKey(args[0].strVal):
|
||||||
return EvalResult(ok: false, error: "put!/<! requires a channel")
|
return EvalResult(ok: false, error: "put!/<! requires a channel")
|
||||||
let ch = channelRegistry[args[0].strVal]
|
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:
|
if ch.capacity > 0 and ch.buf.len >= ch.capacity:
|
||||||
return EvalResult(ok: false, error: "Channel buffer full")
|
return EvalResult(ok: false, error: "Channel buffer full")
|
||||||
ch.buf.addLast(args[1])
|
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")
|
return EvalResult(ok: false, error: "take!/<! requires a channel")
|
||||||
let ch = channelRegistry[args[0].strVal]
|
let ch = channelRegistry[args[0].strVal]
|
||||||
if ch.buf.len == 0:
|
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: cljNil())
|
||||||
return EvalResult(ok: true, value: ch.buf.popFirst())
|
return EvalResult(ok: true, value: ch.buf.popFirst())
|
||||||
|
|
||||||
@@ -1101,7 +1106,8 @@ proc evalList(items: seq[CljVal], env: Env): EvalResult =
|
|||||||
numArgs(1)
|
numArgs(1)
|
||||||
if args[0].kind != ckString or not channelRegistry.hasKey(args[0].strVal):
|
if args[0].kind != ckString or not channelRegistry.hasKey(args[0].strVal):
|
||||||
return EvalResult(ok: false, error: "close! requires a channel")
|
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())
|
return EvalResult(ok: true, value: cljNil())
|
||||||
|
|
||||||
of "go":
|
of "go":
|
||||||
|
|||||||
Reference in New Issue
Block a user