chute/
lib.rs

1//! Multi-producer multi-consumer lock-free multicast queue[^multicast]. 
2//! 
3//! [^multicast]: Or broadcast queue. Each consumer gets every message sent 
4//! to queue, from the moment of subscription.
5//!
6//! Memory-wise all consumers work with the same shared data blocks, so there 
7//! is no duplication. Queue is unbounded - it grows and shrinks dynamically as needed.
8//!
9//! Read performance is **stellar** - there is only one atomic read per block.
10//! Most of the time - this is just plain continuous data reading.
11//! 
12//! # [spmc] vs [mpmc]
13//!
14//! Both [spmc] and [mpmc] can work in multi-producer mode.
15//! 
16//! In general, using `Arc<spin::Mutex<spmc::Queue<T>>>` is more performant
17//! than `Arc<mpmc::Queue<T>>` from writer perspective.
18//! But! Writing simultaneously from several threads is much faster with [mpmc].
19//!
20//! The read performance is almost equal, with a slight advantage for [spmc]. 
21//! 
22//! # Order
23//! 
24//! [spmc] is fully ordered. 
25//! 
26//! [mpmc] ordered within writer's messages. Which means that all messages from
27//! the same [Writer] will arrive in order.
28//! 
29//! [Writer]: mpmc::Writer
30//! 
31//! # Reader memory
32//! 
33//! All readers have something like Arc for its current block in shared queue.
34//! This means that each reader prevents an unread portion of a queue from being dropped.
35//! 
36//! # target-flags
37//! 
38//! [mpmc] use [trailing_ones()]. So you want to have hardware support for it.
39//! On x86 you need `BMI1`, there is analog on each cpu architecture.
40//!
41//! [trailing_ones()]: u64::trailing_ones 
42
43mod block;
44
45pub mod mpmc;
46pub mod spmc;
47
48mod reader;
49pub use reader::*;
50
51#[cfg(test)]
52mod test{
53    #[derive(Clone, PartialEq)]
54    pub struct StringWrapper(String);
55    impl From<usize> for StringWrapper{
56        fn from(value: usize) -> Self {
57            Self(String::from(format!("{value}")))
58        }
59    }
60    impl From<StringWrapper> for usize{
61        fn from(value: StringWrapper) -> Self {
62            value.0.parse().unwrap()
63        }
64    }    
65}