use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::Arc;
use crate::buf::RingBuffer;
use crate::err::{Error, Result};
pub struct Sender<T, const N: usize> {
buf: Arc<RingBuffer<T, N>>,
closed: Arc<AtomicBool>,
}
impl<T, const N: usize> Sender<T, N> {
#[allow(dead_code)]
pub(crate) fn new(buf: Arc<RingBuffer<T, N>>) -> Self {
Self {
buf,
closed: Arc::new(AtomicBool::new(false)),
}
}
pub(crate) fn new_with_closed(buf: Arc<RingBuffer<T, N>>, closed: Arc<AtomicBool>) -> Self {
Self { buf, closed }
}
#[allow(dead_code)]
pub(crate) fn closed_flag(&self) -> Arc<AtomicBool> {
self.closed.clone()
}
#[inline]
pub fn send(&self, value: T) -> Result<()> {
if self.closed.load(Ordering::Acquire) {
return Err(Error::ChannelClosed);
}
self.buf.send(value)
}
#[inline]
pub fn try_send(&self, value: T) -> Result<()> {
self.send(value)
}
pub fn send_spin(&self, value: T) -> Result<()>
where
T: Copy,
{
loop {
if self.closed.load(Ordering::Acquire) {
return Err(Error::ChannelClosed);
}
match self.buf.send(value) {
Ok(()) => return Ok(()),
Err(Error::QueueFull) => std::hint::spin_loop(),
Err(e) => return Err(e),
}
}
}
#[inline]
pub fn capacity(&self) -> usize {
N
}
#[inline]
pub fn is_full(&self) -> bool {
self.buf.len() >= N
}
#[inline]
pub fn is_closed(&self) -> bool {
self.closed.load(Ordering::Acquire)
}
pub fn close(&self) {
self.closed.store(true, Ordering::Release);
}
pub fn send_batch(&self, items: &[T]) -> Result<usize>
where
T: Copy,
{
if self.closed.load(Ordering::Acquire) {
return Err(Error::ChannelClosed);
}
let mut sent = 0;
for item in items {
match self.buf.send(*item) {
Ok(()) => sent += 1,
Err(e) => {
if sent == 0 {
return Err(e);
}
break;
}
}
}
Ok(sent)
}
pub fn send_timeout(&self, value: T, timeout: std::time::Duration) -> Result<()>
where
T: Copy,
{
let start = std::time::Instant::now();
loop {
if self.closed.load(Ordering::Acquire) {
return Err(Error::ChannelClosed);
}
match self.buf.send(value) {
Ok(()) => return Ok(()),
Err(e) => {
if start.elapsed() >= timeout {
return Err(e);
}
std::hint::spin_loop();
}
}
}
}
}
impl<T, const N: usize> Clone for Sender<T, N> {
fn clone(&self) -> Self {
Self {
buf: self.buf.clone(),
closed: self.closed.clone(),
}
}
}
unsafe impl<T: Send, const N: usize> Send for Sender<T, N> {}
unsafe impl<T: Send, const N: usize> Sync for Sender<T, N> {}