1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105
//! A no-std Single Producer, Single Consumer channel for unidirectional message exchange between
//! modules. This module don't use anything from the standard lib and can be easily used in no-std
//! enviroments. We only use mem::take from [core].
use core::mem::take;
use crate::prelude::Vec;
/// A (Send + Sync) single producer, single consumer channel to notify modules about things.
/// The api is super minimalistic to reduce external dependecies, including from the std-lib
///
/// One notable difference from the standard mspc channel is that this channel's ends are't
/// two different types, while this is possible, there's no reason to do that. Specially
/// considering that to get a good compile-time asurance that both ends will not be shared, the
/// channel must not be [Send], but this is one of the main requirements to use this channel in
/// async code. Moreover, if two worker threads are meant to be identical threads balancing their
/// work, it might be beneficial to use this same channel as a de-facto single producer, multiple
/// consumer channel for work distribution.
/// # Example
/// ```
/// use floresta_common::spsc;
/// let channel = spsc::Channel::new();
///
/// // Send something
/// channel.send(1);
/// // Read the same thing back
/// assert_eq!(channel.recv().next(), Some(1));
/// ```
#[derive(Debug, Default)]
pub struct Channel<T> {
/// The data pending for read
content: spin::Mutex<Vec<T>>,
}
impl<T> Channel<T> {
/// Creates a new channel
///
/// # Example
/// ```
/// use floresta_common::spsc;
/// let channel = spsc::Channel::new();
///
/// channel.send(1);
/// assert_eq!(channel.recv().next(), Some(1));
/// ```
pub fn new() -> Self {
Channel {
content: spin::Mutex::new(Vec::new()),
}
}
/// Sends some data through a channel
///
/// # Example
/// ```
/// use floresta_common::spsc;
/// let channel = spsc::Channel::new();
///
/// channel.send(1);
/// assert_eq!(channel.recv().next(), Some(1));
/// ```
pub fn send(&self, data: T) {
self.content.lock().push(data);
}
/// Reads from a channel
///
/// This method returns an iterator over all alements inside a [Channel]
pub fn recv(&self) -> RecvIter<T> {
let inner = take(&mut *self.content.lock());
RecvIter { inner }
}
}
/// An iterator issued every time someone calls `recv`.
///
/// This iterator takes all itens available for reading in a channel
/// and lets the consumer iterate over them, without acquiring the lock
/// every time (the mutex is only locked when `recv` is called).
///
/// # Example
/// ```
/// use floresta_common::spsc;
/// let channel = spsc::Channel::new();
///
/// channel.send(0);
/// channel.send(1);
///
/// for (i, el) in channel.recv().enumerate() {
/// assert_eq!(i, el);
/// }
/// // A second read should create an empty iterator
/// assert_eq!(channel.recv().next(), None);
/// ```
pub struct RecvIter<T> {
inner: Vec<T>,
}
impl<T> Iterator for RecvIter<T> {
type Item = T;
fn next(&mut self) -> Option<Self::Item> {
if self.inner.is_empty() {
return None;
}
Some(self.inner.remove(0))
}
}