1#[cfg(test)]
4mod test;
5
6use crate::{axis::Axis, coord::Vec2};
7use num::traits::{
8 CheckedAdd,
9 CheckedSub,
10 One,
11 SaturatingAdd,
12 SaturatingSub,
13 WrappingAdd,
14 WrappingSub,
15 Zero,
16};
17use std::ops::{Add, AddAssign, Sub, SubAssign};
18
19#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
21#[cfg_attr(
22 feature = "impl-serde",
23 derive(serde::Serialize, serde::Deserialize)
24)]
25pub struct Rect<T, S = T> {
26 pub start: Vec2<T>,
28 pub size: Vec2<S>,
30}
31
32impl<T, S> Rect<T, S> {
33 pub fn from_range<U>(start: Vec2<T>, end: Vec2<U>) -> Self
53 where
54 T: Clone,
55 U: Sub<T, Output = S>,
56 {
57 let size = end - start.clone();
58 Self { start, size }
59 }
60}
61
62impl<T> Rect<T> {
63 pub fn try_from_range(start: Vec2<T>, end: Vec2<T>) -> Option<Self>
66 where
67 T: Clone + CheckedSub,
68 {
69 let size = end.checked_sub(&start)?;
70 Some(Self { start, size })
71 }
72}
73
74impl<T, S> Rect<T, S> {
75 pub fn from_range_incl<Z>(start: Vec2<T>, end: Vec2<T>) -> Self
95 where
96 T: Sub<Output = Z> + Clone + Ord,
97 Z: One + Add<Output = S>,
98 S: Zero,
99 {
100 let size = if end < start {
101 Vec2::<S>::zero()
102 } else {
103 end - start.clone() + Vec2::<Z>::one()
104 };
105 Self { start, size }
106 }
107}
108
109impl<T> Rect<T> {
110 pub fn try_from_range_incl(start: Vec2<T>, end: Vec2<T>) -> Option<Self>
113 where
114 T: CheckedAdd + CheckedSub + One + Zero + Ord + Clone,
115 {
116 let size = if end < start {
117 Vec2::<T>::zero()
118 } else {
119 let diff = end.checked_sub(&start.clone())?;
120 diff.checked_add(&Vec2::<T>::one())?
121 };
122 Some(Self { start, size })
123 }
124}
125
126impl<T, S> Rect<T, S> {
127 pub fn is_empty(&self) -> bool
129 where
130 S: Zero,
131 {
132 self.size.x.is_zero() || self.size.y.is_zero()
133 }
134
135 pub fn end(self) -> Vec2<T::Output>
151 where
152 T: Add<S>,
153 {
154 self.start + self.size
155 }
156}
157
158impl<T> Rect<T> {
159 pub fn wrapping_end(&self) -> Vec2<T>
162 where
163 T: WrappingAdd,
164 {
165 self.start.wrapping_add(&self.size)
166 }
167
168 pub fn saturating_end(&self) -> Vec2<T>
171 where
172 T: SaturatingAdd,
173 {
174 self.start.saturating_add(&self.size)
175 }
176
177 pub fn checked_end(&self) -> Option<Vec2<T>>
180 where
181 T: CheckedAdd,
182 {
183 self.start.checked_add(&self.size)
184 }
185}
186
187impl<T, S> Rect<T, S> {
188 pub fn end_ref<'this, U>(&'this self) -> Vec2<U>
191 where
192 &'this T: Add<&'this S, Output = U>,
193 {
194 &self.start + &self.size
195 }
196
197 pub fn end_inclusive<U, V>(self) -> Vec2<V>
213 where
214 S: Sub<Output = U> + One + Zero,
215 T: Add<U, Output = V> + Sub<Output = V> + One,
216 {
217 if self.is_empty() {
218 self.start - Vec2::<T>::one()
219 } else {
220 self.start + (self.size - Vec2::<S>::one())
221 }
222 }
223}
224
225impl<T> Rect<T> {
226 pub fn wrapping_end_incl(&self) -> Vec2<T>
229 where
230 T: WrappingAdd + WrappingSub + One,
231 {
232 self.start.wrapping_add(&self.size).wrapping_sub(&Vec2::<T>::one())
233 }
234
235 pub fn saturating_end_incl(&self) -> Vec2<T>
238 where
239 T: SaturatingAdd + SaturatingSub + One + Zero,
240 {
241 if self.is_empty() {
242 self.start.saturating_sub(&Vec2::<T>::one())
243 } else {
244 let last_index = self.size.saturating_sub(&Vec2::<T>::one());
245 self.start.saturating_add(&last_index)
246 }
247 }
248
249 pub fn checked_end_incl(&self) -> Option<Vec2<T>>
252 where
253 T: CheckedAdd + CheckedSub + One + Zero,
254 {
255 if self.is_empty() {
256 self.start.checked_sub(&Vec2::<T>::one())
257 } else {
258 let last_index = self.size.checked_sub(&Vec2::<T>::one())?;
259 self.start.checked_add(&&last_index)
260 }
261 }
262}
263
264impl<T, S> Rect<T, S> {
265 pub fn end_incl_ref<'this, U, V>(&'this self) -> Vec2<V>
268 where
269 &'this S: Sub<S, Output = U>,
270 S: One + Zero,
271 &'this T: Add<U, Output = V> + Sub<T, Output = V>,
272 T: One,
273 {
274 if self.size.is_zero() {
275 &self.start - Vec2::<T>::one()
276 } else {
277 &self.start + (&self.size - Vec2::<S>::one())
278 }
279 }
280
281 pub fn end_non_empty<U, V>(self) -> Option<Vec2<V>>
313 where
314 S: Sub<Output = U> + One + Zero,
315 T: Add<U, Output = V> + Sub<Output = V> + One,
316 {
317 if self.is_empty() {
318 None
319 } else {
320 Some(self.start + (self.size - Vec2::<S>::one()))
321 }
322 }
323
324 pub fn end_non_empty_ref<'this, U, V>(&'this self) -> Option<Vec2<V>>
328 where
329 &'this S: Sub<S, Output = U>,
330 S: One + Zero,
331 &'this T: Add<U, Output = V> + Sub<T, Output = V>,
332 T: One,
333 {
334 if self.size.is_zero() {
335 None
336 } else {
337 Some(&self.start + (&self.size - Vec2::<S>::one()))
338 }
339 }
340
341 pub fn has_point<'this, U>(&'this self, point: Vec2<T>) -> bool
343 where
344 &'this S: Sub<S, Output = U>,
345 S: One + Zero,
346 &'this T: Add<U, Output = T> + Sub<T, Output = T>,
347 T: Sub<&'this T> + One + Ord,
348 {
349 let maybe_end = self.end_non_empty_ref();
350 maybe_end.map_or(false, |end| {
351 Axis::iter().all(|axis| {
352 let this_less = self.start[axis] <= point[axis];
353 let other_less = point[axis] <= end[axis];
354 this_less && other_less
355 })
356 })
357 }
358
359 pub fn overlaps<'params, U>(&'params self, other: &'params Self) -> bool
361 where
362 &'params S: Sub<S, Output = U>,
363 S: One + Zero,
364 &'params T: Add<U, Output = T> + Sub<T, Output = T>,
365 T: Sub<&'params T> + One + Ord,
366 {
367 let maybe_ends =
368 self.end_non_empty_ref().zip(other.end_non_empty_ref());
369
370 maybe_ends.map_or(false, |(this_end, other_end)| {
371 Axis::iter().all(|axis| {
372 let this_less = self.start[axis] <= other_end[axis];
373 let other_less = other.start[axis] <= this_end[axis];
374 this_less && other_less
375 })
376 })
377 }
378
379 pub fn overlapped<'params, U, Z>(
403 &'params self,
404 other: &'params Self,
405 ) -> Rect<T, <Z as Add>::Output>
406 where
407 &'params S: Sub<S, Output = U>,
408 S: One + Zero,
409 &'params T: Add<U, Output = T> + Sub<T, Output = T>,
410 T: Sub<&'params T, Output = Z> + One + Ord + Clone,
411 Z: One + Add,
412 {
413 let start =
414 self.start.as_ref().zip_with(other.start.as_ref(), Ord::max);
415 let end = self.end_incl_ref().zip_with(other.end_incl_ref(), Ord::min);
416 let size = end.zip_with(start, |end, start| end - start + Z::one());
417 Rect { start: start.cloned(), size }
418 }
419}
420
421impl<T> Rect<T> {
422 pub fn wrapping_overlapped<'params>(
425 &'params self,
426 other: &'params Self,
427 ) -> Self
428 where
429 T: WrappingAdd + WrappingSub + Ord + Clone,
430 {
431 let start =
432 self.start.as_ref().zip_with(other.start.as_ref(), Ord::max);
433 let end = self.wrapping_end().zip(other.wrapping_end()).zip_with(
434 start,
435 |(this, other), start| {
436 if this >= *start && other < *start {
437 this
438 } else if other >= *start && this < *start {
439 other
440 } else {
441 this.min(other)
442 }
443 },
444 );
445 let size = end.zip_with(start, |end, start| end.wrapping_sub(start));
446 Rect { start: start.cloned(), size }
447 }
448
449 pub fn saturating_overlapped<'params>(
451 &'params self,
452 other: &'params Self,
453 ) -> Self
454 where
455 T: SaturatingAdd + SaturatingSub + One + Zero + Ord + Clone,
456 {
457 let start =
458 self.start.as_ref().zip_with(other.start.as_ref(), Ord::max);
459 let end = self
460 .saturating_end_incl()
461 .zip_with(other.saturating_end_incl(), Ord::min);
462 let size = end.zip_with(start, |end, start| {
463 end.saturating_sub(&start).saturating_add(&T::one())
464 });
465 Rect { start: start.cloned(), size }
466 }
467
468 pub fn checked_overlapped<'params>(
471 &'params self,
472 other: &'params Self,
473 ) -> Option<Self>
474 where
475 T: CheckedAdd + CheckedSub + One + Zero + Ord + Clone,
476 {
477 let start =
478 self.start.as_ref().zip_with(other.start.as_ref(), Ord::max);
479 let end = self
480 .checked_end_incl()?
481 .zip_with(other.checked_end_incl()?, Ord::min);
482 let size = end
483 .zip_with(start, |end, start| end.checked_sub(start))
484 .transpose()?
485 .map(|elem| elem.checked_add(&T::one()))
486 .transpose()?;
487 Some(Rect { start: start.cloned(), size })
488 }
489}
490
491impl<T, S> Rect<T, S> {
492 pub fn columns<'this>(&'this self) -> Columns<T>
495 where
496 &'this S: Sub<S, Output = T>,
497 S: One + Zero,
498 &'this T: Add<T, Output = T> + Sub<T, Output = T>,
499 &'this T: Add<&'this S, Output = T>,
500 T: One + AddAssign + Ord + Clone,
501 {
502 let inner = self.end_non_empty_ref().map(|end| ColumnsInner {
503 start: self.start.clone(),
504 end: end.clone(),
505 front: self.start.clone(),
506 back: end,
507 });
508 Columns { inner }
509 }
510
511 pub fn rows<'this>(&'this self) -> Rows<T>
513 where
514 &'this S: Sub<S, Output = T>,
515 S: One + Zero,
516 &'this T: Add<T, Output = T> + Sub<T, Output = T>,
517 &'this T: Add<&'this S, Output = T>,
518 T: One + AddAssign + Ord + Clone,
519 {
520 let inner = self.end_non_empty_ref().map(|end| RowsInner {
521 start: self.start.clone(),
522 end: end.clone(),
523 front: self.start.clone(),
524 back: end,
525 });
526 Rows { inner }
527 }
528
529 pub fn borders<'this>(&'this self) -> Borders<T>
531 where
532 &'this S: Sub<S, Output = T>,
533 S: One + Zero,
534 &'this T: Add<T, Output = T> + Sub<T, Output = T>,
535 &'this T: Add<&'this S, Output = T>,
536 T: AddAssign + One + Ord + Clone,
537 {
538 let inner = self.end_non_empty_ref().map(|end| BordersInner {
539 start: self.start.clone(),
540 fixed_axis: Axis::X,
541 end,
542 curr: self.start.clone(),
543 });
544 Borders { inner }
545 }
546}
547
548#[derive(Debug)]
550pub struct Columns<T> {
551 inner: Option<ColumnsInner<T>>,
552}
553
554impl<T> Iterator for Columns<T>
555where
556 T: One + AddAssign + Ord + Clone,
557{
558 type Item = Vec2<T>;
559
560 fn next(&mut self) -> Option<Self::Item> {
561 let inner = self.inner.as_mut()?;
562 let front = inner.front.clone();
563 if inner.front.y >= inner.end.y {
564 if inner.front.x < inner.back.x {
565 inner.front.x += T::one();
566 inner.front.y = inner.start.y.clone();
567 } else {
568 self.inner = None;
569 }
570 } else if inner.sides_crossed() {
571 self.inner = None;
572 } else {
573 inner.front.y += T::one();
574 }
575 Some(front)
576 }
577}
578
579impl<T> DoubleEndedIterator for Columns<T>
580where
581 T: One + AddAssign + SubAssign + Ord + Clone,
582{
583 fn next_back(&mut self) -> Option<Self::Item> {
584 let inner = self.inner.as_mut()?;
585 let back = inner.back.clone();
586 if inner.back.y <= inner.start.y {
587 if inner.front.x < inner.back.x {
588 inner.back.x -= T::one();
589 inner.back.y = inner.end.y.clone();
590 } else {
591 self.inner = None;
592 }
593 } else if inner.sides_crossed() {
594 self.inner = None;
595 } else {
596 inner.back.y -= T::one();
597 }
598 Some(back)
599 }
600}
601
602#[derive(Debug)]
603struct ColumnsInner<T> {
604 start: Vec2<T>,
605 end: Vec2<T>,
606 front: Vec2<T>,
607 back: Vec2<T>,
608}
609
610impl<T> ColumnsInner<T>
611where
612 T: Ord,
613{
614 fn sides_crossed(&self) -> bool {
615 self.front.x >= self.back.x && self.front.y >= self.back.y
616 }
617}
618
619#[derive(Debug)]
621pub struct Rows<T> {
622 inner: Option<RowsInner<T>>,
623}
624
625impl<T> Iterator for Rows<T>
626where
627 T: One + AddAssign + Ord + Clone,
628{
629 type Item = Vec2<T>;
630
631 fn next(&mut self) -> Option<Self::Item> {
632 let inner = self.inner.as_mut()?;
633 let front = inner.front.clone();
634 if inner.front.x >= inner.end.x {
635 if inner.front.y < inner.back.y {
636 inner.front.y += T::one();
637 inner.front.x = inner.start.x.clone();
638 } else {
639 self.inner = None;
640 }
641 } else if inner.sides_crossed() {
642 self.inner = None;
643 } else {
644 inner.front.x += T::one();
645 }
646 Some(front)
647 }
648}
649
650impl<T> DoubleEndedIterator for Rows<T>
651where
652 T: One + AddAssign + SubAssign + Ord + Clone,
653{
654 fn next_back(&mut self) -> Option<Self::Item> {
655 let inner = self.inner.as_mut()?;
656 let back = inner.back.clone();
657 if inner.back.x <= inner.start.x {
658 if inner.front.y < inner.back.y {
659 inner.back.y -= T::one();
660 inner.back.x = inner.end.x.clone();
661 } else {
662 self.inner = None;
663 }
664 } else if inner.sides_crossed() {
665 self.inner = None;
666 } else {
667 inner.back.x -= T::one();
668 }
669 Some(back)
670 }
671}
672
673#[derive(Debug)]
674struct RowsInner<T> {
675 start: Vec2<T>,
676 end: Vec2<T>,
677 front: Vec2<T>,
678 back: Vec2<T>,
679}
680
681impl<T> RowsInner<T>
682where
683 T: Ord,
684{
685 fn sides_crossed(&self) -> bool {
686 self.front.x >= self.back.x && self.front.y >= self.back.y
687 }
688}
689
690#[derive(Debug)]
692pub struct Borders<T> {
693 inner: Option<BordersInner<T>>,
694}
695
696impl<T> Iterator for Borders<T>
697where
698 T: AddAssign + One + Ord + Clone,
699{
700 type Item = Vec2<T>;
701
702 fn next(&mut self) -> Option<Self::Item> {
703 let inner = self.inner.as_mut()?;
704
705 match inner.fixed_axis {
706 Axis::X => {
707 let curr = inner.curr.clone();
708 if inner.curr.y >= inner.end.y {
709 if inner.curr.x >= inner.end.x {
710 if inner.start.x < inner.end.x {
711 inner.to_first_row();
712 } else {
713 self.inner = None;
714 }
715 } else {
716 inner.to_second_col();
717 }
718 } else {
719 inner.iter_col();
720 }
721 Some(curr)
722 },
723
724 Axis::Y => {
725 let curr = inner.curr.clone();
726 if inner.curr.x >= inner.end.x {
727 if inner.curr.y < inner.end.y {
728 inner.to_second_row();
729 } else {
730 self.inner = None;
731 }
732 } else {
733 inner.iter_row();
734 }
735 Some(curr)
736 },
737 }
738 }
739}
740
741#[derive(Debug)]
742struct BordersInner<T> {
743 start: Vec2<T>,
744 end: Vec2<T>,
745 fixed_axis: Axis,
746 curr: Vec2<T>,
747}
748
749impl<T> BordersInner<T>
750where
751 T: AddAssign + One + Clone,
752{
753 fn to_second_col(&mut self) {
754 self.curr.x = self.end.x.clone();
755 self.curr.y = self.start.y.clone();
756 }
757
758 fn to_first_row(&mut self) {
759 self.curr.y = self.start.y.clone();
760 self.curr.x = self.start.x.clone();
761 self.curr.x += T::one();
762 self.fixed_axis = Axis::Y;
763 }
764
765 fn to_second_row(&mut self) {
766 self.curr.y = self.end.y.clone();
767 self.curr.x = self.start.x.clone();
768 self.curr.x += T::one();
769 }
770
771 fn iter_col(&mut self) {
772 self.curr.y += T::one();
773 }
774
775 fn iter_row(&mut self) {
776 self.curr.x += T::one();
777 }
778}