1use core::ops::{Deref, DerefMut};
4
5#[derive(Copy, Clone, Debug)]
6pub(crate) enum DecyclerError {
7 DepthLimitExceeded,
8 CycleDetected,
9}
10
11pub(crate) struct Decycler<T, const D: usize> {
30 node_ids: [T; D],
31 depth: usize,
32}
33
34impl<T, const D: usize> Decycler<T, D>
35where
36 T: Copy + PartialEq + Default,
37{
38 pub fn new() -> Self {
39 Self {
40 node_ids: [T::default(); D],
41 depth: 0,
42 }
43 }
44
45 pub fn enter(&mut self, node_id: T) -> Result<DecyclerGuard<'_, T, D>, DecyclerError> {
56 if self.depth < D {
57 if self.depth == 0 || self.node_ids[self.depth / 2] != node_id {
58 self.node_ids[self.depth] = node_id;
59 self.depth += 1;
60 Ok(DecyclerGuard { decycler: self })
61 } else {
62 Err(DecyclerError::CycleDetected)
63 }
64 } else {
65 Err(DecyclerError::DepthLimitExceeded)
66 }
67 }
68}
69
70impl<T, const D: usize> Default for Decycler<T, D>
71where
72 T: Copy + PartialEq + Default,
73{
74 fn default() -> Self {
75 Self::new()
76 }
77}
78
79pub(crate) struct DecyclerGuard<'a, T, const D: usize> {
80 decycler: &'a mut Decycler<T, D>,
81}
82
83impl<T, const D: usize> Deref for DecyclerGuard<'_, T, D> {
84 type Target = Decycler<T, D>;
85
86 fn deref(&self) -> &Self::Target {
87 self.decycler
88 }
89}
90
91impl<T, const D: usize> DerefMut for DecyclerGuard<'_, T, D> {
92 fn deref_mut(&mut self) -> &mut Self::Target {
93 self.decycler
94 }
95}
96
97impl<T, const D: usize> Drop for DecyclerGuard<'_, T, D> {
98 fn drop(&mut self) {
99 self.decycler.depth -= 1;
100 }
101}
102
103#[cfg(test)]
104mod tests {
105 use super::*;
106
107 #[test]
108 fn graph_with_cycles() {
109 let tree = Tree {
110 nodes: vec![
111 Node::new(vec![1, 2]),
112 Node::new(vec![2, 3]),
113 Node::new(vec![]),
114 Node::new(vec![0, 1]),
115 ],
116 };
117 let result = tree.traverse(&mut TestDecycler::new());
118 assert!(matches!(result, Err(DecyclerError::CycleDetected)));
119 }
120
121 #[test]
122 fn exceeds_max_depth() {
123 let mut nodes = (0..MAX_DEPTH)
124 .map(|ix| Node::new(vec![ix + 1]))
125 .collect::<Vec<_>>();
126 nodes.push(Node::new(vec![]));
127 let tree = Tree { nodes };
128 let result = tree.traverse(&mut TestDecycler::new());
129 assert!(matches!(result, Err(DecyclerError::DepthLimitExceeded)));
130 }
131
132 #[test]
133 fn well_formed_tree() {
134 let mut nodes = (0..MAX_DEPTH - 1)
135 .map(|ix| Node::new(vec![ix + 1]))
136 .collect::<Vec<_>>();
137 nodes.push(Node::new(vec![]));
138 let tree = Tree { nodes };
139 let result = tree.traverse(&mut TestDecycler::new());
140 assert!(result.is_ok());
141 }
142
143 const MAX_DEPTH: usize = 64;
144 type TestDecycler = Decycler<usize, MAX_DEPTH>;
145
146 struct Node {
147 child_ids: Vec<usize>,
148 }
149
150 impl Node {
151 fn new(child_ids: Vec<usize>) -> Self {
152 Self { child_ids }
153 }
154 }
155
156 struct Tree {
157 nodes: Vec<Node>,
158 }
159
160 impl Tree {
161 fn traverse(&self, decycler: &mut TestDecycler) -> Result<(), DecyclerError> {
162 self.traverse_impl(decycler, 0)
163 }
164
165 fn traverse_impl(
166 &self,
167 decycler: &mut TestDecycler,
168 node_id: usize,
169 ) -> Result<(), DecyclerError> {
170 let mut cycle_guard = decycler.enter(node_id)?;
171 let node = &self.nodes[node_id];
172 for child_id in &node.child_ids {
173 self.traverse_impl(&mut cycle_guard, *child_id)?;
174 }
175 Ok(())
176 }
177 }
178}