#![allow(dead_code)]
use std::{
marker::PhantomData,
rc::Rc,
sync::{
Arc, Mutex, MutexGuard,
atomic::{AtomicBool, AtomicU64, Ordering::SeqCst},
},
task::Waker,
};
use crate::{
manage::{Detach, Manage},
slot::SlotMeta,
};
#[derive(Debug, Default)]
pub(crate) struct Counts {
pub connected: AtomicU64,
pub disconnected: AtomicU64,
pub recycled: AtomicU64,
}
impl Counts {
pub(crate) fn connected(&self) -> u64 {
self.connected.load(SeqCst)
}
pub(crate) fn disconnected(&self) -> u64 {
self.disconnected.load(SeqCst)
}
pub(crate) fn recycled(&self) -> u64 {
self.recycled.load(SeqCst)
}
}
#[derive(Debug)]
pub(crate) struct TestConn {
pub id: u64,
_not_send: Rc<()>,
}
impl TestConn {
pub(crate) fn new(id: u64) -> Self {
Self {
id,
_not_send: Rc::new(()),
}
}
}
pub(crate) struct TestManager {
counts: Arc<Counts>,
next_id: AtomicU64,
fail_connect: AtomicBool,
fail_recycle: AtomicBool,
hang_connect: AtomicBool,
hang_recycle: AtomicBool,
}
impl TestManager {
pub(crate) fn new() -> Self {
Self {
counts: Arc::new(Counts::default()),
next_id: AtomicU64::new(0),
fail_connect: AtomicBool::new(false),
fail_recycle: AtomicBool::new(false),
hang_connect: AtomicBool::new(false),
hang_recycle: AtomicBool::new(false),
}
}
pub(crate) fn counts(&self) -> Arc<Counts> {
self.counts.clone()
}
pub(crate) fn fail_connect(&self, v: bool) {
self.fail_connect.store(v, SeqCst);
}
pub(crate) fn fail_recycle(&self, v: bool) {
self.fail_recycle.store(v, SeqCst);
}
pub(crate) fn hang_connect(&self, v: bool) {
self.hang_connect.store(v, SeqCst);
}
pub(crate) fn hang_recycle(&self, v: bool) {
self.hang_recycle.store(v, SeqCst);
}
}
impl Manage for TestManager {
type Connection = TestConn;
type Error = &'static str;
async fn connect(&self) -> Result<TestConn, &'static str> {
if self.hang_connect.load(SeqCst) {
std::future::pending::<()>().await;
}
if self.fail_connect.load(SeqCst) {
return Err("connect refused");
}
self.counts.connected.fetch_add(1, SeqCst);
Ok(TestConn::new(self.next_id.fetch_add(1, SeqCst)))
}
async fn recycle(&self, _conn: &mut TestConn, _meta: &SlotMeta) -> Result<(), &'static str> {
if self.hang_recycle.load(SeqCst) {
std::future::pending::<()>().await;
}
self.counts.recycled.fetch_add(1, SeqCst);
if self.fail_recycle.load(SeqCst) {
return Err("stale");
}
Ok(())
}
fn disconnect(&self, _conn: TestConn) {
self.counts.disconnected.fetch_add(1, SeqCst);
}
}
pub(crate) struct DefaultDisconnectManager;
impl Manage for DefaultDisconnectManager {
type Connection = TestConn;
type Error = &'static str;
async fn connect(&self) -> Result<TestConn, &'static str> {
Ok(TestConn::new(0))
}
async fn recycle(&self, _conn: &mut TestConn, _meta: &SlotMeta) -> Result<(), &'static str> {
Ok(())
}
}
#[derive(Debug)]
pub(crate) struct MovableConn {
pub id: u64,
_not_send: PhantomData<*const ()>,
}
impl MovableConn {
pub(crate) fn new(id: u64) -> Self {
Self {
id,
_not_send: PhantomData,
}
}
}
pub(crate) struct MovableManager {
counts: Arc<Counts>,
next_id: AtomicU64,
}
impl MovableManager {
pub(crate) fn new() -> Self {
Self {
counts: Arc::new(Counts::default()),
next_id: AtomicU64::new(0),
}
}
pub(crate) fn counts(&self) -> Arc<Counts> {
self.counts.clone()
}
}
impl Manage for MovableManager {
type Connection = MovableConn;
type Error = &'static str;
async fn connect(&self) -> Result<MovableConn, &'static str> {
self.counts.connected.fetch_add(1, SeqCst);
Ok(MovableConn::new(self.next_id.fetch_add(1, SeqCst)))
}
async fn recycle(&self, _conn: &mut MovableConn, _meta: &SlotMeta) -> Result<(), &'static str> {
self.counts.recycled.fetch_add(1, SeqCst);
Ok(())
}
fn disconnect(&self, _conn: MovableConn) {
self.counts.disconnected.fetch_add(1, SeqCst);
}
}
pub(crate) static CAN_DETACH: AtomicBool = AtomicBool::new(true);
pub(crate) static CAN_ATTACH: AtomicBool = AtomicBool::new(true);
static DETACH_LOCK: Mutex<()> = Mutex::new(());
pub(crate) fn detach_lock() -> DetachGuard {
let guard = DETACH_LOCK.lock().unwrap_or_else(|p| p.into_inner());
CAN_DETACH.store(true, SeqCst);
CAN_ATTACH.store(true, SeqCst);
DetachGuard(Some(guard))
}
pub(crate) struct DetachGuard(Option<MutexGuard<'static, ()>>);
impl Drop for DetachGuard {
fn drop(&mut self) {
CAN_DETACH.store(true, SeqCst);
CAN_ATTACH.store(true, SeqCst);
drop(self.0.take());
}
}
impl Detach for MovableManager {
type Parked = u64;
fn detach(conn: MovableConn) -> Option<u64> {
CAN_DETACH.load(SeqCst).then_some(conn.id)
}
async fn attach(id: u64) -> Result<MovableConn, &'static str> {
if !CAN_ATTACH.load(SeqCst) {
return Err("cannot attach");
}
Ok(MovableConn::new(id))
}
}
#[derive(Debug, Default)]
pub(crate) struct CountingWaker(AtomicU64);
impl CountingWaker {
pub(crate) fn new() -> Arc<Self> {
Arc::new(Self::default())
}
pub(crate) fn count(&self) -> u64 {
self.0.load(SeqCst)
}
}
impl std::task::Wake for CountingWaker {
fn wake(self: Arc<Self>) {
self.0.fetch_add(1, SeqCst);
}
fn wake_by_ref(self: &Arc<Self>) {
self.0.fetch_add(1, SeqCst);
}
}
pub(crate) fn counting_waker() -> (Arc<CountingWaker>, Waker) {
let arc = CountingWaker::new();
let waker = Waker::from(arc.clone());
(arc, waker)
}