use std::cell::RefCell;
use std::collections::BTreeMap;
use std::sync::{LazyLock, RwLock};
use crate::value::DictMap;
type Operations = BTreeMap<String, BTreeMap<String, String>>;
thread_local! {
static SCOPED_MOCKABLE: RefCell<Operations> = const { RefCell::new(BTreeMap::new()) };
}
static MOCKABLE: LazyLock<RwLock<Operations>> = LazyLock::new(|| RwLock::new(BTreeMap::new()));
static CALLABLE: LazyLock<RwLock<Operations>> = LazyLock::new(|| RwLock::new(BTreeMap::new()));
pub(super) fn register_mockable(
capability: impl AsRef<str>,
operation: impl AsRef<str>,
description: impl AsRef<str>,
) {
insert_shared(&MOCKABLE, capability, operation, description);
}
pub(super) fn register_scoped_mockable(
capability: impl AsRef<str>,
operation: impl AsRef<str>,
description: impl AsRef<str>,
) {
SCOPED_MOCKABLE.with(|registered| {
insert(
&mut registered.borrow_mut(),
capability,
operation,
description,
);
});
}
pub(super) fn clear_scoped_mockable() {
SCOPED_MOCKABLE.with(|registered| registered.borrow_mut().clear());
}
pub(super) fn register_callable(
capability: impl AsRef<str>,
operation: impl AsRef<str>,
description: impl AsRef<str>,
) {
insert_shared(&CALLABLE, capability, operation, description);
}
fn insert_shared(
registry: &RwLock<Operations>,
capability: impl AsRef<str>,
operation: impl AsRef<str>,
description: impl AsRef<str>,
) {
insert(
&mut registry
.write()
.unwrap_or_else(std::sync::PoisonError::into_inner),
capability,
operation,
description,
);
}
fn insert(
registry: &mut Operations,
capability: impl AsRef<str>,
operation: impl AsRef<str>,
description: impl AsRef<str>,
) {
registry
.entry(capability.as_ref().to_string())
.or_default()
.insert(
operation.as_ref().to_string(),
description.as_ref().to_string(),
);
}
pub(super) fn apply_mockable(root: &mut DictMap) {
let registered = MOCKABLE
.read()
.unwrap_or_else(std::sync::PoisonError::into_inner);
apply(root, ®istered);
SCOPED_MOCKABLE.with(|scoped| apply(root, &scoped.borrow()));
}
pub(super) fn apply_callable(root: &mut DictMap) {
let registered = CALLABLE
.read()
.unwrap_or_else(std::sync::PoisonError::into_inner);
apply(root, ®istered);
}
fn apply(root: &mut DictMap, registered: &Operations) {
for (capability, operations) in registered {
for (operation, description) in operations {
super::ensure_registered_operation(root, capability, operation, description);
}
}
}