use std::{
fmt::{self, Debug, Formatter},
future::Future,
ops::{Deref, DerefMut},
sync::Arc,
};
use tokio::{runtime::Handle, sync::SemaphorePermit};
use super::inner::{DecrementSizeGuard, PoolInner};
use crate::{Connection, Result};
pub struct PoolConnection {
live: Option<Live>,
pool: Arc<PoolInner>,
}
pub(super) struct Live {
raw: Connection,
}
pub(super) struct Idle {
pub(super) live: Live,
}
pub(super) struct Floating<C> {
pub(super) inner: C,
pub(super) guard: DecrementSizeGuard,
}
const EXPECT_MSG: &str = "BUG: inner connection already taken!";
impl Debug for PoolConnection {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
f.debug_struct("PoolConnection").finish()
}
}
impl Deref for PoolConnection {
type Target = Connection;
fn deref(&self) -> &Self::Target {
&self.live.as_ref().expect(EXPECT_MSG).raw
}
}
impl DerefMut for PoolConnection {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.live.as_mut().expect(EXPECT_MSG).raw
}
}
impl PoolConnection {
#[must_use = "futures returned by `PoolConnection::close` must be awaited"]
pub async fn close(mut self) -> Result<()> {
let floating = self.take_live().float(self.pool.clone());
floating.inner.raw.close().await
}
fn take_live(&mut self) -> Live {
self.live.take().expect(EXPECT_MSG)
}
#[doc(hidden)]
pub(crate) fn return_to_pool(&mut self) -> impl Future<Output = ()> + Send + 'static {
let floating: Option<Floating<Live>> =
self.live.take().map(|live| live.float(self.pool.clone()));
async move {
if let Some(floating) = floating {
floating.return_to_pool().await
} else {
false
};
}
}
}
impl Drop for PoolConnection {
fn drop(&mut self) {
if self.live.is_some()
&& let Ok(handle) = Handle::try_current()
{
handle.spawn(self.return_to_pool());
} else if let Some(live) = self.live.take() {
let floating = live.float(self.pool.clone());
if self.pool.is_closed() {
drop(floating);
} else {
floating.release();
}
}
}
}
impl Live {
pub fn float(self, pool: Arc<PoolInner>) -> Floating<Self> {
Floating {
inner: self,
guard: DecrementSizeGuard::new_permit(pool),
}
}
pub fn into_idle(self) -> Idle {
Idle { live: self }
}
}
impl Deref for Idle {
type Target = Live;
fn deref(&self) -> &Self::Target {
&self.live
}
}
impl DerefMut for Idle {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.live
}
}
impl Idle {
pub(super) async fn close(self) {
let _close_result = self.live.raw.close().await;
}
}
impl Floating<Live> {
pub fn new_live(conn: Connection, guard: DecrementSizeGuard) -> Self {
Self {
inner: Live { raw: conn },
guard,
}
}
pub fn reattach(self) -> PoolConnection {
let Self { inner, guard } = self;
let pool = Arc::clone(&guard.pool);
guard.cancel();
PoolConnection {
live: Some(inner),
pool,
}
}
pub fn release(self) {
self.guard.pool.clone().release(self);
}
async fn return_to_pool(self) -> bool {
if self.guard.pool.is_closed() {
self.close().await;
return false;
}
self.release();
true
}
pub async fn close(self) {
let _close_result = self.inner.raw.close().await;
}
pub fn into_idle(self) -> Floating<Idle> {
Floating {
inner: self.inner.into_idle(),
guard: self.guard,
}
}
}
impl Floating<Idle> {
pub fn from_idle(idle: Idle, pool: Arc<PoolInner>, permit: SemaphorePermit<'_>) -> Self {
Self {
inner: idle,
guard: DecrementSizeGuard::from_permit(pool, permit),
}
}
pub fn into_live(self) -> Floating<Live> {
Floating {
inner: self.inner.live,
guard: self.guard,
}
}
}
impl<C> Deref for Floating<C> {
type Target = C;
fn deref(&self) -> &Self::Target {
&self.inner
}
}
impl<C> DerefMut for Floating<C> {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.inner
}
}