Skip to main content

sim_lib_machine/
managed.rs

1use sim_lib_control::WorkLimit;
2use sim_lib_mutation::ManagedId;
3
4/// Projects live machine storage into the shared managed-object identity space.
5///
6/// Implementations enumerate identities only. Reclamation policy remains outside
7/// the machine, so the same suspended state can be inspected by any tracing or
8/// retention implementation built over `sim-lib-mutation`.
9pub trait ManagedRootSource {
10    /// Visits roots in a stable, source-defined order.
11    ///
12    /// Returns `false` immediately when the visitor refuses further work.
13    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/// Deterministic refusal to materialize a complete root snapshot.
50#[derive(Clone, Copy, Debug, PartialEq, Eq)]
51pub enum RootScanError {
52    /// The next root would exceed the caller-supplied work budget.
53    BudgetExhausted {
54        /// Roots admitted before the refusal.
55        visited: usize,
56        /// Maximum roots admitted for this scan.
57        limit: usize,
58    },
59}
60
61/// A complete, ordered view of roots visible at one machine safepoint.
62#[derive(Clone, Debug, PartialEq, Eq)]
63pub struct RootSnapshot {
64    roots: Vec<ManagedId>,
65}
66
67impl RootSnapshot {
68    /// Materializes all roots atomically or returns exact budget exhaustion.
69    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    /// Returns roots in machine storage order.
89    pub fn roots(&self) -> &[ManagedId] {
90        &self.roots
91    }
92}