1#![cfg_attr(all(feature = "derive", feature = "assert"), doc = "```")]
6#![cfg_attr(not(all(feature = "derive", feature = "assert")), doc = "```ignore")]
7mod by_column_name;
56mod by_condition;
57mod by_content;
58mod by_value;
59mod locator;
60
61pub use by_column_name::ByColumnName;
62pub use by_condition::ByCondition;
63pub use by_content::ByContent;
64pub use by_value::ByValue;
65pub use locator::Locator;
66
67use core::ops::Bound;
68use std::{
69 iter::{self, Once},
70 ops::{Range, RangeBounds},
71};
72
73use crate::{
74 grid::records::{ExactRecords, Records},
75 settings::object::{Column, Columns, FirstColumn, FirstRow, LastColumn, LastRow, Row, Rows},
76};
77
78pub trait Location<Records> {
81 type Coordinate;
83 type IntoIter: IntoIterator<Item = Self::Coordinate>;
86
87 fn locate(&mut self, records: &Records) -> Self::IntoIter;
89}
90
91impl<B, R> Location<R> for Columns<B>
92where
93 B: RangeBounds<usize>,
94 R: Records,
95{
96 type Coordinate = usize;
97 type IntoIter = Range<usize>;
98
99 fn locate(&mut self, records: &R) -> Self::IntoIter {
100 let range = self.get_range();
101 let max = records.count_columns();
102 let (from, to) = bounds_to_usize(range.start_bound(), range.end_bound(), max);
103
104 from..to
105 }
106}
107
108impl<R> Location<R> for Column {
109 type Coordinate = usize;
110 type IntoIter = Once<usize>;
111
112 fn locate(&mut self, _: &R) -> Self::IntoIter {
113 iter::once((*self).into())
114 }
115}
116
117impl<R> Location<R> for FirstColumn {
118 type Coordinate = usize;
119 type IntoIter = Once<usize>;
120
121 fn locate(&mut self, _: &R) -> Self::IntoIter {
122 iter::once(0)
123 }
124}
125
126impl<R> Location<R> for LastColumn
127where
128 R: Records,
129{
130 type Coordinate = usize;
131 type IntoIter = Once<usize>;
132
133 fn locate(&mut self, records: &R) -> Self::IntoIter {
134 if records.count_columns() > 0 {
135 iter::once(records.count_columns() - 1)
136 } else {
137 iter::once(0)
138 }
139 }
140}
141
142impl<B, R> Location<R> for Rows<B>
143where
144 R: ExactRecords,
145 B: RangeBounds<usize>,
146{
147 type Coordinate = usize;
148 type IntoIter = Range<usize>;
149
150 fn locate(&mut self, records: &R) -> Self::IntoIter {
151 let (from, to) = bounds_to_usize(
152 self.get_range().start_bound(),
153 self.get_range().end_bound(),
154 records.count_rows(),
155 );
156
157 from..to
158 }
159}
160
161impl<R> Location<R> for Row {
162 type Coordinate = usize;
163 type IntoIter = Once<usize>;
164
165 fn locate(&mut self, _: &R) -> Self::IntoIter {
166 iter::once((*self).into())
167 }
168}
169
170impl<R> Location<R> for FirstRow {
171 type Coordinate = usize;
172 type IntoIter = Once<usize>;
173
174 fn locate(&mut self, _: &R) -> Self::IntoIter {
175 iter::once(0)
176 }
177}
178
179impl<R> Location<R> for LastRow
180where
181 R: ExactRecords,
182{
183 type Coordinate = usize;
184 type IntoIter = Once<usize>;
185
186 fn locate(&mut self, records: &R) -> Self::IntoIter {
187 if records.count_rows() > 0 {
188 iter::once(records.count_rows() - 1)
189 } else {
190 iter::once(0)
191 }
192 }
193}
194
195fn bounds_to_usize(
196 left: Bound<&usize>,
197 right: Bound<&usize>,
198 count_elements: usize,
199) -> (usize, usize) {
200 match (left, right) {
201 (Bound::Included(x), Bound::Included(y)) => (*x, y + 1),
202 (Bound::Included(x), Bound::Excluded(y)) => (*x, *y),
203 (Bound::Included(x), Bound::Unbounded) => (*x, count_elements),
204 (Bound::Unbounded, Bound::Unbounded) => (0, count_elements),
205 (Bound::Unbounded, Bound::Included(y)) => (0, y + 1),
206 (Bound::Unbounded, Bound::Excluded(y)) => (0, *y),
207 (Bound::Excluded(_), Bound::Unbounded)
208 | (Bound::Excluded(_), Bound::Included(_))
209 | (Bound::Excluded(_), Bound::Excluded(_)) => {
210 unreachable!("A start bound can't be excluded")
211 }
212 }
213}
214
215#[cfg(test)]
216mod tests {
217 use crate::{
218 grid::config::Entity,
219 grid::records::vec_records::Text,
220 grid::records::vec_records::VecRecords,
221 settings::location::{ByColumnName, ByCondition, ByContent},
222 settings::object::Object,
223 };
224
225 use Entity::*;
226
227 #[test]
228 fn object_by_column_name_test() {
229 let data = [
230 vec![vec![1, 2, 3], vec![1, 2, 3], vec![1, 2, 3]],
231 vec![vec![1, 2, 3], vec![1, 1, 3], vec![1, 2, 1]],
232 vec![vec![1, 1, 3], vec![1, 1, 3], vec![1, 1, 1]],
233 vec![vec![1, 1, 1], vec![1, 1, 3], vec![1, 1, 1]],
234 vec![vec![0, 1, 1], vec![1, 1, 3], vec![1, 1, 1]],
235 vec![vec![0, 0, 0], vec![1, 1, 3], vec![1, 1, 1]],
236 ];
237
238 assert_eq!(cells(by_colname("1"), &data[0]), [Column(0)]);
239 assert_eq!(cells(by_colname("1"), &data[1]), [Column(0)]);
240 assert_eq!(cells(by_colname("1"), &data[2]), [Column(0), Column(1)]);
241 assert_eq!(
242 cells(by_colname("1"), &data[3]),
243 [Column(0), Column(1), Column(2)]
244 );
245 assert_eq!(cells(by_colname("1"), &data[4]), [Column(1), Column(2)]);
246 assert_eq!(cells(by_colname("1"), &data[5]), []);
247 }
248
249 #[test]
250 fn object_by_content_test() {
251 let data = [
252 vec![vec![1, 2, 3], vec![1, 2, 3], vec![1, 2, 3]],
253 vec![vec![1, 2, 3], vec![1, 1, 3], vec![1, 2, 1]],
254 vec![vec![1, 1, 3], vec![1, 1, 3], vec![1, 1, 1]],
255 vec![vec![1, 1, 1], vec![1, 1, 3], vec![1, 1, 1]],
256 vec![vec![0, 1, 1], vec![1, 1, 3], vec![1, 1, 1]],
257 vec![vec![0, 0, 0], vec![1, 1, 3], vec![1, 1, 1]],
258 ];
259
260 assert_eq!(cells(by_content("1"), &[]), []);
261 assert_eq!(cells(by_content("1"), &[vec![], vec![], vec![]]), []);
262 assert_eq!(
263 cells(by_content("1"), &data[0]),
264 [Cell(0, 0), Cell(1, 0), Cell(2, 0)]
265 );
266 assert_eq!(
267 cells(by_content("1"), &data[1]),
268 [Cell(0, 0), Cell(1, 0), Cell(1, 1), Cell(2, 0), Cell(2, 2)]
269 );
270 assert_eq!(
271 cells(by_content("1"), &data[2]),
272 [
273 Cell(0, 0),
274 Cell(0, 1),
275 Cell(1, 0),
276 Cell(1, 1),
277 Cell(2, 0),
278 Cell(2, 1),
279 Cell(2, 2)
280 ]
281 );
282 assert_eq!(
283 cells(by_content("1"), &data[3]),
284 [
285 Cell(0, 0),
286 Cell(0, 1),
287 Cell(0, 2),
288 Cell(1, 0),
289 Cell(1, 1),
290 Cell(2, 0),
291 Cell(2, 1),
292 Cell(2, 2)
293 ]
294 );
295 assert_eq!(
296 cells(by_content("1"), &data[4]),
297 [
298 Cell(0, 1),
299 Cell(0, 2),
300 Cell(1, 0),
301 Cell(1, 1),
302 Cell(2, 0),
303 Cell(2, 1),
304 Cell(2, 2)
305 ]
306 );
307 assert_eq!(
308 cells(by_content("1"), &data[5]),
309 [Cell(1, 0), Cell(1, 1), Cell(2, 0), Cell(2, 1), Cell(2, 2)]
310 );
311 }
312
313 #[test]
314 fn object_by_condition_test() {
315 let data = [
316 vec![vec![1, 2, 3], vec![1, 2, 3], vec![1, 2, 3]],
317 vec![vec![1, 2, 3], vec![1, 1, 3], vec![1, 2, 1]],
318 vec![vec![1, 1, 3], vec![1, 1, 3], vec![1, 1, 1]],
319 vec![vec![1, 1, 1], vec![1, 1, 3], vec![1, 1, 1]],
320 vec![vec![0, 1, 1], vec![1, 1, 3], vec![1, 1, 1]],
321 vec![vec![0, 0, 0], vec![1, 1, 3], vec![1, 1, 1]],
322 ];
323
324 assert_eq!(cells(by_cond("1"), &[]), []);
325 assert_eq!(cells(by_cond("1"), &[vec![], vec![], vec![]]), []);
326 assert_eq!(
327 cells(by_cond("1"), &data[0]),
328 [Cell(0, 0), Cell(1, 0), Cell(2, 0)]
329 );
330 assert_eq!(
331 cells(by_cond("1"), &data[1]),
332 [Cell(0, 0), Cell(1, 0), Cell(1, 1), Cell(2, 0), Cell(2, 2)]
333 );
334 assert_eq!(
335 cells(by_cond("1"), &data[2]),
336 [
337 Cell(0, 0),
338 Cell(0, 1),
339 Cell(1, 0),
340 Cell(1, 1),
341 Cell(2, 0),
342 Cell(2, 1),
343 Cell(2, 2)
344 ]
345 );
346 assert_eq!(
347 cells(by_cond("1"), &data[3]),
348 [
349 Cell(0, 0),
350 Cell(0, 1),
351 Cell(0, 2),
352 Cell(1, 0),
353 Cell(1, 1),
354 Cell(2, 0),
355 Cell(2, 1),
356 Cell(2, 2)
357 ]
358 );
359 assert_eq!(
360 cells(by_cond("1"), &data[4]),
361 [
362 Cell(0, 1),
363 Cell(0, 2),
364 Cell(1, 0),
365 Cell(1, 1),
366 Cell(2, 0),
367 Cell(2, 1),
368 Cell(2, 2)
369 ]
370 );
371 assert_eq!(
372 cells(by_cond("1"), &data[5]),
373 [Cell(1, 0), Cell(1, 1), Cell(2, 0), Cell(2, 1), Cell(2, 2)]
374 );
375 }
376
377 fn by_colname(text: &str) -> ByColumnName<&str> {
378 ByColumnName::new(text)
379 }
380
381 fn by_content(text: &str) -> ByContent<&str> {
382 ByContent::new(text)
383 }
384
385 fn by_cond(text: &'static str) -> ByCondition<impl Fn(&str) -> bool> {
386 ByCondition::new(move |content| content == text)
387 }
388
389 fn cells<O>(o: O, data: &[Vec<usize>]) -> Vec<Entity>
390 where
391 O: Object<VecRecords<Text<String>>>,
392 {
393 let data = data
394 .iter()
395 .map(|row| row.iter().map(|n| n.to_string()).map(Text::new).collect())
396 .collect();
397
398 let records = VecRecords::new(data);
399 o.cells(&records).collect::<Vec<_>>()
400 }
401}