use crate::{
Acquisition, Error, Options, Pool, ResourceId, Retirement, Stats,
core::{Acquired, Core, Slot},
};
use base_scheduler::Cancellation;
use std::{
ops::{Deref, DerefMut},
sync::{Arc, Weak},
};
struct SingleSlot<R> {
resource: Option<R>,
draining: bool,
}
impl<R: Send> Slot for SingleSlot<R> {
type Resource = R;
type Acquired = R;
fn available(&self) -> bool {
!self.draining && self.resource.is_some()
}
fn acquire(&mut self) -> R {
self.resource.take().unwrap()
}
fn uses(&self) -> usize {
usize::from(self.resource.is_none())
}
fn draining(&self) -> bool {
self.draining
}
fn drain(&mut self) {
self.draining = true;
}
fn into_resource(self) -> R {
self.resource.unwrap()
}
}
pub struct SingleplexPool<R: Send> {
core: Arc<Core<SingleSlot<R>>>,
}
impl<R: Send> Clone for SingleplexPool<R> {
fn clone(&self) -> Self {
Self {
core: self.core.clone(),
}
}
}
impl<R: Send> SingleplexPool<R> {
pub fn new(options: Options) -> Result<Self, Error> {
Ok(Self {
core: Core::new(options)?,
})
}
pub async fn acquire_or_reserve(
&self,
cancel: &Cancellation,
) -> Result<Acquisition<SingleplexLease<R>, SingleplexBuildPermit<R>>, Error> {
Ok(match self.core.acquire(cancel).await? {
Acquired::Existing(id, resource) => Acquisition::Existing(SingleplexLease {
core: self.core.clone(),
id,
resource: Some(resource),
}),
Acquired::Build(id) => Acquisition::Build(SingleplexBuildPermit {
core: self.core.clone(),
id,
pending: true,
}),
})
}
pub fn begin_close(&self) {
self.core.begin_close();
}
pub fn stats(&self) -> Stats {
self.core.stats()
}
pub fn prune(&self, retain: usize) -> usize {
self.core.prune(retain)
}
pub fn try_retirement(&self) -> Option<Retirement<R>> {
self.core.retirements.pop()
}
pub async fn next_retirement(
&self,
cancel: &Cancellation,
) -> Result<Option<Retirement<R>>, Error> {
self.core.next_retirement(cancel).await
}
pub async fn wait_closed(&self, cancel: &Cancellation) -> Result<(), Error> {
self.core.wait_closed(cancel).await
}
}
impl<R: Send> Pool for SingleplexPool<R> {
type Permit = SingleplexLease<R>;
type BuildPermit = SingleplexBuildPermit<R>;
async fn acquire_or_reserve(
&self,
cancel: &Cancellation,
) -> Result<Acquisition<Self::Permit, Self::BuildPermit>, Error> {
self.acquire_or_reserve(cancel).await
}
fn begin_close(&self) {
self.begin_close();
}
fn stats(&self) -> Stats {
self.stats()
}
}
pub struct SingleplexBuildPermit<R: Send> {
core: Arc<Core<SingleSlot<R>>>,
id: ResourceId,
pending: bool,
}
impl<R: Send> SingleplexBuildPermit<R> {
pub fn id(&self) -> ResourceId {
self.id
}
pub fn commit(mut self, resource: R) -> Result<SingleplexResource<R>, Error> {
self.core.commit(
self.id,
SingleSlot {
resource: Some(resource),
draining: false,
},
)?;
self.pending = false;
Ok(SingleplexResource {
core: Arc::downgrade(&self.core),
id: self.id,
})
}
}
impl<R: Send> Drop for SingleplexBuildPermit<R> {
fn drop(&mut self) {
if self.pending {
self.core.abort_build(self.id);
}
}
}
pub struct SingleplexResource<R: Send> {
core: Weak<Core<SingleSlot<R>>>,
id: ResourceId,
}
impl<R: Send> Clone for SingleplexResource<R> {
fn clone(&self) -> Self {
Self {
core: self.core.clone(),
id: self.id,
}
}
}
impl<R: Send> SingleplexResource<R> {
pub fn id(&self) -> ResourceId {
self.id
}
pub fn retire(&self) -> bool {
self.core.upgrade().is_some_and(|core| core.retire(self.id))
}
}
pub struct SingleplexLease<R: Send> {
core: Arc<Core<SingleSlot<R>>>,
id: ResourceId,
resource: Option<R>,
}
impl<R: Send> SingleplexLease<R> {
pub fn id(&self) -> ResourceId {
self.id
}
pub fn release(mut self) {
self.finish(false);
}
pub fn retire(mut self) {
self.finish(true);
}
fn finish(&mut self, retire: bool) {
let Some(resource) = self.resource.take() else {
return;
};
let retired = {
let mut state = self.core.lock();
let slot = state.slots.get_mut(&self.id).unwrap();
if retire {
slot.drain();
}
debug_assert!(slot.resource.is_none());
slot.resource = Some(resource);
self.core.remove_if_drained(&mut state, self.id)
};
self.core.enqueue(self.id, retired);
}
}
impl<R: Send> Deref for SingleplexLease<R> {
type Target = R;
fn deref(&self) -> &R {
self.resource.as_ref().unwrap()
}
}
impl<R: Send> DerefMut for SingleplexLease<R> {
fn deref_mut(&mut self) -> &mut R {
self.resource.as_mut().unwrap()
}
}
impl<R: Send> Drop for SingleplexLease<R> {
fn drop(&mut self) {
self.finish(true);
}
}