use std::{
fmt,
ops::{Deref, DerefMut},
sync::Arc,
time::{Duration, Instant},
};
use crate::Database;
use self::inner::SharedPool;
pub use self::options::Builder;
use self::options::Options;
mod executor;
mod inner;
mod options;
pub struct Pool<DB>(Arc<SharedPool<DB>>)
where
DB: Database;
struct Connection<DB: Database> {
live: Option<Live<DB>>,
pool: Arc<SharedPool<DB>>,
}
struct Live<DB: Database> {
raw: DB::Connection,
created: Instant,
}
struct Idle<DB: Database> {
live: Live<DB>,
since: Instant,
}
impl<DB> Pool<DB>
where
DB: Database,
DB::Connection: crate::Connection<Database = DB>,
{
pub async fn new(url: &str) -> crate::Result<Self> {
Self::builder().build(url).await
}
async fn with_options(url: &str, options: Options) -> crate::Result<Self> {
let inner = SharedPool::new_arc(url, options).await?;
Ok(Pool(inner))
}
pub fn builder() -> Builder<DB> {
Builder::new()
}
pub async fn acquire(&self) -> crate::Result<impl DerefMut<Target = DB::Connection>> {
self.0.acquire().await.map(|conn| Connection {
live: Some(conn),
pool: Arc::clone(&self.0),
})
}
pub fn try_acquire(&self) -> Option<impl DerefMut<Target = DB::Connection>> {
self.0.try_acquire().map(|conn| Connection {
live: Some(conn),
pool: Arc::clone(&self.0),
})
}
pub async fn close(&self) {
self.0.close().await;
}
pub fn size(&self) -> u32 {
self.0.size()
}
pub fn idle(&self) -> usize {
self.0.num_idle()
}
pub fn max_size(&self) -> u32 {
self.0.options().max_size
}
pub fn connect_timeout(&self) -> Duration {
self.0.options().connect_timeout
}
pub fn min_size(&self) -> u32 {
self.0.options().min_size
}
pub fn max_lifetime(&self) -> Option<Duration> {
self.0.options().max_lifetime
}
pub fn idle_timeout(&self) -> Option<Duration> {
self.0.options().idle_timeout
}
}
impl<DB> Clone for Pool<DB>
where
DB: Database,
{
fn clone(&self) -> Self {
Self(Arc::clone(&self.0))
}
}
impl<DB: Database> fmt::Debug for Pool<DB> {
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt.debug_struct("Pool")
.field("url", &self.0.url())
.field("size", &self.0.size())
.field("num_idle", &self.0.num_idle())
.field("is_closed", &self.0.is_closed())
.field("options", self.0.options())
.finish()
}
}
const DEREF_ERR: &str = "(bug) connection already released to pool";
impl<DB: Database> Deref for Connection<DB> {
type Target = DB::Connection;
fn deref(&self) -> &Self::Target {
&self.live.as_ref().expect(DEREF_ERR).raw
}
}
impl<DB: Database> DerefMut for Connection<DB> {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.live.as_mut().expect(DEREF_ERR).raw
}
}
impl<DB: Database> Drop for Connection<DB> {
fn drop(&mut self) {
if let Some(live) = self.live.take() {
self.pool.release(live);
}
}
}