use crate::data::store::{LocaleProfile, RegistryStore};
use arc_swap::ArcSwap;
use std::sync::Arc;
pub trait IRegistryState: Send + Sync {
fn get_profile(&self, id: &str) -> Option<Arc<LocaleProfile>>;
fn resolve_alias(&self, tag: &str) -> Option<String>;
fn get_version(&self) -> String;
fn get_base_resource_uri(&self) -> String;
}
#[derive(Debug, Clone)]
pub struct RegistryState {
active_store: Arc<ArcSwap<RegistryStore>>,
}
impl Default for RegistryState {
fn default() -> Self {
Self::new()
}
}
impl RegistryState {
#[must_use]
pub fn new() -> Self {
let store = RegistryStore::new();
Self { active_store: Arc::new(ArcSwap::from_pointee(store)) }
}
pub fn swap_registry(&self, new_store: RegistryStore) {
self.active_store.store(Arc::new(new_store));
}
}
impl IRegistryState for RegistryState {
fn get_profile(&self, id: &str) -> Option<Arc<LocaleProfile>> {
let store = self.active_store.load();
store.get_profile(id)
}
fn resolve_alias(&self, tag: &str) -> Option<String> {
let store = self.active_store.load();
store.resolve_alias(tag)
}
fn get_version(&self) -> String {
self.active_store.load().metadata.version.clone()
}
fn get_base_resource_uri(&self) -> String {
self.active_store.load().base_resource_uri.to_string()
}
}
#[cfg(test)]
mod tests {
use super::*;
use bistun_core::manifest::TraitValue;
use bistun_core::traits::{Direction, MorphType, SegType, TraitKey};
use hashbrown::HashMap;
fn create_mock_profile() -> LocaleProfile {
let mut traits = HashMap::new();
traits.insert(TraitKey::MorphologyType, TraitValue::MorphType(MorphType::TEMPLATIC));
traits.insert(TraitKey::SegmentationStrategy, TraitValue::SegType(SegType::SPACE));
traits.insert(TraitKey::PrimaryDirection, TraitValue::Direction(Direction::RTL));
LocaleProfile {
id: "ar-EG".to_string(),
traits,
rules: HashMap::new(),
resources: HashMap::new(),
}
}
#[test]
fn test_registry_wait_free_hot_swap() {
let state = RegistryState::new();
assert!(state.get_profile("ar-EG").is_none());
let mut new_store = RegistryStore::new();
new_store.insert_stub(create_mock_profile());
new_store.insert_alias("in".to_string(), "id".to_string());
new_store.set_base_resource_uri("https://test.cdn.bistun.io/".to_string());
let worker_state = state.clone();
state.swap_registry(new_store);
let profile =
worker_state.get_profile("ar-EG").expect("LMS-TEST: Swap failed on cloned state");
let direction =
profile.traits.get(&TraitKey::PrimaryDirection).expect("LMS-TEST: Missing trait");
assert_eq!(*direction, TraitValue::Direction(Direction::RTL));
assert_eq!(worker_state.resolve_alias("in"), Some("id".to_string()));
assert_eq!(worker_state.get_base_resource_uri(), "https://test.cdn.bistun.io/");
}
}