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:
bors[bot] 2018-07-13 04:53:36 +00:00
commit f7265774ef
2 changed files with 51 additions and 0 deletions

View File

@ -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);
}
}

View File

@ -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