use std::any::Any;
use std::collections::HashMap;
use std::fmt::Debug;
use std::future::Future;
use std::sync::{Arc, Mutex, OnceLock, RwLock, Weak};
type Key = (&'static str, String);
static REGISTRY: OnceLock<RwLock<HashMap<Key, Weak<dyn Any + Send + Sync>>>> = OnceLock::new();
fn registry() -> &'static RwLock<HashMap<Key, Weak<dyn Any + Send + Sync>>> {
REGISTRY.get_or_init(|| RwLock::new(HashMap::new()))
}
static INFLIGHT: OnceLock<Mutex<HashMap<Key, Arc<tokio::sync::Mutex<()>>>>> = OnceLock::new();
fn inflight() -> &'static Mutex<HashMap<Key, Arc<tokio::sync::Mutex<()>>>> {
INFLIGHT.get_or_init(|| Mutex::new(HashMap::new()))
}
pub fn connection_identity<H: Debug>(identity: H) -> String {
format!("{identity:?}")
}
pub async fn get_or_create<T, F, Fut>(
tag: &'static str,
identity: String,
shared: bool,
build: F,
) -> anyhow::Result<Arc<T>>
where
T: Send + Sync + 'static,
F: FnOnce() -> Fut,
Fut: Future<Output = anyhow::Result<T>>,
{
if !shared {
return Ok(Arc::new(build().await?));
}
let key = (tag, identity);
if let Some(existing) = lookup::<T>(&key) {
return Ok(existing);
}
let build_lock = {
let mut inflight = inflight()
.lock()
.expect("connection registry inflight lock poisoned");
Arc::clone(inflight.entry(key.clone()).or_default())
};
let _build_guard = build_lock.lock().await;
if let Some(existing) = lookup::<T>(&key) {
return Ok(existing);
}
let built: Arc<T> = match build().await {
Ok(client) => Arc::new(client),
Err(err) => {
let mut inflight = inflight()
.lock()
.expect("connection registry inflight lock poisoned");
if inflight
.get(&key)
.is_some_and(|queued| Arc::ptr_eq(queued, &build_lock))
&& Arc::strong_count(&build_lock) == 2
{
inflight.remove(&key);
}
return Err(err);
}
};
let resolved = {
let mut map = registry()
.write()
.expect("connection registry lock poisoned");
map.retain(|_, weak| weak.strong_count() > 0);
match map
.get(&key)
.and_then(Weak::upgrade)
.and_then(|arc| arc.downcast::<T>().ok())
{
Some(existing) => existing,
None => {
map.insert(
key.clone(),
Arc::downgrade(&(built.clone() as Arc<dyn Any + Send + Sync>)),
);
built
}
}
};
drop(_build_guard);
inflight()
.lock()
.expect("connection registry inflight lock poisoned")
.remove(&key);
Ok(resolved)
}
fn lookup<T: Send + Sync + 'static>(key: &Key) -> Option<Arc<T>> {
let map = registry()
.read()
.expect("connection registry lock poisoned");
map.get(key)
.and_then(Weak::upgrade)
.and_then(|arc| arc.downcast::<T>().ok())
}
#[cfg(test)]
mod tests {
use super::*;
use std::sync::atomic::{AtomicUsize, Ordering};
async fn build_client(value: u32) -> anyhow::Result<u32> {
Ok(value)
}
#[tokio::test]
async fn shared_key_returns_same_arc_and_builds_once() {
let builds = Arc::new(AtomicUsize::new(0));
let id = connection_identity(("broker:9092", "alice"));
let make = |value: u32| {
let builds = builds.clone();
move || {
let builds = builds.clone();
async move {
builds.fetch_add(1, Ordering::SeqCst);
Ok(value)
}
}
};
let a = get_or_create("test-share", id.clone(), true, make(1))
.await
.unwrap();
let b = get_or_create("test-share", id, true, make(2))
.await
.unwrap();
assert!(Arc::ptr_eq(&a, &b));
assert_eq!(*a, 1); assert_eq!(builds.load(Ordering::SeqCst), 1);
}
#[tokio::test(flavor = "multi_thread", worker_threads = 4)]
async fn concurrent_cold_callers_build_once() {
let builds = Arc::new(AtomicUsize::new(0));
let id = connection_identity(("broker:9092", "concurrent"));
let mut handles = Vec::new();
for _ in 0..16 {
let builds = builds.clone();
let id = id.clone();
handles.push(tokio::spawn(async move {
get_or_create("test-concurrent", id, true, || {
let builds = builds.clone();
async move {
builds.fetch_add(1, Ordering::SeqCst);
tokio::time::sleep(std::time::Duration::from_millis(20)).await;
Ok(42u32)
}
})
.await
.unwrap()
}));
}
let first = handles.pop().unwrap().await.unwrap();
for h in handles {
assert!(Arc::ptr_eq(&first, &h.await.unwrap()));
}
assert_eq!(builds.load(Ordering::SeqCst), 1);
}
#[tokio::test]
async fn not_shared_always_builds_fresh() {
let id = connection_identity(("broker:9092", "bob"));
let a = get_or_create("test-dedicated", id.clone(), false, || build_client(1))
.await
.unwrap();
let b = get_or_create("test-dedicated", id, false, || build_client(1))
.await
.unwrap();
assert!(!Arc::ptr_eq(&a, &b));
}
#[tokio::test]
async fn entry_released_after_last_arc_drops() {
let id = connection_identity(("broker:9092", "carol"));
let a = get_or_create("test-release", id.clone(), true, || build_client(7))
.await
.unwrap();
let key = ("test-release", id);
assert!(lookup::<u32>(&key).is_some());
drop(a);
assert!(lookup::<u32>(&key).is_none());
}
#[tokio::test]
async fn differing_identity_yields_distinct_clients() {
let a = get_or_create("test-id", connection_identity("server-a"), true, || {
build_client(1)
})
.await
.unwrap();
let b = get_or_create("test-id", connection_identity("server-b"), true, || {
build_client(2)
})
.await
.unwrap();
assert!(!Arc::ptr_eq(&a, &b));
}
}