/rust/registry/src/index.crates.io-1949cf8c6b5b557f/prodash-31.0.0/src/progress/key.rs
Line | Count | Source |
1 | | use std::ops::{Index, IndexMut}; |
2 | | |
3 | | use crate::progress::Task; |
4 | | |
5 | | /// a level in the hierarchy of key components |
6 | | /// |
7 | | /// _NOTE:_ This means we will show weird behaviour if there are more than 2^16 tasks at the same time on a level |
8 | | /// as multiple progress handles will manipulate the same state. |
9 | | pub type Level = u8; |
10 | | |
11 | | pub(crate) type Id = u16; |
12 | | |
13 | | /// A type identifying a spot in the hierarchy of `Tree` items. |
14 | | #[derive(Copy, Clone, Default, Hash, Eq, PartialEq, Ord, PartialOrd, Debug)] |
15 | | pub struct Key(Option<Id>, Option<Id>, Option<Id>, Option<Id>, Option<Id>, Option<Id>); |
16 | | |
17 | | /// Determines if a sibling is above or below in the given level of hierarchy |
18 | | #[derive(Default, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Debug)] |
19 | | #[allow(missing_docs)] |
20 | | pub enum SiblingLocation { |
21 | | Above, |
22 | | Below, |
23 | | AboveAndBelow, |
24 | | #[default] |
25 | | NotFound, |
26 | | } |
27 | | |
28 | | impl SiblingLocation { |
29 | 0 | fn merge(&mut self, other: SiblingLocation) { |
30 | | use SiblingLocation::*; |
31 | 0 | *self = match (*self, other) { |
32 | 0 | (any, NotFound) => any, |
33 | 0 | (NotFound, any) => any, |
34 | 0 | (Above, Below) => AboveAndBelow, |
35 | 0 | (Below, Above) => AboveAndBelow, |
36 | 0 | (AboveAndBelow, _) => AboveAndBelow, |
37 | 0 | (_, AboveAndBelow) => AboveAndBelow, |
38 | 0 | (Above, Above) => Above, |
39 | 0 | (Below, Below) => Below, |
40 | | }; |
41 | 0 | } |
42 | | } |
43 | | |
44 | | /// A type providing information about what's above and below `Tree` items. |
45 | | #[derive(Copy, Clone, Default, Eq, PartialEq, Ord, PartialOrd, Debug)] |
46 | | pub struct Adjacency( |
47 | | pub SiblingLocation, |
48 | | pub SiblingLocation, |
49 | | pub SiblingLocation, |
50 | | pub SiblingLocation, |
51 | | pub SiblingLocation, |
52 | | pub SiblingLocation, |
53 | | ); |
54 | | |
55 | | impl Adjacency { |
56 | | /// Return the level at which this sibling is located in the hierarchy. |
57 | 0 | pub fn level(&self) -> Level { |
58 | | use SiblingLocation::*; |
59 | 0 | match self { |
60 | 0 | Adjacency(NotFound, NotFound, NotFound, NotFound, NotFound, NotFound) => 0, |
61 | 0 | Adjacency(_a, NotFound, NotFound, NotFound, NotFound, NotFound) => 1, |
62 | 0 | Adjacency(_a, _b, NotFound, NotFound, NotFound, NotFound) => 2, |
63 | 0 | Adjacency(_a, _b, _c, NotFound, NotFound, NotFound) => 3, |
64 | 0 | Adjacency(_a, _b, _c, _d, NotFound, NotFound) => 4, |
65 | 0 | Adjacency(_a, _b, _c, _d, _e, NotFound) => 5, |
66 | 0 | Adjacency(_a, _b, _c, _d, _e, _f) => 6, |
67 | | } |
68 | 0 | } |
69 | | /// Get a reference to the sibling location at `level`. |
70 | 0 | pub fn get(&self, level: Level) -> Option<&SiblingLocation> { |
71 | 0 | Some(match level { |
72 | 0 | 1 => &self.0, |
73 | 0 | 2 => &self.1, |
74 | 0 | 3 => &self.2, |
75 | 0 | 4 => &self.3, |
76 | 0 | 5 => &self.4, |
77 | 0 | 6 => &self.5, |
78 | 0 | _ => return None, |
79 | | }) |
80 | 0 | } |
81 | | /// Get a mutable reference to the sibling location at `level`. |
82 | 0 | pub fn get_mut(&mut self, level: Level) -> Option<&mut SiblingLocation> { |
83 | 0 | Some(match level { |
84 | 0 | 1 => &mut self.0, |
85 | 0 | 2 => &mut self.1, |
86 | 0 | 3 => &mut self.2, |
87 | 0 | 4 => &mut self.3, |
88 | 0 | 5 => &mut self.4, |
89 | 0 | 6 => &mut self.5, |
90 | 0 | _ => return None, |
91 | | }) |
92 | 0 | } |
93 | | } |
94 | | |
95 | | impl Index<Level> for Adjacency { |
96 | | type Output = SiblingLocation; |
97 | 0 | fn index(&self, index: Level) -> &Self::Output { |
98 | 0 | self.get(index).expect("adjacency index in bound") |
99 | 0 | } |
100 | | } |
101 | | |
102 | | impl IndexMut<Level> for Adjacency { |
103 | 0 | fn index_mut(&mut self, index: Level) -> &mut Self::Output { |
104 | 0 | self.get_mut(index).expect("adjacency index in bound") |
105 | 0 | } |
106 | | } |
107 | | |
108 | | impl Key { |
109 | | /// Return the key to the child identified by `child_id` located in a new nesting level below `self`. |
110 | 0 | pub fn add_child(self, child_id: Id) -> Key { |
111 | 0 | match self { |
112 | 0 | Key(None, None, None, None, None, None) => Key(Some(child_id), None, None, None, None, None), |
113 | 0 | Key(a, None, None, None, None, None) => Key(a, Some(child_id), None, None, None, None), |
114 | 0 | Key(a, b, None, None, None, None) => Key(a, b, Some(child_id), None, None, None), |
115 | 0 | Key(a, b, c, None, None, None) => Key(a, b, c, Some(child_id), None, None), |
116 | 0 | Key(a, b, c, d, None, None) => Key(a, b, c, d, Some(child_id), None), |
117 | 0 | Key(a, b, c, d, e, _f) => { |
118 | | crate::warn!("Maximum nesting level reached. Adding tasks to current parent"); |
119 | 0 | Key(a, b, c, d, e, Some(child_id)) |
120 | | } |
121 | | } |
122 | 0 | } |
123 | | |
124 | | /// The level of hierarchy a node is placed in, i.e. the amount of path components |
125 | 0 | pub fn level(&self) -> Level { |
126 | 0 | match self { |
127 | 0 | Key(None, None, None, None, None, None) => 0, |
128 | 0 | Key(Some(_), None, None, None, None, None) => 1, |
129 | 0 | Key(Some(_), Some(_), None, None, None, None) => 2, |
130 | 0 | Key(Some(_), Some(_), Some(_), None, None, None) => 3, |
131 | 0 | Key(Some(_), Some(_), Some(_), Some(_), None, None) => 4, |
132 | 0 | Key(Some(_), Some(_), Some(_), Some(_), Some(_), None) => 5, |
133 | 0 | Key(Some(_), Some(_), Some(_), Some(_), Some(_), Some(_)) => 6, |
134 | 0 | _ => unreachable!("This is a bug - Keys follow a certain pattern"), |
135 | | } |
136 | 0 | } |
137 | | |
138 | | /// Return the identifier for the item at `level`. |
139 | 0 | fn get(&self, level: Level) -> Option<&Id> { |
140 | 0 | match level { |
141 | 0 | 1 => self.0.as_ref(), |
142 | 0 | 2 => self.1.as_ref(), |
143 | 0 | 3 => self.2.as_ref(), |
144 | 0 | 4 => self.3.as_ref(), |
145 | 0 | 5 => self.4.as_ref(), |
146 | 0 | 6 => self.5.as_ref(), |
147 | 0 | _ => None, |
148 | | } |
149 | 0 | } |
150 | | |
151 | | /// Return true if the item identified by `other` shares the parent at `parent_level`. |
152 | 0 | pub fn shares_parent_with(&self, other: &Key, parent_level: Level) -> bool { |
153 | 0 | if parent_level < 1 { |
154 | 0 | return true; |
155 | 0 | } |
156 | 0 | for level in 1..=parent_level { |
157 | 0 | if let (Some(lhs), Some(rhs)) = (self.get(level), other.get(level)) { |
158 | 0 | if lhs != rhs { |
159 | 0 | return false; |
160 | 0 | } |
161 | | } else { |
162 | 0 | return false; |
163 | | } |
164 | | } |
165 | 0 | true |
166 | 0 | } |
167 | | |
168 | | /// Compute the adjacency map for the key in `sorted` at the given `index`. |
169 | | /// |
170 | | /// It's vital that the invariant of `sorted` to actually be sorted by key is upheld |
171 | | /// for the result to be reliable. |
172 | 0 | pub fn adjacency(sorted: &[(Key, Task)], index: usize) -> Adjacency { |
173 | | use SiblingLocation::*; |
174 | 0 | let key = &sorted[index].0; |
175 | 0 | let key_level = key.level(); |
176 | 0 | let mut adjecency = Adjacency::default(); |
177 | 0 | if key_level == 0 { |
178 | 0 | return adjecency; |
179 | 0 | } |
180 | | |
181 | 0 | fn search<'a>( |
182 | 0 | iter: impl Iterator<Item = &'a (Key, Task)>, |
183 | 0 | key: &Key, |
184 | 0 | key_level: Level, |
185 | 0 | current_level: Level, |
186 | 0 | _id_at_level: Id, |
187 | 0 | ) -> Option<usize> { |
188 | 0 | iter.map(|(k, _)| k) |
189 | 0 | .take_while(|other| key.shares_parent_with(other, current_level.saturating_sub(1))) Unexecuted instantiation: <prodash::progress::key::Key>::adjacency::search::<core::slice::iter::Iter<(prodash::progress::key::Key, prodash::progress::Task)>>::{closure#1}Unexecuted instantiation: <prodash::progress::key::Key>::adjacency::search::<core::iter::adapters::rev::Rev<core::slice::iter::Iter<(prodash::progress::key::Key, prodash::progress::Task)>>>::{closure#1} |
190 | 0 | .enumerate() |
191 | 0 | .find(|(_idx, k)| { |
192 | 0 | if current_level == key_level { |
193 | 0 | k.level() == key_level || k.level() + 1 == key_level |
194 | | } else { |
195 | 0 | k.level() == current_level |
196 | | } |
197 | 0 | }) Unexecuted instantiation: <prodash::progress::key::Key>::adjacency::search::<core::slice::iter::Iter<(prodash::progress::key::Key, prodash::progress::Task)>>::{closure#2}Unexecuted instantiation: <prodash::progress::key::Key>::adjacency::search::<core::iter::adapters::rev::Rev<core::slice::iter::Iter<(prodash::progress::key::Key, prodash::progress::Task)>>>::{closure#2} |
198 | 0 | .map(|(idx, _)| idx) |
199 | 0 | } Unexecuted instantiation: <prodash::progress::key::Key>::adjacency::search::<core::slice::iter::Iter<(prodash::progress::key::Key, prodash::progress::Task)>> Unexecuted instantiation: <prodash::progress::key::Key>::adjacency::search::<core::iter::adapters::rev::Rev<core::slice::iter::Iter<(prodash::progress::key::Key, prodash::progress::Task)>>> |
200 | | |
201 | 0 | let upward_iter = |from: usize, key: &Key, level: Level, id_at_level: Id| { |
202 | 0 | search(sorted[..from].iter().rev(), key, key_level, level, id_at_level) |
203 | 0 | }; |
204 | 0 | let downward_iter = |from: usize, key: &Key, level: Level, id_at_level: Id| { |
205 | 0 | sorted |
206 | 0 | .get(from + 1..) |
207 | 0 | .and_then(|s| search(s.iter(), key, key_level, level, id_at_level)) |
208 | 0 | }; |
209 | | |
210 | | { |
211 | 0 | let mut cursor = index; |
212 | 0 | for level in (1..=key_level).rev() { |
213 | 0 | if level == 1 { |
214 | 0 | adjecency[level].merge(Above); // the root or any other sibling on level one |
215 | 0 | continue; |
216 | 0 | } |
217 | 0 | if let Some(key_offset) = upward_iter(cursor, key, level, key[level]) { |
218 | 0 | cursor = index.saturating_sub(key_offset); |
219 | 0 | adjecency[level].merge(Above); |
220 | 0 | } |
221 | | } |
222 | | } |
223 | | { |
224 | 0 | let mut cursor = index; |
225 | 0 | for level in (1..=key_level).rev() { |
226 | 0 | if let Some(key_offset) = downward_iter(cursor, key, level, key[level]) { |
227 | 0 | cursor = index + key_offset; |
228 | 0 | adjecency[level].merge(Below); |
229 | 0 | } |
230 | | } |
231 | | } |
232 | 0 | for level in 1..key_level { |
233 | 0 | if key_level == 1 && index + 1 == sorted.len() { |
234 | 0 | continue; |
235 | 0 | } |
236 | 0 | adjecency[level] = match adjecency[level] { |
237 | 0 | Above | Below | NotFound => NotFound, |
238 | 0 | AboveAndBelow => AboveAndBelow, |
239 | | }; |
240 | | } |
241 | 0 | adjecency |
242 | 0 | } |
243 | | |
244 | | /// The maximum amount of path components we can represent. |
245 | 0 | pub const fn max_level() -> Level { |
246 | 0 | 6 |
247 | 0 | } |
248 | | } |
249 | | |
250 | | impl Index<Level> for Key { |
251 | | type Output = Id; |
252 | | |
253 | 0 | fn index(&self, index: Level) -> &Self::Output { |
254 | 0 | self.get(index).expect("key index in bound") |
255 | 0 | } |
256 | | } |