use std::{
cell::Cell,
ops::{Deref, DerefMut},
rc::Rc,
};
use crate::{
exchange::Exchange,
manage::Manage,
pool::Pool,
shard::Shard,
slot::{Slot, SlotMeta},
};
pub struct Pooled<M: Manage, X: Exchange<M>> {
slot: Option<Slot<M::Connection>>,
shard: Rc<Shard<M>>,
pool: Pool<M, X>,
poison: Rc<Cell<bool>>,
}
impl<M: Manage, X: Exchange<M>> Pooled<M, X> {
pub(crate) fn new(slot: Slot<M::Connection>, shard: Rc<Shard<M>>, pool: Pool<M, X>) -> Self {
Self {
slot: Some(slot),
shard,
pool,
poison: Rc::new(Cell::new(false)),
}
}
pub fn meta(&self) -> &SlotMeta {
&self.slot.as_ref().expect("slot present until drop").meta
}
pub fn poison(&self) {
self.poison.set(true);
}
pub fn is_poisoned(&self) -> bool {
self.poison.get()
}
pub fn begin_op(&self) -> OpGuard {
OpGuard {
poison: self.poison.clone(),
armed: true,
}
}
pub fn take(mut self) -> M::Connection {
let slot = self.slot.take().expect("slot present until drop");
self.pool.forget(&self.shard);
slot.conn
}
}
impl<M: Manage, X: Exchange<M>> Deref for Pooled<M, X> {
type Target = M::Connection;
fn deref(&self) -> &Self::Target {
&self.slot.as_ref().expect("slot present until drop").conn
}
}
impl<M: Manage, X: Exchange<M>> DerefMut for Pooled<M, X> {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.slot.as_mut().expect("slot present until drop").conn
}
}
impl<M: Manage, X: Exchange<M>> Drop for Pooled<M, X> {
fn drop(&mut self) {
if let Some(slot) = self.slot.take() {
self.pool.release(&self.shard, slot, self.poison.get());
}
}
}
impl<M: Manage, X: Exchange<M>> std::fmt::Debug for Pooled<M, X> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("Pooled")
.field("poisoned", &self.poison.get())
.field("meta", self.meta())
.finish_non_exhaustive()
}
}
#[must_use = "an OpGuard that is dropped immediately poisons the connection"]
pub struct OpGuard {
poison: Rc<Cell<bool>>,
armed: bool,
}
impl OpGuard {
pub fn complete_op(mut self) {
self.armed = false;
}
}
impl Drop for OpGuard {
fn drop(&mut self) {
if self.armed {
self.poison.set(true);
}
}
}
impl std::fmt::Debug for OpGuard {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("OpGuard")
.field("armed", &self.armed)
.finish()
}
}