use std::{
pin::Pin,
task::{Context, Poll, Waker},
};
use super::{Pool, hint};
#[must_use = "futures do nothing unless you `.await` or poll them"]
pub struct Close<T, B> {
pool: Option<Pool<T, B>>,
}
impl<T, B> Close<T, B> {
pub(super) fn new(pool: Pool<T, B>) -> Self {
pool.inner.close();
Self { pool: Some(pool) }
}
}
impl<T, B> Future for Close<T, B> {
type Output = Pool<T, B>;
fn poll(
mut self: Pin<&mut Self>,
context: &mut Context<'_>,
) -> Poll<Self::Output> {
if self.pool.is_none() {
hint::cold_path();
unreachable!(
"The `Close` future has already been resolved: it is violating the contract of `Future`"
);
}
unsafe {
let mut closing_state = loop {
if let Some(closing_state) = self
.pool
.as_ref()
.unwrap_unchecked()
.inner
.closing_state
.try_write_lock()
{
break closing_state;
}
hint::cold_path();
hint::spin_loop();
};
let all_vacants = self
.pool
.as_ref()
.unwrap_unchecked()
.inner
.blocks
.iter()
.all(|slot| slot.is_all_vacants());
if all_vacants {
*closing_state = ClosingState::Closed;
drop(closing_state);
Poll::Ready(self.pool.take().unwrap_unchecked())
} else {
let waker = context.waker().clone();
*closing_state = ClosingState::Closing(Some(waker));
drop(closing_state);
Poll::Pending
}
}
}
}
pub(super) enum ClosingState {
Opened,
Closing(Option<Waker>),
Closed,
}