magnetic/lib.rs
1//! Magnetic contains a set of high-performance queues useful for developing
2//! low-latency applications. All queues are FIFO unless otherwise specified.
3//!
4//! # Examples
5//!
6//! ```
7//! use std::thread::spawn;
8//! use magnetic::spsc::spsc_queue;
9//! use magnetic::buffer::dynamic::DynamicBuffer;
10//! use magnetic::{Producer, Consumer};
11//!
12//! let (p, c) = spsc_queue(DynamicBuffer::new(32).unwrap());
13//!
14//! // Push and pop within a single thread
15//! p.push(1).unwrap();
16//! assert_eq!(c.pop(), Ok(1));
17//!
18//! // Push and pop from multiple threads. Since this example is using the
19//! // SPSC queue, only one producer and one consumer are allowed.
20//! let t1 = spawn(move || {
21//! for i in 0..10 {
22//! println!("Producing {}", i);
23//! p.push(i).unwrap();
24//! }
25//! p
26//! });
27//!
28//! let t2 = spawn(move || {
29//! loop {
30//! let i = c.pop().unwrap();
31//! println!("Consumed {}", i);
32//! if i == 9 { break; }
33//! }
34//! });
35//!
36//! t1.join().unwrap();
37//! t2.join().unwrap();
38//! ```
39
40#![deny(missing_docs)]
41
42use std::fmt;
43
44pub mod buffer;
45pub mod mpmc;
46pub mod mpsc;
47pub mod spmc;
48pub mod spsc;
49mod util;
50
51/// Possible errors for `Producer::push`
52#[derive(Clone, Copy, PartialEq, Eq)]
53pub enum PushError<T> {
54 /// Consumer was destroyed
55 Disconnected(T),
56}
57
58impl<T> fmt::Debug for PushError<T> {
59 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
60 match self {
61 Self::Disconnected(_) => f.pad("Disconnected(_)"),
62 }
63 }
64}
65
66impl<T> fmt::Display for PushError<T> {
67 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
68 match self {
69 Self::Disconnected(_) => "queue abandoned".fmt(f),
70 }
71 }
72}
73
74impl<T> std::error::Error for PushError<T> {}
75
76/// Possible errors for `Producer::try_push`
77#[derive(Clone, Copy, PartialEq, Eq)]
78pub enum TryPushError<T> {
79 /// Queue was full
80 Full(T),
81 /// Consumer was destroyed
82 Disconnected(T),
83}
84
85impl<T> fmt::Debug for TryPushError<T> {
86 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
87 match self {
88 Self::Full(_) => f.pad("Full(_)"),
89 Self::Disconnected(_) => f.pad("Disconnected(_)"),
90 }
91 }
92}
93
94impl<T> fmt::Display for TryPushError<T> {
95 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
96 match self {
97 Self::Full(_) => "queue full".fmt(f),
98 Self::Disconnected(_) => "queue abandoned".fmt(f),
99 }
100 }
101}
102
103impl<T> std::error::Error for TryPushError<T> {}
104
105/// Possible errors for `Consumer::pop`
106#[derive(Debug, Clone, Copy, PartialEq, Eq)]
107pub enum PopError {
108 /// Producer was destroyed
109 Disconnected,
110}
111
112impl fmt::Display for PopError {
113 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
114 match self {
115 Self::Disconnected => "queue abandoned".fmt(f),
116 }
117 }
118}
119
120impl std::error::Error for PopError {}
121
122/// Possible errors for `Consumer::try_pop`
123#[derive(Debug, Clone, Copy, PartialEq, Eq)]
124pub enum TryPopError {
125 /// Queue was empty
126 Empty,
127 /// Producer was destroyed
128 Disconnected,
129}
130
131impl fmt::Display for TryPopError {
132 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
133 match self {
134 Self::Empty => "queue empty".fmt(f),
135 Self::Disconnected => "queue abandoned".fmt(f),
136 }
137 }
138}
139
140impl std::error::Error for TryPopError {}
141
142/// The consumer end of the queue allows for sending data. `Producer<T>` is
143/// always `Send`, but is only `Sync` for multi-producer (MPSC, MPMC) queues.
144pub trait Producer<T> {
145 /// Add value to front of the queue. This method will block if the queue
146 /// is currently full.
147 fn push(&self, value: T) -> Result<(), PushError<T>>;
148
149 /// Attempt to add a value to the front of the queue. If the value was
150 /// added successfully, `None` will be returned. If unsuccessful, `value`
151 /// will be returned. An unsuccessful push indicates that the queue was
152 /// full.
153 fn try_push(&self, value: T) -> Result<(), TryPushError<T>>;
154}
155
156/// The consumer end of the queue allows for receiving data. `Consumer<T>` is
157/// always `Send`, but is only `Sync` for multi-consumer (SPMC, MPMC) queues.
158pub trait Consumer<T> {
159 /// Remove value from the end of the queue. This method will block if the
160 /// queue is currently empty.
161 fn pop(&self) -> Result<T, PopError>;
162
163 /// Attempt to remove a value from the end of the queue. If the value was
164 /// removed successfully, `Some(T)` will be returned. If unsuccessful,
165 /// `None` will be returned. An unsuccessful pop indicates that the queue
166 /// was empty.
167 fn try_pop(&self) -> Result<T, TryPopError>;
168}