use sim_lib_control::WorkLimit;
use sim_lib_mutation::ManagedId;
pub trait ManagedRootSource {
fn visit_managed_roots(&self, visit: &mut dyn FnMut(ManagedId) -> bool) -> bool;
}
impl ManagedRootSource for ManagedId {
fn visit_managed_roots(&self, visit: &mut dyn FnMut(ManagedId) -> bool) -> bool {
visit(*self)
}
}
impl<T: ManagedRootSource> ManagedRootSource for Option<T> {
fn visit_managed_roots(&self, visit: &mut dyn FnMut(ManagedId) -> bool) -> bool {
if let Some(value) = self {
value.visit_managed_roots(visit)
} else {
true
}
}
}
impl<T: ManagedRootSource> ManagedRootSource for Vec<T> {
fn visit_managed_roots(&self, visit: &mut dyn FnMut(ManagedId) -> bool) -> bool {
for value in self {
if !value.visit_managed_roots(visit) {
return false;
}
}
true
}
}
impl ManagedRootSource for () {
fn visit_managed_roots(&self, _visit: &mut dyn FnMut(ManagedId) -> bool) -> bool {
true
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum RootScanError {
BudgetExhausted {
visited: usize,
limit: usize,
},
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct RootSnapshot {
roots: Vec<ManagedId>,
}
impl RootSnapshot {
pub fn scan(source: &impl ManagedRootSource, budget: WorkLimit) -> Result<Self, RootScanError> {
let mut roots = Vec::new();
let complete = source.visit_managed_roots(&mut |root| {
if roots.len() == budget.0 {
return false;
}
roots.push(root);
true
});
if !complete {
Err(RootScanError::BudgetExhausted {
visited: budget.0,
limit: budget.0,
})
} else {
Ok(Self { roots })
}
}
pub fn roots(&self) -> &[ManagedId] {
&self.roots
}
}