use core::mem::ManuallyDrop;
use crate::{
core_impl, unpack_data_index, AtomicUsize, MaybeUninit, Node, Ordering, ReaderData, MAX_LEN,
};
struct InnerChannel<T, const N: usize> {
buffer: [Node<T>; N],
head: AtomicUsize,
}
impl<T: Clone + Sized, const N: usize> InnerChannel<T, N> {
const fn new() -> Self {
let mut uninit_buffer: [MaybeUninit<Node<T>>; N] =
unsafe { MaybeUninit::uninit().assume_init() };
let mut i = 0;
while i < N {
uninit_buffer[i] = MaybeUninit::new(Node::<T>::empty());
i += 1;
}
#[repr(C)]
union InitializedData<T, const N: usize> {
uninit: ManuallyDrop<[MaybeUninit<Node<T>>; N]>,
init: ManuallyDrop<[Node<T>; N]>,
}
let buffer = ManuallyDrop::into_inner(unsafe {
InitializedData {
uninit: ManuallyDrop::new(uninit_buffer),
}
.init
});
Self {
buffer,
head: AtomicUsize::new(0),
}
}
fn push(&self, value: T) {
core_impl::push(&self.buffer, &self.head, value);
}
fn pop(&self, reader: &mut ReaderData) -> Option<T> {
core_impl::pop(&self.buffer, &self.head, reader)
}
}
pub struct Sender<T, const N: usize> {
queue: InnerChannel<T, N>,
}
unsafe impl<T: Clone + Send, const N: usize> Send for Sender<T, N> {}
unsafe impl<T: Clone + Send, const N: usize> Sync for Sender<T, N> {}
impl<T: Clone, const N: usize> Sender<T, N> {
pub fn send(&self, value: T) {
self.queue.push(value);
}
pub const fn new() -> Self {
assert!(N <= MAX_LEN, "Exceeded the maximum length");
Self {
queue: InnerChannel::<T, N>::new(),
}
}
pub fn new_receiver(&self) -> Receiver<'_, T, N> {
let head = self.queue.head.load(Ordering::Relaxed);
let (lap, index) = unpack_data_index(head);
Receiver {
queue: &self.queue,
reader: ReaderData { index, lap },
}
}
}
impl<T: Clone, const N: usize> Default for Sender<T, N> {
fn default() -> Self {
Self::new()
}
}
pub struct Receiver<'a, T, const N: usize> {
queue: &'a InnerChannel<T, N>,
reader: ReaderData,
}
unsafe impl<T: Clone + Send, const N: usize> Send for Receiver<'_, T, N> {}
unsafe impl<T: Clone + Send, const N: usize> Sync for Receiver<'_, T, N> {}
impl<T: Clone, const N: usize> Receiver<'_, T, N> {
pub fn recv(&mut self) -> Option<T> {
self.queue.pop(&mut self.reader)
}
}
impl<T: Clone, const N: usize> Clone for Receiver<'_, T, N> {
fn clone(&self) -> Self {
Self {
queue: self.queue,
reader: self.reader.clone(),
}
}
}