use crate::prelude::*;
use std::sync::{Arc, atomic::Ordering};
pub struct Sender<T> {
shared: Arc<State<T>>,
}
impl<T: Clone> Sender<T> {
pub(crate) fn new(shared: Arc<State<T>>) -> Self {
shared.num_writers.fetch_add(1, Ordering::Release);
Self { shared }
}
#[cfg(feature = "debug")]
pub fn debugger(&self) -> Debug<T> {
Debug {
shared: Arc::clone(&self.shared),
}
}
pub fn spawn_rx(&self) -> Receiver<T> {
Receiver::new(Arc::clone(&self.shared))
}
fn send_inner(&self, value: T, blocking: bool) -> Result<(), SendError<T>> {
if self.shared.num_readers.load(Ordering::Relaxed) == 0 {
return Err(SendError::Disconnected(value));
}
loop {
let mut tail_lock = self.shared.internal_tail.write().unwrap();
let fence = (tail_lock.0 + 1) % self.shared.len;
let required_reads = unsafe { (&*self.shared.ring[fence].state.get()).required_reads };
if required_reads
.saturating_sub(self.shared.ring[fence].num_reads.load(Ordering::SeqCst))
!= 0
{
if blocking {
continue;
} else {
return Err(SendError::Full(value));
}
}
let seat = tail_lock.0;
let state = unsafe { &mut *self.shared.ring[seat].state.get() };
state.val = Some(value);
state.required_reads = self.shared.num_readers.load(Ordering::SeqCst);
let tail = (seat + 1) % self.shared.len;
self.shared.ring[seat].num_reads.store(0, Ordering::SeqCst);
self.shared.tail.store(tail, Ordering::SeqCst);
tail_lock.0 = tail;
return Ok(());
}
}
pub fn blocking_send(&self, value: T) -> Result<(), BlockingSendError<T>> {
self.send_inner(value, true).map_err(|e| match e {
SendError::Disconnected(val) => BlockingSendError::Disconnected(val),
_ => unreachable!(),
})
}
pub fn send(&self, value: T) -> Result<(), SendError<T>> {
self.send_inner(value, false)
}
}
impl<T: Clone> Clone for Sender<T> {
fn clone(&self) -> Self {
Self::new(Arc::clone(&self.shared))
}
}
impl<T> Drop for Sender<T> {
fn drop(&mut self) {
self.shared.num_writers.fetch_sub(1, Ordering::Release);
}
}