pub struct SpscRing<T> { /* private fields */ }Expand description
A bounded SPSC ring buffer owned in place, split into borrowing halves.
use moirai_core::channel::{Consumer, Producer, SpscRing};
let mut ring = SpscRing::<u64>::new(64);
let (tx, rx) = ring.split();
std::thread::scope(|scope| {
scope.spawn(move || {
for value in 0..1000 {
if tx.send(value).is_err() {
break;
}
}
});
let mut sum = 0;
for _ in 0..1000 {
match rx.recv() {
Ok(value) => sum += value,
Err(_) => break,
}
}
assert_eq!(sum, (0..1000).sum::<u64>());
});Implementations§
Source§impl<T> SpscRing<T>where
T: Send,
impl<T> SpscRing<T>where
T: Send,
Sourcepub fn new(capacity: usize) -> SpscRing<T>
pub fn new(capacity: usize) -> SpscRing<T>
Create a ring with at least capacity slots, rounded up to a power of
two so the index-to-slot mapping is a mask rather than a division.
Sourcepub fn split(&mut self) -> (SpscProducer<'_, T>, SpscConsumer<'_, T>)
pub fn split(&mut self) -> (SpscProducer<'_, T>, SpscConsumer<'_, T>)
Borrow the ring as a producer and a consumer.
Both halves borrow self, so the ring cannot be split again, moved, or
dropped until they are.
A ring may be split again once its previous halves are gone. Values left queued by an earlier round stay queued — the counters are not reset — which is what makes a ring reusable across phases without reallocating.
Two details make re-splitting sound, and both are why the caches are seeded from the live counters rather than from zero:
closedis cleared. A half sets it on drop so its peer stops blocking; leaving it set would make the next round’s first operation fail immediately.- The consumer’s cache must satisfy
tail <= cached_head <= head. A zeroedcached_headagainst a non-zerotailbreaks the left side, andhas_valuewould then report a value present in an empty ring and read a slot that was never written. Seeding fromheadrestores it; seeding the producer’s cache fromtailis exact for the same reason.
Taking &mut self is what makes this safe to do without atomics: no
half exists, so nothing else can be touching either counter.