Skip to content

Commit

Permalink
feat(mpsc): add len, capacity, and remaining methods to mpsc (#72)
Browse files Browse the repository at this point in the history
Currently, there is no way to get the total capacity, remaining
capacity, or used length of a MPSC channel. This PR adds the following
methods to `mps::Sender`, `mpsc::Receiver`, `mpsc::StaticSender`,
`mpsc::StaticReceiver`, and their `mpsc::blocking` equivalents:

- `capacity`: Returns the total capacity of a channel, including used
  capacity.
- `len`: Returns the number of messages currently in a channel.
- `remaining`: Returns the current _free_ capacity of a channel
  (`capacity - len`).
- `is_empty`: Returns `true` if there are no messages in a channel.

Additionally, I've fixed a bug in `Core::len` where, if the channel is
closed and contains zero messages, the length returned is equal to its
capacity rather than 0. This is due to the `Core::len` function
incorrectly testing whether `head == tail` without masking out the
`closed` bit, which may be set in either `head` or `tail` when a channel
closes. This causes us to believe a closed channel is full when it's
actually empty. I've added tests reproducing this.

Fixes #71

---------

Co-authored-by: Joel Crevier <[email protected]>
Co-authored-by: Eliza Weisman <[email protected]>
  • Loading branch information
3 people authored Apr 6, 2024
1 parent 7b07d37 commit 00213c1
Show file tree
Hide file tree
Showing 3 changed files with 995 additions and 6 deletions.
34 changes: 33 additions & 1 deletion src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -432,7 +432,11 @@ impl Core {
return match head_idx.cmp(&tail_idx) {
cmp::Ordering::Less => tail_idx - head_idx,
cmp::Ordering::Greater => self.capacity - head_idx + tail_idx,
_ if tail == head => 0,
// Ignore the closed bit when comparing head and tail here,
// since it's not relevant to the length of the channel. If
// both indices point at the same slot and lap, the length
// is zero, even if the channel has been closed.
_ if (tail & !self.closed) == (head & !self.closed) => 0,
_ => self.capacity,
};
}
Expand Down Expand Up @@ -665,3 +669,31 @@ impl<T> fmt::Display for Full<T> {

#[cfg(feature = "std")]
impl<T> std::error::Error for Full<T> {}

#[cfg(test)]
mod tests {
use super::*;

#[test]
fn zero_len() {
const CAP: usize = 16;
let mut core = Core::new(CAP);
assert_eq!(core.len(), 0);
assert_eq!(core.capacity(), CAP);

// don't panic in drop impl.
core.has_dropped_slots = true;
}

#[test]
fn closed_channel_len() {
const CAP: usize = 16;
let mut core = Core::new(CAP);
core.close();
assert_eq!(core.len(), 0);
assert_eq!(core.capacity(), CAP);

// don't panic in drop impl.
core.has_dropped_slots = true;
}
}
Loading

0 comments on commit 00213c1

Please sign in to comment.