use std::sync::{Arc, Mutex};
use crate::kit::{AsyncKit, AsyncReady};
static KIT: Mutex<Option<Arc<AsyncKit<AsyncReady>>>> = Mutex::new(None);
pub fn init_kit(kit: AsyncKit<AsyncReady>) -> Result<(), String> {
let mut guard = KIT.lock().map_err(|_| "Kit lock poisoned".to_string())?;
if guard.is_some() {
return Err("Kit already initialized".to_string());
}
*guard = Some(Arc::new(kit));
Ok(())
}
#[must_use]
pub fn kit() -> Option<Arc<AsyncKit<AsyncReady>>> {
KIT.lock()
.map_err(|e| tracing::error!("Kit mutex poisoned: {e}"))
.ok()
.and_then(|guard| guard.clone())
}
#[cfg(test)]
pub fn reset_kit_for_testing() {
if let Ok(mut guard) = KIT.lock() {
*guard = None;
}
}
#[cfg(test)]
pub fn force_reset_kit_for_testing() {
match KIT.lock() {
Ok(mut guard) => *guard = None,
Err(poisoned) => *poisoned.into_inner() = None,
}
}
#[cfg(test)]
pub fn force_init_kit_for_testing(kit: AsyncKit<AsyncReady>) {
match KIT.lock() {
Ok(mut guard) => *guard = Some(Arc::new(kit)),
Err(poisoned) => *poisoned.into_inner() = Some(Arc::new(kit)),
}
}
#[cfg(test)]
pub fn kit_debug_state() -> String {
match KIT.lock() {
Ok(guard) => format!("kit_is_some={}, not_poisoned", guard.is_some()),
Err(_) => "POISONED".to_string(),
}
}
#[cfg(test)]
mod tests {
use super::*;
#[serial_test::serial(kit_init)]
#[tokio::test]
async fn init_kit_second_call_returns_error() {
reset_kit_for_testing();
let kit1 = AsyncKit::new().build().await.expect("build kit1");
assert!(init_kit(kit1).is_ok(), "first init_kit should succeed");
let kit2 = AsyncKit::new().build().await.expect("build kit2");
let result = init_kit(kit2);
assert!(result.is_err(), "second init_kit call must return Err");
assert!(
result.unwrap_err().contains("already initialized"),
"error message should mention 'already initialized'"
);
reset_kit_for_testing();
}
}