use std::sync::Arc;
use rtrb::PushError;
pub fn sp2c<T>() -> (Sp2cSender<T>, Sp2cReceiver<T>, Sp2cStealer<T>) {
let ring = rtrb::RingBuffer::new(512);
let (send, recv) = ring.split();
let recv = Arc::new(spin::Mutex::new(recv));
let sender = Sp2cSender { send };
let receiver = Sp2cReceiver { recv: recv.clone() };
let stealer = Sp2cStealer { recv };
(sender, receiver, stealer)
}
pub struct Sp2cSender<T> {
send: rtrb::Producer<T>,
}
impl<T> Sp2cSender<T> {
#[inline]
pub fn send(&mut self, item: T) -> Result<(), T> {
self.send.push(item).map_err(|v| match v {
PushError::Full(v) => v,
})
}
#[inline]
pub fn slots(&mut self) -> usize {
self.send.slots()
}
}
pub struct Sp2cReceiver<T> {
recv: Arc<spin::Mutex<rtrb::Consumer<T>>>,
}
impl<T> Sp2cReceiver<T> {
#[inline]
pub fn pop(&mut self) -> Option<T> {
self.recv.lock().pop().ok()
}
}
pub struct Sp2cStealer<T> {
recv: Arc<spin::Mutex<rtrb::Consumer<T>>>,
}
impl<T> Sp2cStealer<T> {
pub fn steal_batch(&mut self, buf: &mut Vec<T>) -> Option<usize> {
let mut recv = self.recv.try_lock()?; let to_pop = recv.slots() / 2;
for _ in 0..to_pop {
buf.push(recv.pop().unwrap())
}
Some(to_pop)
}
}