cranpose_foundation/modifier/
chain_node_ref.rs1use super::{ModifierNode, ModifierNodeChain, NodeCapabilities, NodePath};
5
6#[derive(Clone, Copy, Debug, PartialEq, Eq)]
7enum TraversalDirection {
8 Forward,
9 Backward,
10}
11
12pub struct ModifierChainIter<'a> {
14 chain: &'a ModifierNodeChain,
15 cursor: usize,
16 remaining: usize,
17 direction: TraversalDirection,
18}
19
20impl<'a> ModifierChainIter<'a> {
21 pub(super) fn forward(chain: &'a ModifierNodeChain) -> Self {
22 Self {
23 chain,
24 cursor: 0,
25 remaining: chain.order_len(),
26 direction: TraversalDirection::Forward,
27 }
28 }
29
30 pub(super) fn backward(chain: &'a ModifierNodeChain) -> Self {
31 let len = chain.order_len();
32 Self {
33 chain,
34 cursor: len.wrapping_sub(1),
35 remaining: len,
36 direction: TraversalDirection::Backward,
37 }
38 }
39}
40
41impl<'a> Iterator for ModifierChainIter<'a> {
42 type Item = ModifierChainNodeRef<'a>;
43
44 #[inline]
45 fn next(&mut self) -> Option<Self::Item> {
46 if self.remaining == 0 {
47 return None;
48 }
49 let node_ref = self.chain.node_ref(ChainPosition::Node(self.cursor));
50 self.remaining -= 1;
51 match self.direction {
52 TraversalDirection::Forward => self.cursor += 1,
53 TraversalDirection::Backward => self.cursor = self.cursor.wrapping_sub(1),
54 }
55 Some(node_ref)
56 }
57
58 #[inline]
59 fn size_hint(&self) -> (usize, Option<usize>) {
60 (self.remaining, Some(self.remaining))
61 }
62}
63
64impl ExactSizeIterator for ModifierChainIter<'_> {}
65impl std::iter::FusedIterator for ModifierChainIter<'_> {}
66
67#[derive(Clone)]
71pub struct ModifierChainNodeRef<'a> {
72 pub(super) chain: &'a ModifierNodeChain,
73 pub(super) position: ChainPosition,
74}
75
76#[derive(Clone, Copy)]
79pub(super) enum ChainPosition {
80 Head,
81 Node(usize),
82 Tail,
83}
84
85impl ModifierChainNodeRef<'_> {
86 fn path(&self) -> Option<NodePath> {
87 match self.position {
88 ChainPosition::Node(index) => Some(self.chain.order_at(index).0),
89 ChainPosition::Head | ChainPosition::Tail => None,
90 }
91 }
92
93 pub fn with_node<R>(&self, f: impl FnOnce(&dyn ModifierNode) -> R) -> Option<R> {
96 self.chain.with_path(self.path()?, f)
97 }
98
99 #[inline]
101 pub fn parent(&self) -> Option<Self> {
102 let position = match self.position {
103 ChainPosition::Head => return None,
104 ChainPosition::Node(index) => index.checked_sub(1),
105 ChainPosition::Tail => self.chain.order_len().checked_sub(1),
106 }
107 .map_or(ChainPosition::Head, ChainPosition::Node);
108 Some(self.chain.node_ref(position))
109 }
110
111 #[inline]
113 pub fn child(&self) -> Option<Self> {
114 let next = match self.position {
115 ChainPosition::Head => 0,
116 ChainPosition::Node(index) => index + 1,
117 ChainPosition::Tail => return None,
118 };
119 let position = if next < self.chain.order_len() {
120 ChainPosition::Node(next)
121 } else {
122 ChainPosition::Tail
123 };
124 Some(self.chain.node_ref(position))
125 }
126
127 #[inline]
129 pub fn kind_set(&self) -> NodeCapabilities {
130 match self.position {
131 ChainPosition::Node(index) => self.chain.order_at(index).1,
132 ChainPosition::Head | ChainPosition::Tail => NodeCapabilities::empty(),
133 }
134 }
135
136 pub fn entry_index(&self) -> Option<usize> {
138 self.path().map(|path| path.entry())
139 }
140
141 pub fn delegate_depth(&self) -> usize {
143 self.path().map_or(0, |path| path.delegates().len())
144 }
145
146 #[inline]
148 pub fn aggregate_child_capabilities(&self) -> NodeCapabilities {
149 match self.position {
150 ChainPosition::Head => self.chain.aggregated_capabilities,
151 ChainPosition::Node(index) => self.chain.order_at(index).2,
152 ChainPosition::Tail => NodeCapabilities::empty(),
153 }
154 }
155
156 pub fn is_head(&self) -> bool {
158 matches!(self.position, ChainPosition::Head)
159 }
160
161 pub fn is_tail(&self) -> bool {
163 matches!(self.position, ChainPosition::Tail)
164 }
165
166 pub fn is_sentinel(&self) -> bool {
168 matches!(self.position, ChainPosition::Head | ChainPosition::Tail)
169 }
170
171 pub fn has_capability(&self, mask: NodeCapabilities) -> bool {
173 !mask.is_empty() && self.kind_set().intersects(mask)
174 }
175
176 pub fn visit_descendants<F>(self, include_self: bool, mut f: F)
178 where
179 F: FnMut(Self),
180 {
181 let mut current = if include_self {
182 Some(self)
183 } else {
184 self.child()
185 };
186 while let Some(node) = current {
187 if node.is_tail() {
188 break;
189 }
190 if !node.is_sentinel() {
191 f(node.clone());
192 }
193 current = node.child();
194 }
195 }
196
197 pub fn visit_descendants_matching<F>(self, include_self: bool, mask: NodeCapabilities, mut f: F)
199 where
200 F: FnMut(Self),
201 {
202 if mask.is_empty() {
203 self.visit_descendants(include_self, f);
204 return;
205 }
206
207 if !self.aggregate_child_capabilities().intersects(mask) {
208 return;
209 }
210
211 self.visit_descendants(include_self, |node| {
212 if node.kind_set().intersects(mask) {
213 f(node);
214 }
215 });
216 }
217
218 pub fn visit_ancestors<F>(self, include_self: bool, mut f: F)
220 where
221 F: FnMut(Self),
222 {
223 let mut current = if include_self {
224 Some(self)
225 } else {
226 self.parent()
227 };
228 while let Some(node) = current {
229 if node.is_head() {
230 break;
231 }
232 f(node.clone());
233 current = node.parent();
234 }
235 }
236
237 pub fn visit_ancestors_matching<F>(self, include_self: bool, mask: NodeCapabilities, mut f: F)
239 where
240 F: FnMut(Self),
241 {
242 if mask.is_empty() {
243 self.visit_ancestors(include_self, f);
244 return;
245 }
246
247 self.visit_ancestors(include_self, |node| {
248 if node.kind_set().intersects(mask) {
249 f(node);
250 }
251 });
252 }
253}