use std::collections::HashMap;
use std::sync::Arc;
use khive_runtime::{BackendId, KhiveRuntime};
#[derive(Clone)]
pub struct BackendEntry {
pub id: BackendId,
pub runtime: Arc<KhiveRuntime>,
}
#[derive(Default)]
pub struct BackendRegistry {
backends: HashMap<String, BackendEntry>,
primary: Option<String>,
}
impl BackendRegistry {
pub fn new() -> Self {
Self::default()
}
pub fn register(&mut self, id: BackendId, runtime: Arc<KhiveRuntime>) -> bool {
let key = id.as_str().to_string();
if self.backends.contains_key(&key) {
return false;
}
if self.primary.is_none() {
self.primary = Some(key.clone());
}
self.backends.insert(key, BackendEntry { id, runtime });
true
}
pub fn get(&self, id: &BackendId) -> Option<&BackendEntry> {
self.backends.get(id.as_str())
}
pub fn primary(&self) -> Option<&BackendEntry> {
self.primary.as_deref().and_then(|k| self.backends.get(k))
}
pub fn iter(&self) -> impl Iterator<Item = &BackendEntry> {
self.backends.values()
}
pub fn len(&self) -> usize {
self.backends.len()
}
pub fn is_empty(&self) -> bool {
self.backends.is_empty()
}
pub fn ids(&self) -> Vec<BackendId> {
self.backends.keys().map(BackendId::new).collect()
}
}
pub struct SubstrateCoordinator {
registry: BackendRegistry,
}
impl SubstrateCoordinator {
pub fn new(registry: BackendRegistry) -> Self {
Self { registry }
}
pub fn single(runtime: Arc<KhiveRuntime>) -> Self {
let mut registry = BackendRegistry::new();
registry.register(BackendId::main(), runtime);
Self { registry }
}
pub fn registry(&self) -> &BackendRegistry {
&self.registry
}
pub fn primary_runtime(&self) -> Option<Arc<KhiveRuntime>> {
self.registry.primary().map(|e| Arc::clone(&e.runtime))
}
pub fn backend_ids(&self) -> Vec<BackendId> {
self.registry.ids()
}
pub fn backend_count(&self) -> usize {
self.registry.len()
}
pub fn is_single_backend(&self) -> bool {
self.registry.len() <= 1
}
}
#[cfg(test)]
mod tests {
use super::*;
use khive_runtime::KhiveRuntime;
fn memory_runtime() -> Arc<KhiveRuntime> {
Arc::new(KhiveRuntime::memory().expect("memory runtime"))
}
#[test]
fn single_coordinator_is_single_backend() {
let coord = SubstrateCoordinator::single(memory_runtime());
assert!(coord.is_single_backend());
assert_eq!(coord.backend_count(), 1);
assert_eq!(coord.backend_ids().len(), 1);
assert_eq!(coord.backend_ids()[0].as_str(), "main");
}
#[test]
fn registry_register_dedup() {
let mut reg = BackendRegistry::new();
let rt = memory_runtime();
assert!(reg.register(BackendId::new("main"), Arc::clone(&rt)));
assert!(!reg.register(BackendId::new("main"), Arc::clone(&rt)));
assert_eq!(reg.len(), 1);
}
#[test]
fn registry_primary_is_first_registered() {
let mut reg = BackendRegistry::new();
let rt1 = memory_runtime();
let rt2 = memory_runtime();
reg.register(BackendId::new("main"), rt1);
reg.register(BackendId::new("lore"), rt2);
assert_eq!(reg.primary().unwrap().id.as_str(), "main");
}
#[test]
fn multi_backend_coordinator_not_single() {
let mut registry = BackendRegistry::new();
registry.register(BackendId::new("main"), memory_runtime());
registry.register(BackendId::new("lore"), memory_runtime());
let coord = SubstrateCoordinator::new(registry);
assert!(!coord.is_single_backend());
assert_eq!(coord.backend_count(), 2);
}
#[test]
fn backend_id_display() {
let id = BackendId::new("archive");
assert_eq!(id.to_string(), "archive");
assert_eq!(id.as_str(), "archive");
}
#[test]
fn backend_id_main_constant() {
assert_eq!(BackendId::main().as_str(), BackendId::MAIN);
}
}