diff options
-rw-r--r-- | stream.c | 13 | ||||
-rw-r--r-- | tests/018/close-delegate.expected | 5 | ||||
-rw-r--r-- | tests/018/close-delegate.tl | 20 | ||||
-rw-r--r-- | txr.1 | 36 |
4 files changed, 70 insertions, 4 deletions
@@ -2990,11 +2990,18 @@ val close_stream(val stream, val throw_on_error) struct strm_base *s = coerce(struct strm_base *, cobj_handle(self, stream, stream_cls)); struct strm_ops *ops = coerce(struct strm_ops *, stream->co.ops); + val res = s->close_result; - if (!s->close_result) - s->close_result = ops->close(stream, throw_on_error); + if (!res) { + res = ops->close(stream, throw_on_error); - return s->close_result; + if (res == colon_k) + res = t; + else if (res) + s->close_result = res; + } + + return res; } val get_error(val stream) diff --git a/tests/018/close-delegate.expected b/tests/018/close-delegate.expected index 227f9f67..de68447f 100644 --- a/tests/018/close-delegate.expected +++ b/tests/018/close-delegate.expected @@ -1,3 +1,6 @@ close called, count 2 close called, count 1 -20 +40 +close called, count 2 +close called, count 1 +40 diff --git a/tests/018/close-delegate.tl b/tests/018/close-delegate.tl index 4cf1d650..64a1dc91 100644 --- a/tests/018/close-delegate.tl +++ b/tests/018/close-delegate.tl @@ -18,3 +18,23 @@ (get-lines s)) len prinl) + +(defstruct refcount-close-alt stream-wrap + stream + (count 1) + + (:method close (me throw-on-error-p) + (put-line `close called, count @{me.count}`) + (when (plusp me.count) + (if (zerop (dec me.count)) + (close-stream me.stream throw-on-error-p) + :)))) + +(flow + (with-stream (s (make-struct-delegate-stream + (new refcount-close-alt + count 2 + stream (open-file *load-path*)))) + (get-lines s)) + len + prinl) @@ -65783,6 +65783,42 @@ description of the .code close-stream stream I/O function. +With two exceptions, the value returned from +.code close +is retained by close-stream, such that repeated calls to +.code close-stream +then return that value without calling the +.code close +method. +The exceptions are the values +.code nil +and +.code : +(the colon symbol). +If either of these values is returned, and +.code close-stream +is invoked again on the same stream object, the +.code close +method will be called again. + +Furthermore, if the +.code : +symbol is returned by the +.code close +method, this indicates a successful close, and the +.code close-stream +function returns the +.code t +symbol rather than the +.code : +symbol. + +The rationale for this mechanism is that it supports reference-counted +closing. A struct delegate stream may be written which is shared by +several owners, which must each call +.code close-stream +before the underlying real stream is closed. + .coNP Method @ flush .synb .mets << stream .(flush < offs << whence ) |