| Title: | Single-Producer Single-Consumer Channels |
|---|---|
| Description: | Provides a single-producer single-consumer channel with bounded capacity, optional timeouts on receives, and sentinel return values for full, timeout, and closed states. The ring buffer is implemented in C: sends and receives are constant-time operations, values are delivered in first-in first-out order, and a closed channel drains its buffered values before reporting the closed state. The transport is in-process: both ends of a channel live in the calling R process, which suits the channel to prototyping producer and consumer designs and to testing channel-based logic. |
| Authors: | Charlie Gao [aut, cre] (ORCID: <https://orcid.org/0000-0002-0750-061X>), Posit Software, PBC [cph, fnd] (ROR: <https://ror.org/03wc8by49>) |
| Maintainer: | Charlie Gao <[email protected]> |
| License: | MIT + file LICENSE |
| Version: | 0.0.1 |
| Built: | 2026-09-30 14:09:24 UTC |
| Source: | https://github.com/cran/mizu |
Singletons returned by mizu_send() and mizu_recv() that
tag the terminal states of a channel as ordinary values, not signalled
conditions, so hot loops stay branch-cheap. Dispatch with inherits(x, "mizu_sentinel") or on the specific class; use
mizu_is_sentinel() where payloads are untrusted.
mizu_full mizu_timeout mizu_closedmizu_full mizu_timeout mizu_closed
mizu_full — the buffer is at capacity (mizu_send()).
mizu_timeout — no value arrived within timeout
(mizu_recv()).
mizu_closed — the channel is closed and drained
(mizu_inproc_close()).
Creates a single-producer single-consumer channel: a bounded ring buffer
that holds up to capacity values until they are received. The ring
buffer is implemented in C, with O(1) sends and receives. The transport
is in-process — both ends of the channel live in the calling R process.
mizu_inproc_channel(capacity)mizu_inproc_channel(capacity)
capacity |
a positive integer: the number of values the channel
buffers before |
This interface is experimental and may change in a future release.
A channel (class "mizu_inproc_channel").
ch <- mizu_inproc_channel(2) mizu_send(ch, "a") mizu_send(ch, 42) mizu_recv(ch) mizu_recv(ch) mizu_inproc_close(ch)ch <- mizu_inproc_channel(2) mizu_send(ch, "a") mizu_send(ch, 42) mizu_recv(ch) mizu_recv(ch) mizu_inproc_close(ch)
Orderly shutdown. Values buffered before the close remain receivable;
further sends return the mizu_closed sentinel, and a receive on a
drained channel returns the same. Closing an already-closed channel is a
no-op.
mizu_inproc_close(ch)mizu_inproc_close(ch)
ch |
a channel from |
Invisibly, TRUE.
ch <- mizu_inproc_channel(1) mizu_send(ch, "a") mizu_inproc_close(ch) mizu_recv(ch) mizu_recv(ch)ch <- mizu_inproc_channel(1) mizu_send(ch, "a") mizu_inproc_close(ch) mizu_recv(ch) mizu_recv(ch)
Identity comparison against the interned sentinel singletons —
mizu_full, mizu_timeout, and mizu_closed — that
the verbs of mizu return to tag terminal states. inherits(x, "mizu_sentinel") tests the class alone, which any payload can
carry. This includes a genuine sentinel forwarded over a channel, which
arrives as an ordinary copy. mizu_is_sentinel() is provenance: TRUE
only for the exact objects that the own calls of mizu return. So code
that relays untrusted values can distinguish its terminal states from
look-alike payloads.
mizu_is_sentinel(x)mizu_is_sentinel(x)
x |
any R object. |
Sentinels are ordinary values, not R conditions: nothing is signalled, and condition handlers never see them.
TRUE or FALSE.
ch <- mizu_inproc_channel(1) x <- mizu_recv(ch, timeout = 0) mizu_is_sentinel(x) mizu_is_sentinel(42) # class alone does not make a sentinel: mizu_is_sentinel( structure("x", class = c("mizu_timeout", "mizu_sentinel")) ) mizu_inproc_close(ch)ch <- mizu_inproc_channel(1) x <- mizu_recv(ch, timeout = 0) mizu_is_sentinel(x) mizu_is_sentinel(42) # class alone does not make a sentinel: mizu_is_sentinel( structure("x", class = c("mizu_timeout", "mizu_sentinel")) ) mizu_inproc_close(ch)
mizu_send() appends x to the buffer of the channel. Sends never
block: a send on a full channel returns the mizu_full sentinel
immediately. mizu_recv() removes and returns the oldest buffered
value, waiting up to timeout seconds for one to arrive.
mizu_send(ch, x) mizu_recv(ch, timeout = Inf)mizu_send(ch, x) mizu_recv(ch, timeout = Inf)
ch |
a channel from |
x |
the payload: any R object. |
timeout |
seconds to wait before the call returns the
|
Terminal states surface as class-tagged sentinels, not errors. Dispatch
with inherits(x, "mizu_sentinel"), or on the specific classes:
mizu_full — the buffer is at capacity (send). Receive first, or
drop the value.
mizu_timeout — no value arrived within timeout (recv).
mizu_closed — the channel was closed with
mizu_inproc_close(). A receive drains all buffered values before it
reports this.
NULL is a legal payload. Sentinels are ordinary values, identifiable by
class alone, and never signalled conditions. mizu_is_sentinel()
checks identity where payloads are untrusted.
mizu_send() returns TRUE (invisibly) on success, or a
sentinel otherwise. mizu_recv() returns the received value or a
sentinel.
ch <- mizu_inproc_channel(1) mizu_send(ch, "a") mizu_send(ch, "b") # full: returns the mizu_full sentinel mizu_recv(ch) mizu_recv(ch, timeout = 0) mizu_inproc_close(ch)ch <- mizu_inproc_channel(1) mizu_send(ch, "a") mizu_send(ch, "b") # full: returns the mizu_full sentinel mizu_recv(ch) mizu_recv(ch, timeout = 0) mizu_inproc_close(ch)
One-line summaries. A channel prints its state — open or closed —
and the number of buffered values out of its capacity. Sentinels print as
their class. The methods never error, so auto-printing is always safe.
## S3 method for class 'mizu_inproc_channel' print(x, ...) ## S3 method for class 'mizu_sentinel' print(x, ...)## S3 method for class 'mizu_inproc_channel' print(x, ...) ## S3 method for class 'mizu_sentinel' print(x, ...)
x |
the object. |
... |
ignored. |
x, invisibly.
ch <- mizu_inproc_channel(2) ch mizu_send(ch, "a") ch mizu_inproc_close(ch)ch <- mizu_inproc_channel(2) ch mizu_send(ch, "a") ch mizu_inproc_close(ch)