Skip to main content

xianyun_cluster/
registry.rs

1//! Port of `internal/cluster/registry.go`: a registry of driver factories,
2//! keyed by driver name, that [`new_manager`] and [`list_drivers`] read from.
3
4use crate::driver::{Driver, DriverError};
5use std::collections::HashMap;
6use std::sync::{LazyLock, RwLock};
7use xianyun_core::config::types::ClusterConfig;
8
9/// Port of `cluster.DriverFactory`.
10pub type DriverFactory = fn(ClusterConfig, String) -> Box<dyn Driver>;
11
12static REGISTRY: LazyLock<RwLock<HashMap<String, DriverFactory>>> =
13    LazyLock::new(|| RwLock::new(HashMap::new()));
14
15/// Port of `cluster.RegisterDriver`.
16///
17/// # Panics
18///
19/// Panics if a driver with the same name is already registered.
20pub fn register_driver(name: &str, factory: DriverFactory) {
21    let mut registry = REGISTRY
22        .write()
23        .unwrap_or_else(std::sync::PoisonError::into_inner);
24    assert!(
25        !registry.contains_key(name),
26        "driver already registered: {name}"
27    );
28    registry.insert(name.to_string(), factory);
29}
30
31/// Port of `cluster.NewManager`.
32///
33/// # Errors
34///
35/// Returns `DriverError::DriverNotFound` if the driver named in
36/// `cfg.driver` is not registered.
37pub fn new_manager(
38    cfg: ClusterConfig,
39    profile_name: String,
40) -> Result<Box<dyn Driver>, DriverError> {
41    let registry = REGISTRY
42        .read()
43        .unwrap_or_else(std::sync::PoisonError::into_inner);
44    let factory = registry
45        .get(cfg.driver.as_str())
46        .ok_or_else(|| DriverError::DriverNotFound(cfg.driver.clone()))?;
47    Ok(factory(cfg, profile_name))
48}
49
50/// Port of `cluster.ListDrivers`.
51pub fn list_drivers() -> Vec<String> {
52    let mut names: Vec<String> = REGISTRY
53        .read()
54        .unwrap_or_else(std::sync::PoisonError::into_inner)
55        .keys()
56        .cloned()
57        .collect();
58    names.sort();
59    names
60}
61
62/// Test-only hook: clears the global registry so each test can start from
63/// a clean slate, mirroring the Go tests' direct save/restore of the
64/// package-private `registry` map (only possible there because those tests
65/// live in `package cluster` itself, so a plain `#[cfg(test)]` cannot reach
66/// it from this crate's separate `tests/` integration binaries). Kept
67/// always-compiled but `#[doc(hidden)]` and explicitly *not* part of the
68/// public API contract: it exists solely so integration tests can reset
69/// global registry state between cases.
70#[doc(hidden)]
71pub fn __reset_for_tests() {
72    REGISTRY
73        .write()
74        .unwrap_or_else(std::sync::PoisonError::into_inner)
75        .clear();
76}