use std::cell::RefCell;
thread_local! {
static DECLARED: RefCell<Option<Vec<String>>> = const { RefCell::new(None) };
}
pub struct DeclaredMachines {
previous: Option<Vec<String>>,
}
impl DeclaredMachines {
#[must_use]
pub fn of(machines: &[String]) -> Self {
let previous = DECLARED.with(|c| c.borrow_mut().replace(machines.to_vec()));
Self { previous }
}
}
impl Drop for DeclaredMachines {
fn drop(&mut self) {
let previous = self.previous.take();
DECLARED.with(|c| *c.borrow_mut() = previous);
}
}
#[must_use]
pub(super) fn declared() -> Option<Vec<String>> {
DECLARED.with(|c| c.borrow().clone())
}
#[cfg(test)]
mod tests {
use super::*;
fn names(of: &[&str]) -> Vec<String> {
of.iter().map(|s| (*s).to_string()).collect()
}
#[test]
fn without_the_guard_nothing_is_declared() {
assert_eq!(declared(), None);
}
#[test]
fn the_guard_is_released_on_drop_and_nests() {
{
let _outer = DeclaredMachines::of(&names(&["mini", "lambda-labs"]));
assert_eq!(declared(), Some(names(&["mini", "lambda-labs"])));
{
let _inner = DeclaredMachines::of(&names(&["clean-room"]));
assert_eq!(declared(), Some(names(&["clean-room"])));
}
assert_eq!(
declared(),
Some(names(&["mini", "lambda-labs"])),
"an inner scope must not outlive itself"
);
}
assert_eq!(declared(), None, "and the outer scope releases too");
}
#[test]
fn declaring_nothing_is_a_claim_not_an_absence() {
let _guard = DeclaredMachines::of(&[]);
assert_eq!(declared(), Some(Vec::new()));
}
}