#[macro_export]
macro_rules! static_spsc {
(
$(#[$attr:meta])*
$vis:vis mod $name:ident : EventBuf<$t:ty, $n:tt>;
) => {
$(#[$attr])*
#[allow(unreachable_pub, dead_code)]
$vis mod $name {
#[allow(unused_imports)]
use super::*;
pub type Tx = $crate::event_buf::Producer<'static, $t, $n>;
pub type Rx = $crate::event_buf::Consumer<'static, $t, $n>;
static BUF: $crate::EventBuf<$t, $n> = $crate::EventBuf::new();
pub fn take() -> ::core::option::Option<(Tx, Rx)> {
let tx = BUF.try_producer()?;
match BUF.try_consumer() {
::core::option::Option::Some(rx) => {
::core::option::Option::Some((tx, rx))
}
::core::option::Option::None => {
::core::mem::drop(tx);
::core::option::Option::None
}
}
}
pub fn buffer() -> &'static $crate::EventBuf<$t, $n> {
&BUF
}
}
};
(
$(#[$attr:meta])*
$vis:vis mod $name:ident : SeqRing<$t:ty, $n:tt>;
) => {
$(#[$attr])*
#[allow(unreachable_pub, dead_code)]
$vis mod $name {
#[allow(unused_imports)]
use super::*;
pub type Tx = $crate::seq_ring::Producer<'static, $t, $n>;
pub type Rx = $crate::seq_ring::Consumer<'static, $t, $n>;
static RING: $crate::SeqRing<$t, $n> = $crate::SeqRing::new();
pub fn take() -> ::core::option::Option<(Tx, Rx)> {
let tx = RING.try_producer()?;
match RING.try_consumer() {
::core::option::Option::Some(rx) => {
::core::option::Option::Some((tx, rx))
}
::core::option::Option::None => {
::core::mem::drop(tx);
::core::option::Option::None
}
}
}
pub fn ring() -> &'static $crate::SeqRing<$t, $n> {
&RING
}
}
};
}
#[cfg(all(test, not(loom)))]
mod tests {
crate::static_spsc! {
pub mod eb_round_trip: EventBuf<u32, 4>;
}
crate::static_spsc! {
mod eb_once: EventBuf<u32, 4>;
}
crate::static_spsc! {
mod eb_partial: EventBuf<u32, 2>;
}
crate::static_spsc! {
pub mod sr_round_trip: SeqRing<u32, 4>;
}
crate::static_spsc! {
mod send_check: EventBuf<u32, 4>;
}
crate::static_spsc! {
mod send_check_sr: SeqRing<u32, 4>;
}
#[test]
fn event_buf_module_round_trips() {
let (tx, rx) = eb_round_trip::take().expect("first take");
tx.push(7).unwrap();
assert_eq!(rx.pop(), Some(7));
assert_eq!(eb_round_trip::buffer().capacity(), 4);
}
#[test]
fn event_buf_take_is_once_only() {
let first = eb_once::take();
assert!(first.is_some(), "first take must succeed");
assert!(eb_once::take().is_none(), "second take must fail");
drop(first);
assert!(eb_once::take().is_some(), "take succeeds again after drop");
}
#[test]
fn seq_ring_module_round_trips() {
let (tx, mut rx) = sr_round_trip::take().expect("first take");
tx.push(9);
assert_eq!(rx.poll_one_value(), Some((1, 9)));
assert_eq!(sr_round_trip::ring().capacity(), 4);
}
#[test]
fn failed_take_strands_nothing() {
let rx = eb_partial::buffer().try_consumer().expect("consumer");
assert!(eb_partial::take().is_none());
let tx = eb_partial::buffer()
.try_producer()
.expect("producer must still be free after a failed take");
tx.push(1).unwrap();
assert_eq!(rx.pop(), Some(1));
}
#[test]
fn handles_are_send() {
fn assert_send<T: Send>() {}
assert_send::<send_check::Tx>();
assert_send::<send_check::Rx>();
assert_send::<send_check_sr::Tx>();
assert_send::<send_check_sr::Rx>();
}
}