1use core::cmp::Ordering;
9use core::fmt::{self, Display, Formatter};
10use core::iter::FusedIterator;
11use core::marker::PhantomData;
12use core::ops::Range;
13
14use crate::location::{Column, Component, Location, LocationLike, Row};
15use crate::vector::Component as VecComponent;
16
17#[derive(Debug, Clone, Eq, PartialEq, Hash)]
25pub struct ComponentRange<C: Component> {
26 range: Range<isize>,
27 phanton: PhantomData<C>,
28}
29
30impl<C: Component> ComponentRange<C> {
31 #[must_use]
52 #[inline]
53 pub fn bounded(start: C, end: C) -> Self {
54 ComponentRange {
55 phanton: PhantomData,
56 range: start.value()..end.value(),
57 }
58 }
59
60 #[must_use]
80 #[inline]
81 pub fn span(start: C, size: C::Distance) -> Self {
82 Self::bounded(start, start.add_distance(size))
83 }
84
85 #[must_use]
87 #[inline]
88 pub fn start(&self) -> C {
89 self.range.start.into()
90 }
91
92 #[must_use]
94 #[inline]
95 pub fn end(&self) -> C {
96 self.range.end.into()
97 }
98
99 #[must_use]
112 #[inline]
113 pub fn size(&self) -> C::Distance {
114 self.start().distance_to(self.end())
115 }
116
117 pub fn check(&self, idx: impl Into<C>) -> Result<C, RangeError<C>> {
138 let idx = idx.into();
139
140 let min = self.start();
141 let max = self.end();
142
143 if idx < min {
144 Err(RangeError::TooLow(min))
145 } else if idx >= max {
146 Err(RangeError::TooHigh(max))
147 } else {
148 Ok(idx)
149 }
150 }
151
152 #[must_use]
154 #[inline]
155 pub fn in_bounds(&self, loc: impl Into<C>) -> bool {
156 self.check(loc).is_ok()
157 }
158
159 #[must_use]
177 #[inline]
178 pub fn cross(self, index: C::Converse) -> LocationRange<C::Converse> {
179 LocationRange::new(index, self)
180 }
181}
182
183impl<C: Component> Iterator for ComponentRange<C> {
187 type Item = C;
188
189 #[inline]
190 fn next(&mut self) -> Option<C> {
191 self.range.next().map(C::from)
192 }
193
194 #[must_use]
195 #[inline]
196 fn size_hint(&self) -> (usize, Option<usize>) {
197 self.range.size_hint()
198 }
199
200 #[inline]
201 fn nth(&mut self, n: usize) -> Option<C> {
202 self.range.nth(n).map(C::from)
203 }
204
205 #[inline]
206 fn last(mut self) -> Option<C> {
207 self.next_back()
208 }
209}
210
211impl<C: Component> DoubleEndedIterator for ComponentRange<C> {
212 #[inline]
213 fn next_back(&mut self) -> Option<C> {
214 self.range.next_back().map(C::from)
215 }
216}
217
218impl<C: Component> ExactSizeIterator for ComponentRange<C> {}
219impl<C: Component> FusedIterator for ComponentRange<C> {}
220pub type RowRange = ComponentRange<Row>;
223pub type ColumnRange = ComponentRange<Column>;
224
225#[derive(Debug, Copy, Clone, PartialEq, Eq)]
245pub enum RangeError<T: Component> {
246 TooLow(T),
249
250 TooHigh(T),
254}
255
256impl<T: Component> Display for RangeError<T> {
257 fn fmt(&self, f: &mut Formatter) -> fmt::Result {
258 match self {
259 RangeError::TooLow(min) => write!(f, "{} too low, must be >= {:?}", T::name(), min),
260 RangeError::TooHigh(max) => write!(f, "{} too high, must be < {:?}", T::name(), max),
261 }
262 }
263}
264
265pub type RowRangeError = RangeError<Row>;
269pub type ColumnRangeError = RangeError<Column>;
270
271#[derive(Debug, Clone, Eq, PartialEq, Hash)]
277pub struct LocationRange<C: Component> {
278 index: C,
279 range: ComponentRange<C::Converse>,
280}
281
282impl<C: Component> LocationRange<C> {
283 #[inline]
284 #[must_use]
285 pub fn new(index: C, range: ComponentRange<C::Converse>) -> Self {
286 LocationRange { index, range }
287 }
288
289 #[inline]
290 #[must_use]
291 pub fn bounded(index: C, start: C::Converse, end: C::Converse) -> Self {
292 Self::new(index, ComponentRange::bounded(start, end))
293 }
294
295 #[inline]
296 #[must_use]
297 pub fn span(index: C, start: C::Converse, size: <C::Converse as Component>::Distance) -> Self {
298 Self::new(index, ComponentRange::span(start, size))
299 }
300
301 #[inline]
302 #[must_use]
303 pub fn rooted(root: Location, size: <C::Converse as Component>::Distance) -> Self {
304 Self::span(root.get_component(), root.get_component(), size)
305 }
306
307 #[inline]
308 #[must_use]
309 pub fn component_range(&self) -> ComponentRange<C::Converse> {
310 self.range.clone()
311 }
312
313 #[inline]
314 #[must_use]
315 pub fn index(&self) -> C {
316 self.index
317 }
318
319 #[inline]
320 #[must_use]
321 pub fn start(&self) -> Location {
322 self.range.start().combine(self.index)
323 }
324
325 #[inline]
326 #[must_use]
327 pub fn end(&self) -> Location {
328 self.range.end().combine(self.index)
329 }
330
331 #[inline]
332 #[must_use]
333 pub fn size(&self) -> <C::Converse as Component>::Distance {
334 self.range.start().distance_to(self.range.end())
335 }
336}
337
338impl LocationRange<Row> {
339 #[inline]
340 #[must_use]
341 pub fn row(&self) -> Row {
342 self.index
343 }
344
345 #[inline]
346 #[must_use]
347 pub fn columns(&self) -> ColumnRange {
348 self.component_range()
349 }
350}
351
352impl LocationRange<Column> {
353 #[inline]
354 #[must_use]
355 pub fn column(&self) -> Column {
356 self.index
357 }
358
359 #[inline]
360 #[must_use]
361 pub fn rows(&self) -> RowRange {
362 self.component_range()
363 }
364}
365
366impl<C: Component> Iterator for LocationRange<C> {
367 type Item = Location;
368
369 #[inline]
370 fn next(&mut self) -> Option<Location> {
371 self.range
372 .next()
373 .map(move |cross| cross.combine(self.index))
374 }
375
376 #[must_use]
377 #[inline]
378 fn size_hint(&self) -> (usize, Option<usize>) {
379 self.range.size_hint()
380 }
381
382 #[inline]
383 fn nth(&mut self, n: usize) -> Option<Location> {
384 self.range
385 .nth(n)
386 .map(move |cross| cross.combine(self.index))
387 }
388
389 #[inline]
390 fn last(self) -> Option<Location> {
391 let index = self.index;
392 self.range.last().map(move |cross| cross.combine(index))
393 }
394}
395
396impl<C: Component> DoubleEndedIterator for LocationRange<C> {
397 fn next_back(&mut self) -> Option<Self::Item> {
398 self.range
399 .next_back()
400 .map(move |cross| cross.combine(self.index))
401 }
402}
403
404impl<C: Component> FusedIterator for LocationRange<C> {}
405impl<C: Component> ExactSizeIterator for LocationRange<C> {}
406#[derive(Debug, Clone, Eq, PartialEq, Hash)]
410pub struct CrossRange<C: Component> {
411 top: C,
415
416 bottom: C,
418
419 span: ComponentRange<C::Converse>,
421
422 next_front: C::Converse,
423
424 next_back: C::Converse,
426}
427
428impl<C: Component> CrossRange<C> {
429 #[must_use]
430 #[inline]
431 pub fn new(major: ComponentRange<C>, cross: ComponentRange<C::Converse>) -> Self {
432 Self {
433 top: major.start(),
434 bottom: major.end().add_distance(-1),
435
436 next_front: cross.start(),
437 next_back: cross.end(),
438
439 span: cross,
440 }
441 }
442
443 #[must_use]
445 fn size(&self) -> Option<usize> {
446 match self.top.cmp(&self.bottom) {
447 Ordering::Greater => Some(0),
448 Ordering::Equal => Some(self.next_front.distance_to(self.next_back).value() as usize),
449 Ordering::Less => {
450 let hamburger_thickness = (self.top.distance_to(self.bottom).value() as usize) - 1;
453 let hamburger_size =
454 hamburger_thickness.checked_mul(self.span.size().value() as usize)?;
455
456 let top_bun = self.next_front.distance_to(self.span.end()).value() as usize;
457 let bottom_bun = self.span.start().distance_to(self.next_back).value() as usize;
458
459 hamburger_size.checked_add(top_bun)?.checked_add(bottom_bun)
460 }
461 }
462 }
463}
464
465impl<C: Component> Iterator for CrossRange<C> {
466 type Item = Location;
467
468 fn next(&mut self) -> Option<Location> {
469 loop {
470 match self.top.cmp(&self.bottom) {
471 Ordering::Greater => break None,
472 Ordering::Equal if self.next_front >= self.next_back => break None,
473 Ordering::Less if self.next_front >= self.span.end() => {
474 self.top = self.top.add_distance(1);
475 self.next_front = self.span.start();
476 }
477 _ => {
478 let index = self.next_front;
479 self.next_front = self.next_front.add_distance(1);
480 break Some(index.combine(self.top));
481 }
482 }
483 }
484 }
485
486 #[must_use]
487 #[inline]
488 fn size_hint(&self) -> (usize, Option<usize>) {
489 let size = self.size();
490
491 (size.unwrap_or(core::usize::MAX), size)
492 }
493}
494
495impl<C: Component> DoubleEndedIterator for CrossRange<C> {
496 fn next_back(&mut self) -> Option<Location> {
497 loop {
498 match self.top.cmp(&self.bottom) {
499 Ordering::Greater => break None,
500 Ordering::Equal if self.next_front >= self.next_back => break None,
501 Ordering::Less if self.next_back <= self.span.start() => {
502 self.bottom = self.bottom.add_distance(-1);
503 self.next_back = self.span.end();
504 }
505 _ => {
506 self.next_back = self.next_back.add_distance(-1);
507 break Some(self.next_back.combine(self.bottom));
508 }
509 }
510 }
511 }
512}
513
514impl<C: Component> FusedIterator for CrossRange<C> {}
515impl<C: Component> ExactSizeIterator for CrossRange<C> {}
516
517#[test]
518fn test_cross_range() {
519 use crate::vector::{Columns, Rows};
520
521 let row_range = RowRange::span(Row(-2), Rows(5));
522 let column_range = ColumnRange::span(Column(3), Columns(4));
523
524 let mut cross_range = CrossRange::new(row_range.clone(), column_range.clone());
525
526 let mut remaining = 20;
527
528 assert_eq!(cross_range.size_hint(), (20, Some(20)));
529
530 for row in row_range {
531 for column in column_range.clone() {
532 let actual = cross_range.next();
533 remaining -= 1;
534
535 assert_eq!(Some(row + column), actual);
536 assert_eq!(cross_range.size_hint(), (remaining, Some(remaining)));
537 }
538 }
539
540 assert_eq!(cross_range.next(), None);
541}
542
543#[test]
544fn test_cross_range_reverse() {
545 use crate::vector::{Columns, Rows};
546
547 let row_range = RowRange::span(Row(-2), Rows(5));
548 let column_range = ColumnRange::span(Column(3), Columns(4));
549
550 let mut cross_range = CrossRange::new(row_range.clone(), column_range.clone());
551
552 let mut remaining = 20;
553
554 assert_eq!(cross_range.size_hint(), (20, Some(20)));
555
556 for row in row_range.rev() {
557 for column in column_range.clone().rev() {
558 let actual = cross_range.next_back();
559 remaining -= 1;
560
561 assert_eq!(Some(row + column), actual);
562 assert_eq!(cross_range.size_hint(), (remaining, Some(remaining)));
563 }
564 }
565
566 assert_eq!(cross_range.next_back(), None);
567}
568
569#[test]
572fn test_cross_range_converge() {
573 use crate::vector::{Columns, Rows};
574
575 let row_range = RowRange::span(Row(-2), Rows(5));
576 let column_range = ColumnRange::span(Column(3), Columns(4));
577
578 let mut converging_cross_range = CrossRange::new(row_range, column_range);
579
580 let mut front_cross_range = converging_cross_range.clone();
581 let mut back_cross_range = converging_cross_range.clone();
582
583 let mut remaining = 20;
584
585 while remaining > 0 {
586 let next_front = front_cross_range.next();
587 let converge_front = converging_cross_range.next();
588 remaining -= 1;
589
590 assert!(converge_front.is_some());
591 assert_eq!(next_front, converge_front);
592 assert_eq!(
593 converging_cross_range.size_hint(),
594 (remaining, Some(remaining))
595 );
596
597 let next_back = back_cross_range.next_back();
598 let converge_back = converging_cross_range.next_back();
599 remaining -= 1;
600
601 assert!(converge_back.is_some());
602 assert_eq!(next_back, converge_back);
603 assert_eq!(
604 converging_cross_range.size_hint(),
605 (remaining, Some(remaining))
606 );
607 }
608
609 assert_eq!(converging_cross_range.size_hint(), (0, Some(0)));
610 assert_eq!(converging_cross_range.next(), None);
611 assert_eq!(converging_cross_range.next_back(), None);
612 assert_eq!(converging_cross_range.size_hint(), (0, Some(0)));
613}