use std::collections::HashMap;
use std::sync::{OnceLock, RwLock};
fn registry() -> &'static RwLock<HashMap<String, String>> {
static REGISTRY: OnceLock<RwLock<HashMap<String, String>>> = OnceLock::new();
REGISTRY.get_or_init(|| RwLock::new(HashMap::new()))
}
pub fn set(key: &str, value: &str) {
registry()
.write()
.expect("override registry poisoned")
.insert(key.to_string(), value.to_string());
}
pub fn get(key: &str) -> Option<String> {
if key.is_empty() {
return None; }
registry()
.read()
.expect("override registry poisoned")
.get(key)
.cloned()
}
pub fn clear(key: &str) {
registry()
.write()
.expect("override registry poisoned")
.remove(key);
}
pub fn clear_all() {
registry()
.write()
.expect("override registry poisoned")
.clear();
}
pub fn load_runtime_args() {
use std::sync::OnceLock;
static LOADED: OnceLock<()> = OnceLock::new();
LOADED.get_or_init(|| {
apply_runtime_args(std::env::args().skip(1));
});
}
pub fn apply_runtime_args<I>(args: I)
where
I: IntoIterator<Item = String>,
{
for arg in args {
if let Some(pair) = arg.strip_prefix("-D") {
if let Some((key, value)) = pair.split_once('=') {
if !key.is_empty() {
set(key, value);
}
}
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn set_get_clear() {
set("unit.test.key", "value-1");
assert_eq!(get("unit.test.key"), Some("value-1".to_string()));
clear("unit.test.key");
assert_eq!(get("unit.test.key"), None);
assert_eq!(get(""), None);
}
#[test]
fn runtime_args_parse_dash_d_pairs() {
apply_runtime_args(
[
"-Dlog.format=json",
"-Druntime.arg.test=a=b", "--not-a-property",
"-Dmalformed",
"-D=novalue",
"plainarg",
]
.into_iter()
.map(String::from),
);
assert_eq!(get("log.format"), Some("json".to_string()));
assert_eq!(get("runtime.arg.test"), Some("a=b".to_string()));
assert_eq!(get("malformed"), None);
clear("log.format");
clear("runtime.arg.test");
}
}