mirror of
https://github.com/rust-embedded/heapless.git
synced 2025-10-01 06:20:34 +00:00
Merge #44
44: Added Consumer::ready and Producer::ready indicating if it is ready t… r=japaric a=Frans-Willem …o enqueue/dequeue. I needed this to use it with a serial library. e.g. without it: ``` if let Some(x) = serial.read() { if let Err(x) = producer.enqueue(x) { // Now what ? } } ``` With the ready flag: ``` if producer.ready() { if let Some(x) = serial.read() { producer.enqueue(x).unwrap(); } } ``` Co-authored-by: Frans-Willem Hardijzer <fw@hardijzer.nl>
This commit is contained in:
commit
f7265774ef
@ -556,4 +556,32 @@ mod tests {
|
||||
|
||||
assert_eq!(rb.len(), 2);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn ready_flag() {
|
||||
let mut rb: RingBuffer<i32, U2> = RingBuffer::new();
|
||||
let (mut p, mut c) = rb.split();
|
||||
assert_eq!(c.ready(), false);
|
||||
assert_eq!(p.ready(), true);
|
||||
|
||||
p.enqueue(0).unwrap();
|
||||
|
||||
assert_eq!(c.ready(), true);
|
||||
assert_eq!(p.ready(), true);
|
||||
|
||||
p.enqueue(1).unwrap();
|
||||
|
||||
assert_eq!(c.ready(), true);
|
||||
assert_eq!(p.ready(), false);
|
||||
|
||||
c.dequeue().unwrap();
|
||||
|
||||
assert_eq!(c.ready(), true);
|
||||
assert_eq!(p.ready(), true);
|
||||
|
||||
c.dequeue().unwrap();
|
||||
|
||||
assert_eq!(c.ready(), false);
|
||||
assert_eq!(p.ready(), true);
|
||||
}
|
||||
}
|
||||
|
@ -79,6 +79,14 @@ macro_rules! impl_ {
|
||||
N: Add<U1> + Unsigned,
|
||||
Sum<N, U1>: ArrayLength<T>,
|
||||
{
|
||||
/// Returns if there are any items to dequeue. When this returns true, at least the
|
||||
/// first subsequent dequeue will succeed.
|
||||
pub fn ready(&self) -> bool {
|
||||
let tail = unsafe { self.rb.as_ref().tail.load_acquire() };
|
||||
let head = unsafe { self.rb.as_ref().head.load_relaxed() };
|
||||
return head != tail;
|
||||
}
|
||||
|
||||
/// Returns the item in the front of the queue, or `None` if the queue is empty
|
||||
pub fn dequeue(&mut self) -> Option<T> {
|
||||
let tail = unsafe { self.rb.as_ref().tail.load_acquire() };
|
||||
@ -119,6 +127,21 @@ macro_rules! impl_ {
|
||||
N: Add<U1> + Unsigned,
|
||||
Sum<N, U1>: ArrayLength<T>,
|
||||
{
|
||||
/// Returns if there is any space to enqueue a new item. When this returns true, at
|
||||
/// least the first subsequent enqueue will succeed.
|
||||
pub fn ready(&self) -> bool {
|
||||
let n = unsafe { self.rb.as_ref().capacity() + 1 };
|
||||
let tail = unsafe { self.rb.as_ref().tail.load_relaxed() };
|
||||
// NOTE we could replace this `load_acquire` with a `load_relaxed` and this method
|
||||
// would be sound on most architectures but that change would result in UB according
|
||||
// to the C++ memory model, which is what Rust currently uses, so we err on the side
|
||||
// of caution and stick to `load_acquire`. Check issue google#sanitizers#882 for
|
||||
// more details.
|
||||
let head = unsafe { self.rb.as_ref().head.load_acquire() };
|
||||
let next_tail = (tail + 1) % n;
|
||||
return next_tail != head;
|
||||
}
|
||||
|
||||
/// Adds an `item` to the end of the queue
|
||||
///
|
||||
/// Returns back the `item` if the queue is full
|
||||
|
Loading…
x
Reference in New Issue
Block a user