use crate::{atomic::Ordering, spmc::queue::QueuePtr};
pub struct Sender<T> {
ptr: QueuePtr<T>,
local_tail: usize,
}
impl<T> Sender<T> {
pub(crate) fn new(queue_ptr: QueuePtr<T>) -> Self {
Self {
ptr: queue_ptr,
local_tail: 0,
}
}
pub fn send(&mut self, value: T) {
self.send_with_spin_count(value, 128);
}
pub fn send_with_spin_count(&mut self, value: T, spin_count: u32) {
let cell = self.ptr.cell_at(self.local_tail);
let mut backoff = crate::Backoff::with_spin_count(spin_count);
while cell.epoch().load(Ordering::Acquire) != self.local_tail {
backoff.backoff();
}
let next = self.local_tail.wrapping_add(1);
cell.set(value);
cell.epoch().store(next, Ordering::Release);
self.local_tail = next;
}
pub fn try_send(&mut self, value: T) -> Result<(), T> {
let cell = self.ptr.cell_at(self.local_tail);
if cell.epoch().load(Ordering::Acquire) != self.local_tail {
return Err(value);
}
let next = self.local_tail.wrapping_add(1);
cell.set(value);
cell.epoch().store(next, Ordering::Release);
self.local_tail = next;
Ok(())
}
}
unsafe impl<T: Send> Send for Sender<T> {}