use core::fmt;
use core::future::Future;
use core::mem;
use core::pin::Pin;
use core::task::{Context, Poll};
use std::rc::Rc;
use super::chan::{Chan, Limit};
use crate::sync::TryAcquireError;
use crate::sync::local::semaphore::{Acquire, Semaphore};
use crate::sync::mpsc::error::{SendError, TrySendError};
pub(super) struct Bounded {
slots: Semaphore,
max: usize,
}
impl Limit for Bounded {
fn release(&self, n: usize) {
if n > 0 {
self.slots.add_permits(n);
}
}
fn is_idle(&self) -> bool {
self.slots.available_permits() == self.max
}
fn close(&self) {
self.slots.close();
}
}
#[track_caller]
pub fn channel<T>(buffer: usize) -> (Sender<T>, Receiver<T>) {
assert!(buffer > 0, "mpsc bounded channel requires buffer > 0");
let chan = Rc::new(Chan::new(Bounded {
slots: Semaphore::new(buffer),
max: buffer,
}));
let tx = Sender {
chan: Rc::clone(&chan),
};
(tx, Receiver { chan })
}
pub struct Sender<T> {
chan: Rc<Chan<T, Bounded>>,
}
impl<T> Sender<T> {
pub async fn send(&self, value: T) -> Result<(), SendError<T>> {
match self.reserve().await {
Ok(permit) => {
permit.send(value);
Ok(())
}
Err(_) => Err(SendError(value)),
}
}
pub fn try_send(&self, value: T) -> Result<(), TrySendError<T>> {
match self.try_reserve() {
Ok(permit) => {
permit.send(value);
Ok(())
}
Err(TrySendError::Full(())) => Err(TrySendError::Full(value)),
Err(TrySendError::Closed(())) => Err(TrySendError::Closed(value)),
}
}
pub async fn reserve(&self) -> Result<Permit<'_, T>, SendError<()>> {
Reserve {
chan: &self.chan,
acquire: self.chan.limit.slots.acquire(),
}
.await
}
pub fn try_reserve(&self) -> Result<Permit<'_, T>, TrySendError<()>> {
match self.chan.limit.slots.try_acquire() {
Ok(permit) => {
permit.forget();
Ok(Permit { chan: &self.chan })
}
Err(TryAcquireError::NoPermits) => Err(TrySendError::Full(())),
Err(TryAcquireError::Closed) => Err(TrySendError::Closed(())),
}
}
pub async fn closed(&self) {
self.chan.closed().await;
}
pub fn is_closed(&self) -> bool {
self.chan.is_closed()
}
pub fn same_channel(&self, other: &Self) -> bool {
Rc::ptr_eq(&self.chan, &other.chan)
}
pub fn capacity(&self) -> usize {
self.chan.limit.slots.available_permits()
}
pub fn max_capacity(&self) -> usize {
self.chan.limit.max
}
}
impl<T> Clone for Sender<T> {
fn clone(&self) -> Self {
self.chan.add_sender();
Self {
chan: Rc::clone(&self.chan),
}
}
}
impl<T> Drop for Sender<T> {
fn drop(&mut self) {
self.chan.drop_sender();
}
}
impl<T> fmt::Debug for Sender<T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("Sender")
.field("capacity", &self.capacity())
.field("max_capacity", &self.max_capacity())
.field("closed", &self.is_closed())
.finish()
}
}
struct Reserve<'a, T> {
chan: &'a Chan<T, Bounded>,
acquire: Acquire<'a>,
}
impl<'a, T> Future for Reserve<'a, T> {
type Output = Result<Permit<'a, T>, SendError<()>>;
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
let this = self.get_mut();
match Pin::new(&mut this.acquire).poll(cx) {
Poll::Ready(Ok(permit)) => {
permit.forget();
Poll::Ready(Ok(Permit { chan: this.chan }))
}
Poll::Ready(Err(_)) => Poll::Ready(Err(SendError(()))),
Poll::Pending => Poll::Pending,
}
}
}
impl<T> Drop for Reserve<'_, T> {
fn drop(&mut self) {
self.acquire.cancel();
self.chan.wake_if_finished();
}
}
#[must_use = "dropping a permit gives its slot back unused"]
pub struct Permit<'a, T> {
chan: &'a Chan<T, Bounded>,
}
impl<T> Permit<'_, T> {
pub fn send(self, value: T) {
let chan = self.chan;
mem::forget(self);
chan.push(value);
}
}
impl<T> Drop for Permit<'_, T> {
fn drop(&mut self) {
self.chan.give_back(1);
}
}
impl<T> fmt::Debug for Permit<'_, T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("Permit").finish_non_exhaustive()
}
}
pub struct Receiver<T> {
chan: Rc<Chan<T, Bounded>>,
}
impl<T> Receiver<T> {
receiver_methods!();
pub fn capacity(&self) -> usize {
self.chan.limit.slots.available_permits()
}
pub fn max_capacity(&self) -> usize {
self.chan.limit.max
}
}
impl<T> Drop for Receiver<T> {
fn drop(&mut self) {
self.chan.drop_rx();
}
}
impl<T> fmt::Debug for Receiver<T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("Receiver")
.field("len", &self.len())
.field("closed", &self.is_closed())
.finish()
}
}