kas_core/core/
collection.rs1use crate::layout::{GridCellInfo, GridDimensions};
9use crate::{Node, Tile, Widget};
10use kas_macros::impl_self;
11use std::ops::RangeBounds;
12
13pub trait Collection {
23 type Data;
25
26 fn is_empty(&self) -> bool {
28 self.len() == 0
29 }
30
31 fn len(&self) -> usize;
33
34 fn get_tile(&self, index: usize) -> Option<&dyn Tile>;
36
37 fn get_mut_tile(&mut self, index: usize) -> Option<&mut dyn Tile>;
39
40 fn child_node<'n>(&'n mut self, data: &'n Self::Data, index: usize) -> Option<Node<'n>>;
42
43 fn iter_tile(&self, range: impl RangeBounds<usize>) -> CollectionIterTile<'_, Self> {
48 use std::ops::Bound::{Excluded, Included, Unbounded};
49 let start = match range.start_bound() {
50 Included(start) => *start,
51 Excluded(start) => *start + 1,
52 Unbounded => 0,
53 };
54 let end = match range.end_bound() {
55 Included(end) => *end + 1,
56 Excluded(end) => *end,
57 Unbounded => self.len(),
58 };
59 CollectionIterTile {
60 start,
61 end,
62 collection: self,
63 }
64 }
65
66 fn binary_search_by<'a, F>(&'a self, mut f: F) -> Option<Result<usize, usize>>
82 where
83 F: FnMut(&'a dyn Tile) -> std::cmp::Ordering,
84 {
85 use std::cmp::Ordering::{Greater, Less};
86
87 let mut size = self.len();
92 let mut left = 0;
93 let mut right = size;
94 while left < right {
95 let mid = left + size / 2;
96
97 let cmp = f(self.get_tile(mid)?);
98
99 if cmp == Less {
100 left = mid + 1;
101 } else if cmp == Greater {
102 right = mid;
103 } else {
104 return Some(Ok(mid));
105 }
106
107 size = right - left;
108 }
109
110 Some(Err(left))
111 }
112}
113
114pub trait CellCollection: Collection {
116 fn cell_info(&self, index: usize) -> Option<GridCellInfo>;
118
119 fn iter_cell_info(&self, range: impl RangeBounds<usize>) -> CollectionIterCellInfo<'_, Self> {
121 use std::ops::Bound::{Excluded, Included, Unbounded};
122 let start = match range.start_bound() {
123 Included(start) => *start,
124 Excluded(start) => *start + 1,
125 Unbounded => 0,
126 };
127 let end = match range.end_bound() {
128 Included(end) => *end + 1,
129 Excluded(end) => *end,
130 Unbounded => self.len(),
131 };
132 CollectionIterCellInfo {
133 start,
134 end,
135 collection: self,
136 }
137 }
138
139 fn grid_dimensions(&self) -> GridDimensions {
143 let mut dim = GridDimensions::default();
144 let (mut last_col, mut last_row) = (0, 0);
145 for cell_info in self.iter_cell_info(..) {
146 last_col = last_col.max(cell_info.last_col);
147 last_row = last_row.max(cell_info.last_row);
148 if cell_info.last_col > cell_info.col {
149 dim.col_spans += 1;
150 }
151 if cell_info.last_row > cell_info.row {
152 dim.row_spans += 1;
153 }
154 }
155 dim.cols = last_col + 1;
156 dim.rows = last_row + 1;
157 dim
158 }
159}
160
161#[impl_self]
162mod CollectionIterTile {
163 pub struct CollectionIterTile<'a, C: Collection + ?Sized> {
165 start: usize,
166 end: usize,
167 collection: &'a C,
168 }
169
170 impl Iterator for Self {
171 type Item = &'a dyn Tile;
172
173 fn next(&mut self) -> Option<Self::Item> {
174 let index = self.start;
175 if index < self.end {
176 self.start += 1;
177 self.collection.get_tile(index)
178 } else {
179 None
180 }
181 }
182 }
183
184 impl DoubleEndedIterator for Self {
185 fn next_back(&mut self) -> Option<Self::Item> {
186 if self.start < self.end {
187 let index = self.end - 1;
188 self.end = index;
189 self.collection.get_tile(index)
190 } else {
191 None
192 }
193 }
194 }
195
196 impl ExactSizeIterator for Self {}
197}
198
199#[impl_self]
200mod CollectionIterCellInfo {
201 pub struct CollectionIterCellInfo<'a, C: CellCollection + ?Sized> {
203 start: usize,
204 end: usize,
205 collection: &'a C,
206 }
207
208 impl Iterator for Self {
209 type Item = GridCellInfo;
210
211 fn next(&mut self) -> Option<Self::Item> {
212 let index = self.start;
213 if index < self.end {
214 self.start += 1;
215 self.collection.cell_info(index)
216 } else {
217 None
218 }
219 }
220 }
221
222 impl DoubleEndedIterator for Self {
223 fn next_back(&mut self) -> Option<Self::Item> {
224 if self.start < self.end {
225 let index = self.end - 1;
226 self.end = index;
227 self.collection.cell_info(index)
228 } else {
229 None
230 }
231 }
232 }
233
234 impl ExactSizeIterator for Self {}
235}
236
237macro_rules! impl_slice {
238 (($($gg:tt)*) for $t:ty as $w:ident in $pat:pat) => {
239 impl<$($gg)*> Collection for $t {
240 type Data = W::Data;
241
242 #[inline]
243 fn len(&self) -> usize {
244 <[_]>::len(self)
245 }
246
247 #[inline]
248 fn get_tile(&self, index: usize) -> Option<&dyn Tile> {
249 self.get(index).map(|$pat| $w as &dyn Tile)
250 }
251
252 #[inline]
253 fn get_mut_tile(&mut self, index: usize) -> Option<&mut dyn Tile> {
254 self.get_mut(index).map(|$pat| $w as &mut dyn Tile)
255 }
256
257 #[inline]
258 fn child_node<'n>(
259 &'n mut self,
260 data: &'n Self::Data,
261 index: usize,
262 ) -> Option<Node<'n>> {
263 self.get_mut(index).map(|$pat| $w.as_node(data))
264 }
265
266 #[inline]
267 fn binary_search_by<'a, F>(&'a self, mut f: F) -> Option<Result<usize, usize>>
268 where
269 F: FnMut(&'a dyn Tile) -> std::cmp::Ordering,
270 {
271 Some(<[_]>::binary_search_by(self, move |$pat| f($w.as_tile())))
272 }
273 }
274 };
275}
276
277impl_slice!((const N: usize, W: Widget) for [W; N] as w in w);
281impl_slice!((W: Widget) for [W] as w in w);
282impl_slice!((W: Widget) for Vec<W> as w in w);
283
284impl_slice!((const N: usize, W: Widget) for [(GridCellInfo, W); N] as w in (_, w));
285impl_slice!((W: Widget) for [(GridCellInfo, W)] as w in (_, w));
286impl_slice!((W: Widget) for Vec<(GridCellInfo, W)> as w in (_, w));
287
288impl<W: Widget, C: Collection> CellCollection for C
289where
290 C: std::ops::Deref<Target = [(GridCellInfo, W)]>,
291{
292 fn cell_info(&self, index: usize) -> Option<GridCellInfo> {
293 self.get(index).map(|(info, _)| *info)
294 }
295}