sim_lib_machine/
managed.rs1use sim_lib_control::WorkLimit;
2use sim_lib_mutation::ManagedId;
3
4pub trait ManagedRootSource {
10 fn visit_managed_roots(&self, visit: &mut dyn FnMut(ManagedId) -> bool) -> bool;
14}
15
16impl ManagedRootSource for ManagedId {
17 fn visit_managed_roots(&self, visit: &mut dyn FnMut(ManagedId) -> bool) -> bool {
18 visit(*self)
19 }
20}
21
22impl<T: ManagedRootSource> ManagedRootSource for Option<T> {
23 fn visit_managed_roots(&self, visit: &mut dyn FnMut(ManagedId) -> bool) -> bool {
24 if let Some(value) = self {
25 value.visit_managed_roots(visit)
26 } else {
27 true
28 }
29 }
30}
31
32impl<T: ManagedRootSource> ManagedRootSource for Vec<T> {
33 fn visit_managed_roots(&self, visit: &mut dyn FnMut(ManagedId) -> bool) -> bool {
34 for value in self {
35 if !value.visit_managed_roots(visit) {
36 return false;
37 }
38 }
39 true
40 }
41}
42
43impl ManagedRootSource for () {
44 fn visit_managed_roots(&self, _visit: &mut dyn FnMut(ManagedId) -> bool) -> bool {
45 true
46 }
47}
48
49#[derive(Clone, Copy, Debug, PartialEq, Eq)]
51pub enum RootScanError {
52 BudgetExhausted {
54 visited: usize,
56 limit: usize,
58 },
59}
60
61#[derive(Clone, Debug, PartialEq, Eq)]
63pub struct RootSnapshot {
64 roots: Vec<ManagedId>,
65}
66
67impl RootSnapshot {
68 pub fn scan(source: &impl ManagedRootSource, budget: WorkLimit) -> Result<Self, RootScanError> {
70 let mut roots = Vec::new();
71 let complete = source.visit_managed_roots(&mut |root| {
72 if roots.len() == budget.0 {
73 return false;
74 }
75 roots.push(root);
76 true
77 });
78 if !complete {
79 Err(RootScanError::BudgetExhausted {
80 visited: budget.0,
81 limit: budget.0,
82 })
83 } else {
84 Ok(Self { roots })
85 }
86 }
87
88 pub fn roots(&self) -> &[ManagedId] {
90 &self.roots
91 }
92}