mirror of
https://github.com/rust-embedded/heapless.git
synced 2025-10-02 14:54:30 +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);
|
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,
|
N: Add<U1> + Unsigned,
|
||||||
Sum<N, U1>: ArrayLength<T>,
|
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
|
/// Returns the item in the front of the queue, or `None` if the queue is empty
|
||||||
pub fn dequeue(&mut self) -> Option<T> {
|
pub fn dequeue(&mut self) -> Option<T> {
|
||||||
let tail = unsafe { self.rb.as_ref().tail.load_acquire() };
|
let tail = unsafe { self.rb.as_ref().tail.load_acquire() };
|
||||||
@ -119,6 +127,21 @@ macro_rules! impl_ {
|
|||||||
N: Add<U1> + Unsigned,
|
N: Add<U1> + Unsigned,
|
||||||
Sum<N, U1>: ArrayLength<T>,
|
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
|
/// Adds an `item` to the end of the queue
|
||||||
///
|
///
|
||||||
/// Returns back the `item` if the queue is full
|
/// Returns back the `item` if the queue is full
|
||||||
|
Loading…
x
Reference in New Issue
Block a user