schan
session-typed channel wrappers over a linear opaque handle.
SChan<p> is a thin generic wrapper over a synchronous blocking channel that carries a protocol phantom p. Each operation advances the phantom:
schan-send : SChan<SSend T R> -> T -> SChan<R> schan-recv : SChan<SRecv T R> -> (Pair T SChan<R>) schan-close : SChan<SClose> -> nil
The phantom is threaded through the result type, so a caller cannot skip a step or reorder send/recv: doing so is a compile-time type error (TUR-E0001 phantom mismatch). Combined with the :linear discipline (under -Xlinear), every protocol step happens exactly once and in order.
(The plan's ideal schan-recv : SChan<SRecv T R> -> Pair<T SChan<R>> is blocked by a monomorphizer limitation around parametric aggregates whose element type is a phantom carried inside an opaque -- see schan-recv's docstring and docs/archive/history/generic-struct-opaque-element-miscompile.md. recv therefore returns the typed continuation directly and delivers the received value through a caller-provided cell, which keeps the continuation protocol fully checked.)
The wrapper operations carry their channel work directly as inline-C over the opaque carrier (the phantom is erased at the C ABI), so the typed surface adds no runtime overhead beyond the underlying channel. The low-level tur/chan keeps its untyped surface for callers that do not want the protocol discipline.
Since: S1
SSend
(defopaque SSend [T R] :int)
protocol step: send a value of type T, then continue as R.
SRecv
(defopaque SRecv [T R] :int)
protocol step: receive a value of type T, then continue as R.
SClose
(defopaque SClose :int)
protocol terminus: the channel is closed.
SChan
(defopaque SChan [P] :ptr<void> :linear)
a linear channel handle carrying a protocol phantom P.
Lowers to the underlying :ptr<void> channel in the C ABI; the phantom P is erased at runtime. :linear so the protocol cannot be replayed: each operation consumes the handle and yields the continuation at the next step.
Since: S1
schan-new
(schan-new [P])
open a session-typed channel running protocol P.
| cap | ring-buffer capacity (>= 1) |
A fresh SChan<P>. The protocol P is fixed by the call site's expected type (or an ascription).
(:: (schan-new 4) (SChan (SSend int SClose))) ; => SChan<SSend int SClose>
Since: S1
schan-send
(schan-send [T R])
send a T over a channel whose protocol begins with SSend T R.
| c | channel at protocol SSend<T R> (consumed) | |
| v | the value to send |
The same channel, advanced to protocol R.
(let [c2 (schan-send c 42)] ...) ; c : SChan<SSend int R> => c2 : SChan<R>
Since: S1
schan-recv
(schan-recv [T R])
schan-close
(schan-close [c :(SChan SClose)] :nil)
close a channel whose protocol has reached SClose.
| c | channel at protocol SClose (consumed) |
nil. The underlying channel is freed.
(schan-close c) ; c : SChan<SClose>
Since: S1
Internal definitions
schan-recv-value-- receive a T from a channel whose protocol begins with SRecv T R.schan-advance-recv-- internal: retag the channel from SRecv T R to R.