use std::{
sync::{Arc, atomic::Ordering},
task::Poll,
};
use crate::{
Counts, State,
consumer::Consumer,
lock::*,
producer::{Mut, Producer, Ref},
waiter::*,
};
#[derive(Debug)]
pub struct Weak<T> {
pub(crate) state: Lock<State<T>>,
pub(crate) counts: Arc<Counts>,
}
impl<T> Weak<T> {
pub fn produce(&self) -> Option<Producer<T>> {
self.counts.producers.fetch_add(1, Ordering::Relaxed);
{
let state = self.state.lock();
if state.closed {
self.counts.producers.fetch_sub(1, Ordering::Relaxed);
return None;
}
}
Some(Producer {
state: self.state.clone(),
counts: self.counts.clone(),
})
}
pub fn consume(&self) -> Consumer<T> {
let prev = self.counts.consumers.fetch_add(1, Ordering::AcqRel);
if prev == 0 {
let mut waiters = self.state.lock().waiters.take();
waiters.wake();
}
Consumer {
state: self.state.clone(),
counts: self.counts.clone(),
}
}
pub fn write(&self) -> Result<Mut<'_, T>, Ref<'_, T>> {
let state = self.state.lock();
if state.closed {
Err(Ref { state })
} else {
Ok(Mut::new(state))
}
}
pub fn read(&self) -> Ref<'_, T> {
Ref {
state: self.state.lock(),
}
}
pub fn poll_write<F, R>(&self, waiter: &Waiter, mut f: F) -> Poll<Option<R>>
where
F: FnMut(&mut Mut<'_, T>) -> Poll<R>,
{
let Ok(mut state) = self.write() else {
return Poll::Ready(None);
};
if let Poll::Ready(res) = f(&mut state) {
return Poll::Ready(Some(res));
}
state.modified = false;
let state = state.state.as_mut().unwrap();
waiter.register(&mut state.waiters);
Poll::Pending
}
pub async fn wait<F, R>(&self, mut f: F) -> Result<R, Ref<'_, T>>
where
F: FnMut(&mut Mut<'_, T>) -> Poll<R> + Unpin,
R: Unpin,
{
match crate::wait(move |waiter| self.poll_write(waiter, &mut f)).await {
Some(r) => Ok(r),
None => Err(self.read()),
}
}
pub fn is_closed(&self) -> bool {
self.state.lock().closed
}
pub async fn unused(&self) -> Result<(), Ref<'_, T>> {
match crate::wait(move |waiter| self.poll_unused(waiter)).await {
Some(()) => Ok(()),
None => Err(self.read()),
}
}
fn poll_unused(&self, waiter: &Waiter) -> Poll<Option<()>> {
if self.counts.consumers.load(Ordering::Relaxed) == 0 {
return Poll::Ready(Some(()));
}
let mut state = self.state.lock();
if state.closed {
return Poll::Ready(None);
}
waiter.register(&mut state.waiters);
if self.counts.consumers.load(Ordering::Relaxed) == 0 {
return Poll::Ready(Some(()));
}
Poll::Pending
}
pub async fn used(&self) -> Result<(), Ref<'_, T>> {
match crate::wait(move |waiter| self.poll_used(waiter)).await {
Some(()) => Ok(()),
None => Err(self.read()),
}
}
fn poll_used(&self, waiter: &Waiter) -> Poll<Option<()>> {
if self.counts.consumers.load(Ordering::Relaxed) > 0 {
return Poll::Ready(Some(()));
}
let mut state = self.state.lock();
if state.closed {
return Poll::Ready(None);
}
waiter.register(&mut state.waiters);
if self.counts.consumers.load(Ordering::Relaxed) > 0 {
return Poll::Ready(Some(()));
}
Poll::Pending
}
pub fn same_channel(&self, other: &Self) -> bool {
self.state.is_clone(&other.state)
}
}
impl<T> Clone for Weak<T> {
fn clone(&self) -> Self {
Self {
state: self.state.clone(),
counts: self.counts.clone(),
}
}
}