Skip to main content

sim_lib_mutation/managed/
object.rs

1/// A role-bearing managed object with stable, ordered strong edges.
2///
3/// Edge storage and identity allocation are deliberately private. Callers can
4/// mutate the graph only through checked operations, so identities are never
5/// reused and compare-and-mutate failures leave the node unchanged.
6#[derive(Clone, Debug, Eq, PartialEq)]
7pub struct ManagedNode<R> {
8    role: ManagedRole<R>,
9    edges: EdgeAllocator,
10    limits: EdgeLimits,
11    strong: BTreeMap<EdgeId, ManagedId>,
12    weak: BTreeMap<EdgeId, ManagedId>,
13    ephemerons: BTreeMap<EdgeId, (ManagedId, ManagedId)>,
14}
15/// A managed object carrying caller-owned role evidence outside graph policy.
16pub trait RoleBearingManagedObject: ManagedObject {
17    /// Role label type chosen by the object owner.
18    type Role;
19    /// Borrows the current audit role.
20    fn managed_role(&self) -> &Self::Role;
21    /// Replaces audit role evidence without changing the managed graph.
22    fn replace_managed_role(&mut self, role: Self::Role) -> Self::Role;
23}
24
25impl<R> ManagedNode<R> {
26    /// Constructs an empty node carrying caller-owned role evidence.
27    pub const fn new(role: R) -> Self {
28        Self::with_edge_limits(role, EdgeLimits::DEFAULT)
29    }
30
31    /// Constructs an empty node with explicit total and per-kind hard caps.
32    pub const fn with_edge_limits(role: R, limits: EdgeLimits) -> Self {
33        Self {
34            role: ManagedRole::new(role),
35            edges: EdgeAllocator::new(),
36            limits,
37            strong: BTreeMap::new(),
38            weak: BTreeMap::new(),
39            ephemerons: BTreeMap::new(),
40        }
41    }
42
43    /// Returns an allocation-ordered copy of every live outgoing edge.
44    pub fn edge_snapshot(&self) -> Vec<EdgeSnapshot> {
45        let mut result = self
46            .strong
47            .iter()
48            .map(|(&edge, &target)| EdgeSnapshot::Strong { edge, target })
49            .chain(
50                self.weak
51                    .iter()
52                    .map(|(&edge, &target)| EdgeSnapshot::Weak { edge, target }),
53            )
54            .chain(
55                self.ephemerons
56                    .iter()
57                    .map(|(&edge, &(key, value))| EdgeSnapshot::Ephemeron { edge, key, value }),
58            )
59            .collect::<Vec<_>>();
60        result.sort_unstable_by_key(|entry| entry.id());
61        result
62    }
63
64    fn edge_kind(&self, edge: EdgeId) -> Option<EdgeKind> {
65        self.strong
66            .contains_key(&edge)
67            .then_some(EdgeKind::Strong)
68            .or_else(|| self.weak.contains_key(&edge).then_some(EdgeKind::Weak))
69            .or_else(|| {
70                self.ephemerons
71                    .contains_key(&edge)
72                    .then_some(EdgeKind::Ephemeron)
73            })
74    }
75
76    fn admit(&self, kind: EdgeKind) -> Result<(), EdgeAllocationError> {
77        let total = self.strong.len() + self.weak.len() + self.ephemerons.len();
78        if total >= self.limits.total() {
79            return Err(EdgeAllocationError::CapacityExceeded {
80                kind,
81                cap: self.limits.total(),
82            });
83        }
84        let count = match kind {
85            EdgeKind::Strong => self.strong.len(),
86            EdgeKind::Weak => self.weak.len(),
87            EdgeKind::Ephemeron => self.ephemerons.len(),
88        };
89        let cap = self.limits.for_kind(kind);
90        if count >= cap {
91            return Err(EdgeAllocationError::CapacityExceeded { kind, cap });
92        }
93        Ok(())
94    }
95
96    /// Borrows the node's role evidence.
97    pub const fn role(&self) -> &R {
98        self.role.role()
99    }
100
101    /// Replaces the role without changing the managed graph.
102    pub fn replace_role(&mut self, role: R) -> R {
103        self.role.replace_role(role)
104    }
105
106    /// Inserts a strong edge and returns its stable identity.
107    pub fn insert_strong(&mut self, target: ManagedId) -> Result<EdgeId, StrongEdgeMutationError> {
108        self.admit(EdgeKind::Strong)?;
109        let edge = self.edges.allocate(EdgeKind::Strong)?.id();
110        let previous = self.strong.insert(edge, target);
111        debug_assert!(previous.is_none(), "fresh edge identity must be vacant");
112        Ok(edge)
113    }
114
115    /// Replaces a strong target only if it still equals `expected`.
116    pub fn replace_strong(
117        &mut self,
118        edge: EdgeId,
119        expected: ManagedId,
120        replacement: ManagedId,
121    ) -> Result<(), StrongEdgeMutationError> {
122        if let Some(actual) = self
123            .edge_kind(edge)
124            .filter(|kind| *kind != EdgeKind::Strong)
125        {
126            return Err(StrongEdgeMutationError::WrongKind { edge, actual });
127        }
128        let target = self
129            .strong
130            .get_mut(&edge)
131            .ok_or(StrongEdgeMutationError::UnknownEdge(edge))?;
132        if *target != expected {
133            return Err(StrongEdgeMutationError::TargetChanged {
134                expected,
135                actual: *target,
136            });
137        }
138        *target = replacement;
139        Ok(())
140    }
141
142    /// Removes a strong edge only if it still equals `expected`.
143    pub fn remove_strong(
144        &mut self,
145        edge: EdgeId,
146        expected: ManagedId,
147    ) -> Result<ManagedId, StrongEdgeMutationError> {
148        if let Some(actual) = self
149            .edge_kind(edge)
150            .filter(|kind| *kind != EdgeKind::Strong)
151        {
152            return Err(StrongEdgeMutationError::WrongKind { edge, actual });
153        }
154        let actual = self
155            .strong
156            .get(&edge)
157            .copied()
158            .ok_or(StrongEdgeMutationError::UnknownEdge(edge))?;
159        if actual != expected {
160            return Err(StrongEdgeMutationError::TargetChanged { expected, actual });
161        }
162        Ok(self
163            .strong
164            .remove(&edge)
165            .expect("edge checked immediately before removal"))
166    }
167
168    /// Inserts a weak edge and returns its stable identity.
169    pub fn insert_weak(&mut self, target: ManagedId) -> Result<EdgeId, WeakEdgeMutationError> {
170        self.admit(EdgeKind::Weak)?;
171        let edge = self.edges.allocate(EdgeKind::Weak)?.id();
172        let previous = self.weak.insert(edge, target);
173        debug_assert!(previous.is_none(), "fresh edge identity must be vacant");
174        Ok(edge)
175    }
176
177    /// Replaces a weak target only if it still equals `expected`.
178    pub fn replace_weak(
179        &mut self,
180        edge: EdgeId,
181        expected: ManagedId,
182        replacement: ManagedId,
183    ) -> Result<(), WeakEdgeMutationError> {
184        if let Some(actual) = self.edge_kind(edge).filter(|kind| *kind != EdgeKind::Weak) {
185            return Err(WeakEdgeMutationError::WrongKind { edge, actual });
186        }
187        let target = self
188            .weak
189            .get_mut(&edge)
190            .ok_or(WeakEdgeMutationError::UnknownEdge(edge))?;
191        if *target != expected {
192            return Err(WeakEdgeMutationError::TargetChanged {
193                expected,
194                actual: *target,
195            });
196        }
197        *target = replacement;
198        Ok(())
199    }
200
201    /// Removes a weak edge only if it still equals `expected`.
202    pub fn remove_weak(
203        &mut self,
204        edge: EdgeId,
205        expected: ManagedId,
206    ) -> Result<ManagedId, WeakEdgeMutationError> {
207        if let Some(actual) = self.edge_kind(edge).filter(|kind| *kind != EdgeKind::Weak) {
208            return Err(WeakEdgeMutationError::WrongKind { edge, actual });
209        }
210        let actual = self
211            .weak
212            .get(&edge)
213            .copied()
214            .ok_or(WeakEdgeMutationError::UnknownEdge(edge))?;
215        if actual != expected {
216            return Err(WeakEdgeMutationError::TargetChanged { expected, actual });
217        }
218        Ok(self
219            .weak
220            .remove(&edge)
221            .expect("edge checked immediately before removal"))
222    }
223
224    /// Inserts an ephemeron entry and returns its stable identity.
225    pub fn insert_ephemeron(
226        &mut self,
227        key: ManagedId,
228        value: ManagedId,
229    ) -> Result<EdgeId, EphemeronMutationError> {
230        self.admit(EdgeKind::Ephemeron)?;
231        let edge = self.edges.allocate(EdgeKind::Ephemeron)?.id();
232        let previous = self.ephemerons.insert(edge, (key, value));
233        debug_assert!(previous.is_none(), "fresh edge identity must be vacant");
234        Ok(edge)
235    }
236
237    /// Replaces an ephemeron only if it still contains the expected pair.
238    pub fn replace_ephemeron(
239        &mut self,
240        edge: EdgeId,
241        expected: (ManagedId, ManagedId),
242        replacement: (ManagedId, ManagedId),
243    ) -> Result<(), EphemeronMutationError> {
244        if let Some(actual) = self
245            .edge_kind(edge)
246            .filter(|kind| *kind != EdgeKind::Ephemeron)
247        {
248            return Err(EphemeronMutationError::WrongKind { edge, actual });
249        }
250        let entry = self
251            .ephemerons
252            .get_mut(&edge)
253            .ok_or(EphemeronMutationError::UnknownEdge(edge))?;
254        if *entry != expected {
255            return Err(EphemeronMutationError::EntryChanged {
256                expected_key: expected.0,
257                expected_value: expected.1,
258                actual_key: entry.0,
259                actual_value: entry.1,
260            });
261        }
262        *entry = replacement;
263        Ok(())
264    }
265
266    /// Removes an ephemeron only if it still contains the expected pair.
267    pub fn remove_ephemeron(
268        &mut self,
269        edge: EdgeId,
270        expected: (ManagedId, ManagedId),
271    ) -> Result<(ManagedId, ManagedId), EphemeronMutationError> {
272        if let Some(actual) = self
273            .edge_kind(edge)
274            .filter(|kind| *kind != EdgeKind::Ephemeron)
275        {
276            return Err(EphemeronMutationError::WrongKind { edge, actual });
277        }
278        let actual = self
279            .ephemerons
280            .get(&edge)
281            .copied()
282            .ok_or(EphemeronMutationError::UnknownEdge(edge))?;
283        if actual != expected {
284            return Err(EphemeronMutationError::EntryChanged {
285                expected_key: expected.0,
286                expected_value: expected.1,
287                actual_key: actual.0,
288                actual_value: actual.1,
289            });
290        }
291        Ok(self
292            .ephemerons
293            .remove(&edge)
294            .expect("entry checked immediately before removal"))
295    }
296}
297
298impl<R> ManagedObject for ManagedNode<R> {
299    fn trace_edges(&self, visitor: &mut dyn EdgeVisitor) {
300        let mut edges = self
301            .strong
302            .iter()
303            .map(|(&edge, &target)| (edge, EdgeKind::Strong, target, target))
304            .chain(
305                self.weak
306                    .iter()
307                    .map(|(&edge, &target)| (edge, EdgeKind::Weak, target, target)),
308            )
309            .chain(
310                self.ephemerons
311                    .iter()
312                    .map(|(&edge, &(key, value))| (edge, EdgeKind::Ephemeron, key, value)),
313            )
314            .collect::<Vec<_>>();
315        edges.sort_unstable_by_key(|entry| entry.0);
316        for (edge, kind, first, second) in edges {
317            match kind {
318                EdgeKind::Strong => visitor.strong(edge, first),
319                EdgeKind::Weak => visitor.weak(edge, first),
320                EdgeKind::Ephemeron => visitor.ephemeron(edge, first, second),
321            }
322        }
323    }
324
325    fn clear_weak_edge(&mut self, edge: EdgeId, expected: ManagedId) -> bool {
326        if self.weak.get(&edge) != Some(&expected) {
327            return false;
328        }
329        self.weak.remove(&edge).is_some()
330    }
331
332    fn clear_ephemeron_edge(
333        &mut self,
334        edge: EdgeId,
335        expected_key: ManagedId,
336        expected_value: ManagedId,
337    ) -> bool {
338        if self.ephemerons.get(&edge) != Some(&(expected_key, expected_value)) {
339            return false;
340        }
341        self.ephemerons.remove(&edge).is_some()
342    }
343}
344
345impl<R> RoleBearingManagedObject for ManagedNode<R> {
346    type Role = R;
347
348    fn managed_role(&self) -> &Self::Role {
349        self.role()
350    }
351
352    fn replace_managed_role(&mut self, role: Self::Role) -> Self::Role {
353        self.replace_role(role)
354    }
355}