Try to dequeue a value. Returns `Err(BridgeError::Empty)` if the ring is empty, or `Err(BridgeError::Disconnected)` if the producer was dropped.
(&mut self)
| 229 | /// Try to dequeue a value. Returns `Err(BridgeError::Empty)` if the ring is empty, |
| 230 | /// or `Err(BridgeError::Disconnected)` if the producer was dropped. |
| 231 | pub fn try_pop(&mut self) -> Result<T> { |
| 232 | let head = self.shared.head.value.load(Ordering::Relaxed); |
| 233 | |
| 234 | // Fast path: check cached tail first. |
| 235 | if head == self.cached_tail { |
| 236 | // Slow path: refresh cached tail from the atomic. |
| 237 | self.cached_tail = self.shared.tail.value.load(Ordering::Acquire); |
| 238 | |
| 239 | if head == self.cached_tail { |
| 240 | if self.shared.disconnected.load(Ordering::Relaxed) { |
| 241 | return Err(BridgeError::Disconnected { side: "producer" }); |
| 242 | } |
| 243 | return Err(BridgeError::Empty); |
| 244 | } |
| 245 | } |
| 246 | |
| 247 | let idx = (head as usize) & self.shared.mask; |
| 248 | |
| 249 | // SAFETY: We have exclusive read access to this slot because: |
| 250 | // 1. We are the only consumer (SPSC). |
| 251 | // 2. The producer has already written to this slot (tail > head, checked above). |
| 252 | let value = unsafe { (*self.shared.slots[idx].get()).take() }; |
| 253 | |
| 254 | // Advance head to free the slot for the producer. |
| 255 | self.shared |
| 256 | .head |
| 257 | .value |
| 258 | .store(head.wrapping_add(1), Ordering::Release); |
| 259 | |
| 260 | self.shared.metrics.record_pop(); |
| 261 | |
| 262 | // SAFETY: The producer wrote `Some(value)` before advancing tail. |
| 263 | // We only reach here when tail > head, so the slot is guaranteed occupied. |
| 264 | Ok(value.expect("BUG: slot was None despite tail > head")) |
| 265 | } |
| 266 | |
| 267 | /// Drain up to `max` items into the provided vector. Returns the count drained. |
| 268 | /// |