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