mpsc
import std::sync::mpsc; · source
channel
function channel<T>() -> Receiver<T>;
channel<T>() returns the owning Receiver<T>; mint producers from it with rx.sender(). Each Sender<T> is independently owned and movable into its own thread, and cloneable for further fan-out. Values of any type — including owned data like String — move through an unbounded FIFO queue.
import std::sync::mpsc;
import std::thread;
mut rx: mpsc::Receiver<i32> = mpsc::channel<i32>();
const tx: mpsc::Sender<i32> = rx.sender();
const h = thread::spawn<mpsc::Sender<i32>, i32>(tx, (s: mpsc::Sender<i32>) -> i32 {
mut snd: mpsc::Sender<i32> = s;
snd.send(42);
snd.close();
return 0;
});
match (rx.recv()) {
Result::Ok(v) => { use(v); }
Result::Err(_) => { }
}
h.join();
Sender<T>
type struct Sender<T> {
inner: ChannelInner<T>*;
send(&this, value: T) -> Result<(), SendError<T>>;
clone(&this) -> Sender<T>;
close(mut this) -> void;
}
send moves a value into the queue. clone() mints another producer; close() consumes the sender and is equivalent to dropping it early.
Receiver<T>
type struct Receiver<T> {
inner: ChannelInner<T>*;
sender(&this) -> Sender<T>;
recv(&this) -> Result<T, RecvError>;
try_recv(&this) -> Result<T, TryRecvError>;
}
recv() blocks; try_recv() returns Err(Empty) immediately when nothing is queued. sender() mints producers from the receiver, which is why channel returns only the receiver.
The errors
type struct SendError<T> {
value: T;
}
type enum RecvError {
Disconnected;
}
type enum TryRecvError {
Empty;
Disconnected;
}
Disconnection
When every Sender has been dropped, a blocked recv() returns Err(RecvError::Disconnected) and try_recv() returns Err(TryRecvError::Disconnected).
When the Receiver is dropped, send() returns Err(SendError) handing the value back, rather than queueing into a channel nobody will drain.
Underneath, a heap inner holds a mutex and condition variable guarding a raw singly-linked node queue, plus a live-sender count and a total-handle refcount; the inner is reclaimed when the last handle of either kind drops. Values move out of dequeued nodes through raw pointers, so the move-checker sees each as a clean transfer — no aliasing, no double free.
Trait implementations
implement<T> trait Drop for struct Sender<T>
implement<T> trait Drop for struct Receiver<T>
where T: Drop
Receiver::drop drains and drops whatever is still queued, which is why it carries the T: Drop bound.