#[derive(Debug, Clone, PartialEq, Eq)]
pub(crate) struct UsageHashMap<V>
{
map: HashMap<String, (V, Cell<u64>)>,
could_not_resolve_program_error: ParseError,
not_all_values_have_been_used_program_error: fn(Vec<String>) -> ParseError,
}
impl<V> UsageHashMap<V>
{
#[inline(always)]
pub(crate) fn new(could_not_resolve_program_error: ParseError, not_all_values_have_been_used_program_error: fn(Vec<String>) -> ParseError) -> Self
{
Self
{
map: HashMap::default(),
could_not_resolve_program_error,
not_all_values_have_been_used_program_error,
}
}
#[inline(always)]
pub(crate) fn insert<'name>(&mut self, key: String, value: V)
{
let previous = self.map.insert(key, (value, Cell::default()));
debug_assert!(previous.is_none());
}
#[inline(always)]
pub(crate) fn resolve(&self, key: &str) -> Result<&V, ParseError>
{
match self.map.get(key)
{
Some((value, usage_count)) =>
{
usage_count.set(usage_count.get().saturating_add(1));
Ok(value)
}
None => Err(self.could_not_resolve_program_error.clone()),
}
}
#[inline(always)]
pub(crate) fn guard_all_values_have_been_resolved_at_least_once(self) -> Result<(), ParseError>
{
let mut unused = Vec::new();
for (name, (_, usage_count)) in self.map
{
if unlikely!(usage_count.get() == 0)
{
unused.push(name)
}
}
if likely!(unused.is_empty())
{
Ok(())
}
else
{
Err((self.not_all_values_have_been_used_program_error)(unused))
}
}
}