use std::path::Path;
use crate::error::Result;
use crate::signature::LayoutSignature;
use crate::spmc::RingConsumer;
pub struct RingMultiplexer<T: Copy + LayoutSignature + 'static> {
consumers: Vec<RingConsumer<T>>,
names: Vec<String>,
next_idx: usize,
}
impl<T: Copy + LayoutSignature + 'static> Default for RingMultiplexer<T> {
fn default() -> Self {
Self::new()
}
}
impl<T: Copy + LayoutSignature + 'static> RingMultiplexer<T> {
pub fn new() -> Self {
Self {
consumers: Vec::new(),
names: Vec::new(),
next_idx: 0,
}
}
pub fn add(&mut self, consumer: RingConsumer<T>) -> usize {
let idx = self.consumers.len();
self.names.push(format!("channel_{}", idx));
self.consumers.push(consumer);
idx
}
pub fn add_named<S: Into<String>>(&mut self, name: S, consumer: RingConsumer<T>) -> usize {
let idx = self.consumers.len();
self.names.push(name.into());
self.consumers.push(consumer);
idx
}
pub fn attach<P: AsRef<Path>>(&mut self, path: P) -> Result<usize> {
let consumer = RingConsumer::attach(path)?;
Ok(self.add(consumer))
}
pub fn attach_named<P: AsRef<Path>, S: Into<String>>(&mut self, name: S, path: P) -> Result<usize> {
let consumer = RingConsumer::attach(path)?;
Ok(self.add_named(name, consumer))
}
#[inline]
pub fn len(&self) -> usize {
self.consumers.len()
}
#[inline]
pub fn is_empty(&self) -> bool {
self.consumers.is_empty()
}
#[inline]
pub fn channel_name(&self, idx: usize) -> Option<&str> {
self.names.get(idx).map(|s| s.as_str())
}
#[inline]
pub fn consumer(&self, idx: usize) -> Option<&RingConsumer<T>> {
self.consumers.get(idx)
}
#[inline]
pub fn consumer_mut(&mut self, idx: usize) -> Option<&mut RingConsumer<T>> {
self.consumers.get_mut(idx)
}
#[inline]
pub fn try_recv_any(&mut self) -> Option<(usize, T)> {
let n = self.consumers.len();
if n == 0 {
return None;
}
let start = self.next_idx;
for i in 0..n {
let idx = (start + i) % n;
if let Some(msg) = self.consumers[idx].try_recv() {
self.next_idx = (idx + 1) % n;
return Some((idx, msg));
}
}
None
}
#[inline]
pub fn try_recv_priority(&mut self) -> Option<(usize, T)> {
for (idx, consumer) in self.consumers.iter_mut().enumerate() {
if let Some(msg) = consumer.try_recv() {
return Some((idx, msg));
}
}
None
}
pub fn recv_batch_any(&mut self, max_items: usize) -> Vec<(usize, T)> {
let mut batch = Vec::with_capacity(max_items.min(64));
while batch.len() < max_items {
if let Some((idx, msg)) = self.try_recv_any() {
batch.push((idx, msg));
} else {
break;
}
}
batch
}
}
#[cfg(feature = "tokio")]
pub use async_impl::AsyncRingMultiplexer;
#[cfg(feature = "tokio")]
mod async_impl {
use super::*;
use crate::async_ring::AsyncRingConsumer;
pub struct AsyncRingMultiplexer<T: Copy + LayoutSignature + 'static> {
consumers: Vec<AsyncRingConsumer<T>>,
names: Vec<String>,
next_idx: usize,
}
impl<T: Copy + LayoutSignature + 'static> Default for AsyncRingMultiplexer<T> {
fn default() -> Self {
Self::new()
}
}
impl<T: Copy + LayoutSignature + 'static> AsyncRingMultiplexer<T> {
pub fn new() -> Self {
Self {
consumers: Vec::new(),
names: Vec::new(),
next_idx: 0,
}
}
pub fn add(&mut self, consumer: AsyncRingConsumer<T>) -> usize {
let idx = self.consumers.len();
self.names.push(format!("channel_{}", idx));
self.consumers.push(consumer);
idx
}
pub fn add_named<S: Into<String>>(&mut self, name: S, consumer: AsyncRingConsumer<T>) -> usize {
let idx = self.consumers.len();
self.names.push(name.into());
self.consumers.push(consumer);
idx
}
pub fn attach<P: AsRef<Path>>(&mut self, path: P) -> Result<usize> {
let consumer = AsyncRingConsumer::attach(path)?;
Ok(self.add(consumer))
}
pub fn attach_named<P: AsRef<Path>, S: Into<String>>(&mut self, name: S, path: P) -> Result<usize> {
let consumer = AsyncRingConsumer::attach(path)?;
Ok(self.add_named(name, consumer))
}
#[inline]
pub fn len(&self) -> usize {
self.consumers.len()
}
#[inline]
pub fn is_empty(&self) -> bool {
self.consumers.is_empty()
}
#[inline]
pub fn channel_name(&self, idx: usize) -> Option<&str> {
self.names.get(idx).map(|s| s.as_str())
}
#[inline]
pub fn try_recv_any(&mut self) -> Option<(usize, T)> {
let n = self.consumers.len();
if n == 0 {
return None;
}
let start = self.next_idx;
for i in 0..n {
let idx = (start + i) % n;
if let Some(msg) = self.consumers[idx].try_recv() {
self.next_idx = (idx + 1) % n;
return Some((idx, msg));
}
}
None
}
pub async fn recv_any(&mut self) -> (usize, T) {
let mut spin_count = 0u32;
let mut yield_count = 0u32;
loop {
if let Some((idx, msg)) = self.try_recv_any() {
return (idx, msg);
}
if spin_count < 64 {
core::hint::spin_loop();
spin_count += 1;
} else if yield_count < 16 {
tokio::task::yield_now().await;
yield_count += 1;
} else {
tokio::time::sleep(std::time::Duration::from_micros(10)).await;
spin_count = 0;
yield_count = 0;
}
}
}
}
}