use crate::thread::Position;
pub const ORIGIN_CAP: usize = 8;
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub struct Origin {
pub position: Position,
pub command: u32,
}
impl Default for Origin {
fn default() -> Self {
Origin {
position: Position(0),
command: 0,
}
}
}
#[derive(Clone, Debug, Default, PartialEq)]
pub struct Origins {
pub known: Vec<Origin>,
pub more: u32,
}
impl Origins {
pub fn at(position: Position, command: u32) -> Origins {
Origins {
known: vec![Origin {
position,
command: command,
}],
more: 0,
}
}
pub fn is_empty(&self) -> bool {
self.known.is_empty() && self.more == 0
}
pub fn insert(&mut self, o: Origin) {
if self.known.contains(&o) {
return;
}
if self.known.len() < ORIGIN_CAP {
self.known.push(o);
} else {
self.more = self.more.saturating_add(1);
}
}
pub fn union(&mut self, other: &Origins) {
for o in &other.known {
self.insert(*o);
}
self.more = self.more.saturating_add(other.more);
}
pub fn positions(&self) -> impl Iterator<Item = Position> + '_ {
self.known.iter().map(|o| o.position)
}
}
#[derive(Clone, Debug, Default, PartialEq)]
pub struct Prov {
pub origins: Origins,
pub parts: std::sync::Arc<Vec<(String, Prov)>>,
}
impl Prov {
pub fn at(position: Position, command: u32) -> Prov {
Prov {
origins: Origins::at(position, command),
parts: Default::default(),
}
}
pub fn leaf(origins: Origins) -> Prov {
Prov {
origins,
parts: Default::default(),
}
}
pub fn record(parts: Vec<(String, Prov)>) -> Prov {
let mut origins = Origins::default();
for (_, p) in &parts {
origins.union(&p.origins);
}
Prov {
origins,
parts: std::sync::Arc::new(parts),
}
}
pub fn list(items: Vec<Prov>) -> Prov {
Prov::record(
items
.into_iter()
.enumerate()
.map(|(i, p)| (i.to_string(), p))
.collect(),
)
}
pub fn part(&self, key: &str) -> Prov {
self.parts
.iter()
.find(|(k, _)| k == key)
.map(|(_, p)| p.clone())
.unwrap_or_else(|| Prov::leaf(self.origins.clone()))
}
pub fn item(&self, i: usize) -> Prov {
self.part(&i.to_string())
}
pub fn flat(&self) -> Prov {
Prov::leaf(self.origins.clone())
}
}