From eae66b9b87df94329a6a1e2bb36c92de5ddd72bb Mon Sep 17 00:00:00 2001 From: Josh Gao Date: Sat, 8 Jun 2019 00:56:55 -0700 Subject: [PATCH] Add Queue::peek. --- src/spsc/mod.rs | 38 ++++++++++++++++++++++++++++++++++++++ src/spsc/split.rs | 35 +++++++++++++++++++++++++++++++++++ 2 files changed, 73 insertions(+) diff --git a/src/spsc/mod.rs b/src/spsc/mod.rs index f798245c..444d75ac 100644 --- a/src/spsc/mod.rs +++ b/src/spsc/mod.rs @@ -117,6 +117,10 @@ where U: sealed::Uxx, C: sealed::XCore, { + fn get(&self) -> &U { + unsafe { &*self.v.get() } + } + fn get_mut(&mut self) -> &mut U { unsafe { &mut *self.v.get() } } @@ -341,6 +345,40 @@ macro_rules! impl_ { N: ArrayLength, C: sealed::XCore, { + /// Returns a reference to the item in the front of the queue without dequeuing, or + /// `None` if the queue is empty. + /// + /// # Examples + /// ``` + /// use heapless::spsc::Queue; + /// use heapless::consts::*; + /// + /// let mut queue: Queue = Queue::u8(); + /// let (mut producer, mut consumer) = queue.split(); + /// assert_eq!(None, consumer.peek()); + /// producer.enqueue(1); + /// assert_eq!(Some(&1), consumer.peek()); + /// assert_eq!(Some(1), consumer.dequeue()); + /// assert_eq!(None, consumer.peek()); + /// ``` + pub fn peek(&self) -> Option<&T> { + let cap = self.capacity(); + + let head = self.0.head.get(); + let tail = self.0.tail.get(); + + let p = self.0.buffer.as_ptr(); + + if *head != *tail { + let item = unsafe { + &*(p as *const T).add(usize::from(*head % cap)) + }; + Some(item) + } else { + None + } + } + /// Returns the item in the front of the queue, or `None` if the queue is empty pub fn dequeue(&mut self) -> Option { let cap = self.capacity(); diff --git a/src/spsc/split.rs b/src/spsc/split.rs index e987dbc8..3614af1f 100644 --- a/src/spsc/split.rs +++ b/src/spsc/split.rs @@ -84,6 +84,32 @@ macro_rules! impl_ { return head != tail; } + /// Returns the item in the front of the queue without dequeuing, or `None` if the queue is empty. + /// + /// # Examples + /// ``` + /// use heapless::spsc::Queue; + /// use heapless::consts::*; + /// + /// let mut queue: Queue = Queue::u8(); + /// let (mut producer, mut consumer) = queue.split(); + /// assert_eq!(None, consumer.peek()); + /// producer.enqueue(1); + /// assert_eq!(Some(&1), consumer.peek()); + /// assert_eq!(Some(1), consumer.dequeue()); + /// assert_eq!(None, consumer.peek()); + /// ``` + pub fn peek(&self) -> Option<&T> { + let head = unsafe { self.rb.as_ref().0.head.load_relaxed() }; + let tail = unsafe { self.rb.as_ref().0.tail.load_acquire() }; + + if head != tail { + Some(unsafe { self._peek(head) }) + } else { + None + } + } + /// Returns the item in the front of the queue, or `None` if the queue is empty pub fn dequeue(&mut self) -> Option { let head = unsafe { self.rb.as_ref().0.head.load_relaxed() }; @@ -107,6 +133,15 @@ macro_rules! impl_ { self._dequeue(head) // ▲ } + unsafe fn _peek(&self, head: $uxx) -> &T { + let rb = self.rb.as_ref(); + + let cap = rb.capacity(); + + let item = (rb.0.buffer.as_ptr() as *const T).add(usize::from(head % cap)); + &*item + } + unsafe fn _dequeue(&mut self, head: $uxx) -> T { let rb = self.rb.as_ref();