use std::collections::{HashMap, HashSet};
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
pub enum Provenance {
Captured,
Generated,
}
#[derive(Clone, Default, Debug)]
pub struct Produced {
values: HashMap<String, String>,
generated: HashSet<String>,
}
impl Produced {
pub fn record_captured(&mut self, name: &str, value: &str) {
self.values.insert(name.to_string(), value.to_string());
self.generated.remove(name);
}
pub fn record_generated(&mut self, name: &str, value: &str) {
self.values.insert(name.to_string(), value.to_string());
self.generated.insert(name.to_string());
}
pub fn get(&self, name: &str) -> Option<&String> {
self.values.get(name)
}
pub fn contains(&self, name: &str) -> bool {
self.values.contains_key(name)
}
pub fn is_generated(&self, name: &str) -> bool {
self.generated.contains(name)
}
pub fn iter(&self) -> impl Iterator<Item = (&String, &String)> {
self.values.iter()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn a_capture_that_fires_clears_the_generated_mark() {
let mut p = Produced::default();
p.record_generated("sid", "MINTED");
assert!(p.is_generated("sid"));
p.record_captured("sid", "SERVER");
assert_eq!(p.get("sid").map(String::as_str), Some("SERVER"));
assert!(
!p.is_generated("sid"),
"the capture answered, so it is not minted"
);
}
#[test]
fn a_name_nothing_produced_has_no_provenance() {
let p = Produced::default();
assert!(!p.contains("sid"));
assert!(!p.is_generated("sid"));
}
#[test]
fn a_generated_value_that_a_capture_never_answered_stays_generated() {
let mut p = Produced::default();
p.record_generated("sid", "MINTED");
p.record_captured("other", "X");
assert!(p.is_generated("sid"));
}
}