use std::sync::{Arc, Mutex, OnceLock};
pub trait DriverSupport: Send + Sync + 'static {
fn report(&self, level: i32) -> Option<String>;
}
static DRIVER_SUPPORT: OnceLock<Mutex<Vec<(String, Arc<dyn DriverSupport>)>>> = OnceLock::new();
fn table() -> &'static Mutex<Vec<(String, Arc<dyn DriverSupport>)>> {
DRIVER_SUPPORT.get_or_init(|| Mutex::new(Vec::new()))
}
pub fn register_driver_support(name: &str, drvet: Arc<dyn DriverSupport>) -> bool {
let mut table = table().lock().expect("driver support registry poisoned");
if table.iter().any(|(n, _)| n == name) {
return false;
}
table.push((name.to_string(), drvet));
true
}
pub fn find_driver_support(name: &str) -> Option<Arc<dyn DriverSupport>> {
let table = table().lock().expect("driver support registry poisoned");
table
.iter()
.find(|(n, _)| n == name)
.map(|(_, d)| Arc::clone(d))
}
pub fn driver_supports() -> Vec<(String, Arc<dyn DriverSupport>)> {
table()
.lock()
.expect("driver support registry poisoned")
.clone()
}
pub(crate) fn driver_support_entries() -> Vec<(String, usize)> {
table()
.lock()
.expect("driver support registry poisoned")
.iter()
.map(|(name, drvet)| (name.clone(), Arc::as_ptr(drvet) as *const () as usize))
.collect()
}
#[cfg(test)]
mod tests {
use super::*;
struct Reporting(&'static str);
impl DriverSupport for Reporting {
fn report(&self, level: i32) -> Option<String> {
Some(format!("{} at level {level}", self.0))
}
}
struct Silent;
impl DriverSupport for Silent {
fn report(&self, _level: i32) -> Option<String> {
None
}
}
#[test]
fn a_registered_driver_is_found_and_an_unknown_one_is_not() {
assert!(register_driver_support(
"drvRegistryProbe",
Arc::new(Reporting("probe"))
));
let found = find_driver_support("drvRegistryProbe").expect("just registered");
assert_eq!(found.report(2).as_deref(), Some("probe at level 2"));
assert!(find_driver_support("drvNoSuchDriverProbe").is_none());
}
#[test]
fn a_duplicate_registration_is_refused_and_the_first_entry_stands() {
assert!(register_driver_support("drvDupProbe", Arc::new(Silent)));
assert!(!register_driver_support(
"drvDupProbe",
Arc::new(Reporting("second"))
));
assert_eq!(
find_driver_support("drvDupProbe")
.expect("registered")
.report(0),
None,
"the first, report-less entry table is still the registered one"
);
assert_eq!(
driver_support_entries()
.iter()
.filter(|(n, _)| n == "drvDupProbe")
.count(),
1
);
}
#[test]
fn each_driver_entry_has_its_own_address() {
register_driver_support("drvAddrProbeA", Arc::new(Silent));
register_driver_support("drvAddrProbeB", Arc::new(Silent));
let entries = driver_support_entries();
let a = entries
.iter()
.find(|(n, _)| n == "drvAddrProbeA")
.unwrap()
.1;
let b = entries
.iter()
.find(|(n, _)| n == "drvAddrProbeB")
.unwrap()
.1;
assert_ne!(a, 0);
assert_ne!(a, b);
}
}