thedes_geometry/
coords.rs

1use std::{
2    cmp::Ordering,
3    fmt,
4    mem,
5    ops::{
6        Add,
7        AddAssign,
8        Bound,
9        Div,
10        DivAssign,
11        Index,
12        IndexMut,
13        Mul,
14        MulAssign,
15        Neg,
16        RangeBounds,
17        Rem,
18        RemAssign,
19        Sub,
20        SubAssign,
21    },
22};
23
24use num::{
25    CheckedAdd,
26    CheckedDiv,
27    CheckedMul,
28    CheckedSub,
29    Integer,
30    One,
31    Zero,
32    traits::{CheckedRem, SaturatingAdd, SaturatingMul, SaturatingSub},
33};
34use serde::{Deserialize, Serialize};
35
36use crate::{
37    orientation::{Axis, Direction, DirectionVec},
38    rect::Rect,
39};
40
41#[derive(
42    Debug,
43    Clone,
44    Copy,
45    PartialEq,
46    Eq,
47    PartialOrd,
48    Ord,
49    Hash,
50    Default,
51    Serialize,
52    Deserialize,
53)]
54pub struct CoordPair<C> {
55    pub y: C,
56    pub x: C,
57}
58
59impl<C> CoordPair<C> {
60    pub fn with_order(first: C, second: C) -> Self {
61        Self { y: first, x: second }
62    }
63
64    pub fn from_axes<F>(mut generator: F) -> Self
65    where
66        F: FnMut(Axis) -> C,
67    {
68        Self { y: generator(Axis::Y), x: generator(Axis::X) }
69    }
70
71    pub fn try_from_axes<F, E>(mut generator: F) -> Result<Self, E>
72    where
73        F: FnMut(Axis) -> Result<C, E>,
74    {
75        Ok(Self { y: generator(Axis::Y)?, x: generator(Axis::X)? })
76    }
77
78    pub fn into_order(self) -> (C, C) {
79        (self.y, self.x)
80    }
81
82    pub fn as_ref(&self) -> CoordPair<&C> {
83        CoordPair::from_axes(|axis| &self[axis])
84    }
85
86    pub fn as_mut(&mut self) -> CoordPair<&mut C> {
87        CoordPair { y: &mut self.y, x: &mut self.x }
88    }
89
90    pub fn map<F, C0>(self, mut mapper: F) -> CoordPair<C0>
91    where
92        F: FnMut(C) -> C0,
93    {
94        CoordPair { y: mapper(self.y), x: mapper(self.x) }
95    }
96
97    pub fn try_map<F, C0, E>(self, mut mapper: F) -> Result<CoordPair<C0>, E>
98    where
99        F: FnMut(C) -> Result<C0, E>,
100    {
101        Ok(CoordPair { y: mapper(self.y)?, x: mapper(self.x)? })
102    }
103
104    pub fn map_with_axes<F, C0>(self, mut mapper: F) -> CoordPair<C0>
105    where
106        F: FnMut(C, Axis) -> C0,
107    {
108        CoordPair { y: mapper(self.y, Axis::Y), x: mapper(self.x, Axis::X) }
109    }
110
111    pub fn try_map_with_axes<F, C0, E>(
112        self,
113        mut mapper: F,
114    ) -> Result<CoordPair<C0>, E>
115    where
116        F: FnMut(C, Axis) -> Result<C0, E>,
117    {
118        Ok(CoordPair {
119            y: mapper(self.y, Axis::Y)?,
120            x: mapper(self.x, Axis::X)?,
121        })
122    }
123
124    pub fn shift(self) -> Self {
125        CoordPair { y: self.x, x: self.y }
126    }
127
128    pub fn shift_rev(self) -> Self {
129        CoordPair { y: self.x, x: self.y }
130    }
131
132    pub fn shift_in_place(&mut self) {
133        mem::swap(&mut self.y, &mut self.x);
134    }
135
136    pub fn shift_rev_in_place(&mut self) {
137        mem::swap(&mut self.x, &mut self.y);
138    }
139
140    pub fn shift_to(self, axis: Axis) -> Self {
141        match axis {
142            Axis::Y => self,
143            Axis::X => self.shift(),
144        }
145    }
146
147    pub fn shift_in_place_to(&mut self, axis: Axis) {
148        match axis {
149            Axis::Y => (),
150            Axis::X => self.shift_in_place(),
151        }
152    }
153
154    pub fn shift_rev_to(self, axis: Axis) -> Self {
155        match axis {
156            Axis::Y => self,
157            Axis::X => self.shift_rev(),
158        }
159    }
160
161    pub fn shift_rev_in_place_to(&mut self, axis: Axis) {
162        match axis {
163            Axis::Y => (),
164            Axis::X => self.shift_rev_in_place(),
165        }
166    }
167
168    pub fn zip2<C0>(self, other: CoordPair<C0>) -> CoordPair<(C, C0)> {
169        CoordPair { y: (self.y, other.y), x: (self.x, other.x) }
170    }
171
172    pub fn zip2_with<F, C0, C1>(
173        self,
174        other: CoordPair<C0>,
175        mut zipper: F,
176    ) -> CoordPair<C1>
177    where
178        F: FnMut(C, C0) -> C1,
179    {
180        self.zip2(other).map(|(a, b)| zipper(a, b))
181    }
182
183    pub fn zip2_with_axes<F, C0, C1>(
184        self,
185        other: CoordPair<C0>,
186        mut zipper: F,
187    ) -> CoordPair<C1>
188    where
189        F: FnMut(C, C0, Axis) -> C1,
190    {
191        self.zip2(other).map_with_axes(|(a, b), axis| zipper(a, b, axis))
192    }
193
194    pub fn try_zip2_with<F, C0, C1, E>(
195        self,
196        other: CoordPair<C0>,
197        mut zipper: F,
198    ) -> Result<CoordPair<C1>, E>
199    where
200        F: FnMut(C, C0) -> Result<C1, E>,
201    {
202        self.zip2(other).try_map(|(a, b)| zipper(a, b))
203    }
204
205    pub fn try_zip2_with_axes<F, C0, C1, E>(
206        self,
207        other: CoordPair<C0>,
208        mut zipper: F,
209    ) -> Result<CoordPair<C1>, E>
210    where
211        F: FnMut(C, C0, Axis) -> Result<C1, E>,
212    {
213        self.zip2(other).try_map_with_axes(|(a, b), axis| zipper(a, b, axis))
214    }
215
216    pub fn zip3<C0, C1>(
217        self,
218        other: CoordPair<C0>,
219        another: CoordPair<C1>,
220    ) -> CoordPair<(C, C0, C1)> {
221        CoordPair {
222            y: (self.y, other.y, another.y),
223            x: (self.x, other.x, another.x),
224        }
225    }
226
227    pub fn zip3_with<F, C0, C1, C2>(
228        self,
229        other: CoordPair<C0>,
230        another: CoordPair<C1>,
231        mut zipper: F,
232    ) -> CoordPair<C2>
233    where
234        F: FnMut(C, C0, C1) -> C2,
235    {
236        self.zip3(other, another).map(|(a, b, c)| zipper(a, b, c))
237    }
238
239    pub fn zip3_with_axes<F, C0, C1, C2>(
240        self,
241        other: CoordPair<C0>,
242        another: CoordPair<C1>,
243        mut zipper: F,
244    ) -> CoordPair<C2>
245    where
246        F: FnMut(C, C0, C1, Axis) -> C2,
247    {
248        self.zip3(other, another)
249            .map_with_axes(|(a, b, c), axis| zipper(a, b, c, axis))
250    }
251
252    pub fn try_zip3_with<F, C0, C1, C2, E>(
253        self,
254        other: CoordPair<C0>,
255        another: CoordPair<C1>,
256        mut zipper: F,
257    ) -> Result<CoordPair<C2>, E>
258    where
259        F: FnMut(C, C0, C1) -> Result<C2, E>,
260    {
261        self.zip3(other, another).try_map(|(a, b, c)| zipper(a, b, c))
262    }
263
264    pub fn try_zip3_with_axes<F, C0, C1, C2, E>(
265        self,
266        other: CoordPair<C0>,
267        another: CoordPair<C1>,
268        mut zipper: F,
269    ) -> Result<CoordPair<C2>, E>
270    where
271        F: FnMut(C, C0, C1, Axis) -> Result<C2, E>,
272    {
273        self.zip3(other, another)
274            .try_map_with_axes(|(a, b, c), axis| zipper(a, b, c, axis))
275    }
276
277    pub fn extract(self, axis: Axis) -> C {
278        match axis {
279            Axis::Y => self.y,
280            Axis::X => self.x,
281        }
282    }
283
284    pub fn all<F>(self, mut predicate: F) -> bool
285    where
286        F: FnMut(C) -> bool,
287    {
288        predicate(self.y) && predicate(self.x)
289    }
290
291    pub fn any<F>(self, mut predicate: F) -> bool
292    where
293        F: FnMut(C) -> bool,
294    {
295        predicate(self.y) || predicate(self.x)
296    }
297
298    pub fn checked_add_to(&self, other: &C) -> Option<Self>
299    where
300        C: CheckedAdd,
301    {
302        self.as_ref().checked_add_by_ref_to(other)
303    }
304
305    pub fn checked_sub_except(&self, other: &C) -> Option<Self>
306    where
307        C: CheckedSub,
308    {
309        self.as_ref().checked_sub_by_ref_except(other)
310    }
311
312    pub fn checked_sub_from(&self, other: &C) -> Option<Self>
313    where
314        C: CheckedSub,
315    {
316        self.as_ref().checked_sub_by_ref_from(other)
317    }
318
319    pub fn checked_mul_scalar(&self, other: &C) -> Option<Self>
320    where
321        C: CheckedMul,
322    {
323        self.as_ref().checked_mul_by_ref_scalar(other)
324    }
325
326    pub fn checked_div_by(&self, other: &C) -> Option<Self>
327    where
328        C: CheckedDiv,
329    {
330        self.as_ref().checked_div_by_ref_by(other)
331    }
332
333    pub fn checked_div_on(&self, other: &C) -> Option<Self>
334    where
335        C: CheckedDiv,
336    {
337        self.as_ref().checked_div_by_ref_on(other)
338    }
339
340    pub fn checked_rem_by(&self, other: &C) -> Option<Self>
341    where
342        C: CheckedRem,
343    {
344        self.as_ref().checked_rem_by_ref_by(other)
345    }
346
347    pub fn checked_rem_on(&self, other: &C) -> Option<Self>
348    where
349        C: CheckedRem,
350    {
351        self.as_ref().checked_rem_by_ref_on(other)
352    }
353
354    pub fn saturating_add_to(&self, other: &C) -> Self
355    where
356        C: SaturatingAdd,
357    {
358        self.as_ref().saturating_add_by_ref_to(other)
359    }
360
361    pub fn saturating_sub_except(&self, other: &C) -> Self
362    where
363        C: SaturatingSub,
364    {
365        self.as_ref().saturating_sub_by_ref_except(other)
366    }
367
368    pub fn saturating_sub_from(&self, other: &C) -> Self
369    where
370        C: SaturatingSub,
371    {
372        self.as_ref().saturating_sub_by_ref_from(other)
373    }
374
375    pub fn saturating_mul_scalar(&self, other: &C) -> Self
376    where
377        C: SaturatingMul,
378    {
379        self.as_ref().saturating_mul_by_ref_scalar(other)
380    }
381
382    pub fn div_floor_by(&self, divisor: &C) -> Self
383    where
384        C: Integer,
385    {
386        self.as_ref().div_floor_by_ref_by(divisor)
387    }
388
389    pub fn div_ceil_by(&self, divisor: &C) -> Self
390    where
391        C: Integer,
392    {
393        self.as_ref().div_ceil_by_ref_by(divisor)
394    }
395
396    pub fn div_floor_on(&self, dividend: &C) -> Self
397    where
398        C: Integer,
399    {
400        self.as_ref().div_floor_by_ref_on(dividend)
401    }
402
403    pub fn div_ceil_on(&self, dividend: &C) -> Self
404    where
405        C: Integer,
406    {
407        self.as_ref().div_ceil_by_ref_on(dividend)
408    }
409
410    pub fn div_floor(&self, other: &Self) -> Self
411    where
412        C: Integer,
413    {
414        self.as_ref().div_floor_by_ref(other.as_ref())
415    }
416
417    pub fn div_ceil(&self, other: &Self) -> Self
418    where
419        C: Integer,
420    {
421        self.as_ref().div_ceil_by_ref(other.as_ref())
422    }
423
424    pub fn move_unit(self, direction: Direction) -> Self
425    where
426        C: Add<Output = C> + Sub<Output = C> + One,
427    {
428        direction.move_unit(self)
429    }
430
431    pub fn checked_move_unit(&self, direction: Direction) -> Option<Self>
432    where
433        C: CheckedAdd + CheckedSub + One + Clone,
434    {
435        direction.checked_move_unit(self)
436    }
437
438    pub fn saturating_move_unit(&self, direction: Direction) -> Self
439    where
440        C: SaturatingAdd + SaturatingSub + One + Clone,
441    {
442        direction.saturating_move_unit(self)
443    }
444
445    pub fn move_by(self, vector: DirectionVec<C>) -> Self
446    where
447        C: Add<Output = C> + Sub<Output = C>,
448    {
449        vector.mov(self)
450    }
451
452    pub fn checked_move_by(&self, vector: DirectionVec<&C>) -> Option<Self>
453    where
454        C: CheckedAdd + CheckedSub + Clone,
455    {
456        vector.checked_move(self)
457    }
458
459    pub fn saturating_move_by(&self, vector: DirectionVec<&C>) -> Self
460    where
461        C: SaturatingAdd + SaturatingSub + Clone,
462    {
463        vector.saturating_move(self)
464    }
465
466    pub fn as_rect_size(self, top_left: Self) -> Rect<C> {
467        Rect { top_left, size: self }
468    }
469
470    pub fn as_rect_top_left(self, size: Self) -> Rect<C> {
471        Rect { top_left: self, size }
472    }
473
474    pub fn direction_to(self, other: Self) -> Option<DirectionVec<C>>
475    where
476        C: PartialOrd + Sub<Output = C>,
477    {
478        let vector = match self
479            .as_ref()
480            .zip2_with(other.as_ref(), |a, b| a.partial_cmp(&b))
481            .transpose()?
482        {
483            CoordPair { y: Ordering::Greater, x: Ordering::Equal } => {
484                DirectionVec {
485                    direction: Direction::Up,
486                    magnitude: self.y - other.y,
487                }
488            },
489            CoordPair { y: Ordering::Equal, x: Ordering::Greater } => {
490                DirectionVec {
491                    direction: Direction::Left,
492                    magnitude: self.x - other.x,
493                }
494            },
495            CoordPair { y: Ordering::Less, x: Ordering::Equal } => {
496                DirectionVec {
497                    direction: Direction::Down,
498                    magnitude: other.y - self.y,
499                }
500            },
501            CoordPair { y: Ordering::Equal, x: Ordering::Less } => {
502                DirectionVec {
503                    direction: Direction::Right,
504                    magnitude: other.x - self.x,
505                }
506            },
507            _ => None?,
508        };
509        Some(vector)
510    }
511
512    pub fn direction_from(self, other: Self) -> Option<DirectionVec<C>>
513    where
514        C: PartialOrd + Sub<Output = C>,
515    {
516        other.direction_to(self)
517    }
518}
519
520impl<'a, C> CoordPair<&'a C> {
521    pub fn copied(self) -> CoordPair<C>
522    where
523        C: Copy,
524    {
525        self.map(|a| *a)
526    }
527
528    pub fn cloned(self) -> CoordPair<C>
529    where
530        C: Clone,
531    {
532        self.map(C::clone)
533    }
534
535    pub fn checked_add_by_ref(self, other: Self) -> Option<CoordPair<C>>
536    where
537        C: CheckedAdd,
538    {
539        self.zip2_with(other, C::checked_add).transpose()
540    }
541
542    pub fn checked_add_by_ref_to(self, other: &C) -> Option<CoordPair<C>>
543    where
544        C: CheckedAdd,
545    {
546        self.checked_add_by_ref(CoordPair::from_axes(|_| other))
547    }
548
549    pub fn checked_sub_by_ref(self, other: Self) -> Option<CoordPair<C>>
550    where
551        C: CheckedSub,
552    {
553        self.zip2_with(other, C::checked_sub).transpose()
554    }
555
556    pub fn checked_sub_by_ref_except(self, other: &C) -> Option<CoordPair<C>>
557    where
558        C: CheckedSub,
559    {
560        self.checked_sub_by_ref(CoordPair::from_axes(|_| other))
561    }
562
563    pub fn checked_sub_by_ref_from(self, other: &C) -> Option<CoordPair<C>>
564    where
565        C: CheckedSub,
566    {
567        CoordPair::from_axes(|_| other).checked_sub_by_ref(self)
568    }
569
570    pub fn checked_mul_by_ref(self, other: Self) -> Option<CoordPair<C>>
571    where
572        C: CheckedMul,
573    {
574        self.zip2_with(other, C::checked_mul).transpose()
575    }
576
577    pub fn checked_mul_by_ref_scalar(self, other: &C) -> Option<CoordPair<C>>
578    where
579        C: CheckedMul,
580    {
581        self.checked_mul_by_ref(CoordPair::from_axes(|_| other))
582    }
583
584    pub fn checked_div_by_ref(self, other: Self) -> Option<CoordPair<C>>
585    where
586        C: CheckedDiv,
587    {
588        self.zip2_with(other, C::checked_div).transpose()
589    }
590
591    pub fn checked_div_by_ref_by(self, other: &C) -> Option<CoordPair<C>>
592    where
593        C: CheckedDiv,
594    {
595        self.checked_div_by_ref(CoordPair::from_axes(|_| other))
596    }
597
598    pub fn checked_div_by_ref_on(self, other: &C) -> Option<CoordPair<C>>
599    where
600        C: CheckedDiv,
601    {
602        CoordPair::from_axes(|_| other).checked_div_by_ref(self)
603    }
604
605    pub fn checked_rem_by_ref(self, other: Self) -> Option<CoordPair<C>>
606    where
607        C: CheckedRem,
608    {
609        self.zip2_with(other, C::checked_rem).transpose()
610    }
611
612    pub fn checked_rem_by_ref_by(self, other: &C) -> Option<CoordPair<C>>
613    where
614        C: CheckedRem,
615    {
616        self.checked_rem_by_ref(CoordPair::from_axes(|_| other))
617    }
618
619    pub fn checked_rem_by_ref_on(self, other: &C) -> Option<CoordPair<C>>
620    where
621        C: CheckedRem,
622    {
623        CoordPair::from_axes(|_| other).checked_rem_by_ref(self)
624    }
625
626    pub fn saturating_add_by_ref(self, other: Self) -> CoordPair<C>
627    where
628        C: SaturatingAdd,
629    {
630        self.zip2_with(other, C::saturating_add)
631    }
632
633    pub fn saturating_add_by_ref_to(self, other: &C) -> CoordPair<C>
634    where
635        C: SaturatingAdd,
636    {
637        self.saturating_add_by_ref(CoordPair::from_axes(|_| other))
638    }
639
640    pub fn saturating_sub_by_ref(self, other: Self) -> CoordPair<C>
641    where
642        C: SaturatingSub,
643    {
644        self.zip2_with(other, C::saturating_sub)
645    }
646
647    pub fn saturating_sub_by_ref_except(self, other: &C) -> CoordPair<C>
648    where
649        C: SaturatingSub,
650    {
651        self.saturating_sub_by_ref(CoordPair::from_axes(|_| other))
652    }
653
654    pub fn saturating_sub_by_ref_from(self, other: &C) -> CoordPair<C>
655    where
656        C: SaturatingSub,
657    {
658        self.saturating_sub_by_ref(CoordPair::from_axes(|_| other))
659    }
660
661    pub fn saturating_mul_by_ref(self, other: Self) -> CoordPair<C>
662    where
663        C: SaturatingMul,
664    {
665        self.zip2_with(other, C::saturating_mul)
666    }
667
668    pub fn saturating_mul_by_ref_scalar(self, other: &C) -> CoordPair<C>
669    where
670        C: SaturatingMul,
671    {
672        self.saturating_mul_by_ref(CoordPair::from_axes(|_| other))
673    }
674
675    pub fn div_floor_by_ref_by(self, divisor: &C) -> CoordPair<C>
676    where
677        C: Integer,
678    {
679        self.map(|dividend| dividend.div_floor(divisor))
680    }
681
682    pub fn div_ceil_by_ref_by(self, divisor: &C) -> CoordPair<C>
683    where
684        C: Integer,
685    {
686        self.map(|dividend| dividend.div_ceil(divisor))
687    }
688
689    pub fn div_floor_by_ref_on(self, dividend: &C) -> CoordPair<C>
690    where
691        C: Integer,
692    {
693        self.map(|divisor| divisor.div_floor(dividend))
694    }
695
696    pub fn div_ceil_by_ref_on(self, dividend: &C) -> CoordPair<C>
697    where
698        C: Integer,
699    {
700        self.map(|divisor| divisor.div_ceil(dividend))
701    }
702
703    pub fn div_floor_by_ref(self, other: Self) -> CoordPair<C>
704    where
705        C: Integer,
706    {
707        self.zip2_with(other, C::div_floor)
708    }
709
710    pub fn div_ceil_by_ref(self, other: Self) -> CoordPair<C>
711    where
712        C: Integer,
713    {
714        self.zip2_with(other, C::div_ceil)
715    }
716
717    pub fn checked_move_unit_by_ref(
718        self,
719        direction: Direction,
720    ) -> Option<CoordPair<C>>
721    where
722        C: CheckedAdd + CheckedSub + One + Clone,
723    {
724        direction.checked_move_unit_by_ref(self)
725    }
726
727    pub fn saturating_move_unit_by_ref(
728        self,
729        direction: Direction,
730    ) -> CoordPair<C>
731    where
732        C: SaturatingAdd + SaturatingSub + One + Clone,
733    {
734        direction.saturating_move_unit_by_ref(self)
735    }
736
737    pub fn checked_move_by_ref_by(
738        self,
739        vector: DirectionVec<&C>,
740    ) -> Option<CoordPair<C>>
741    where
742        C: CheckedAdd + CheckedSub + Clone,
743    {
744        vector.checked_move_by_ref(self)
745    }
746
747    pub fn saturating_move_by_ref_by(
748        self,
749        vector: DirectionVec<&C>,
750    ) -> CoordPair<C>
751    where
752        C: SaturatingAdd + SaturatingSub + Clone,
753    {
754        vector.saturating_move_by_ref(self)
755    }
756}
757
758impl<'a, C> CoordPair<&'a mut C> {
759    pub fn copied(self) -> CoordPair<C>
760    where
761        C: Copy,
762    {
763        self.map(|a| *a)
764    }
765
766    pub fn cloned(self) -> CoordPair<C>
767    where
768        C: Clone,
769    {
770        self.map(|a| a.clone())
771    }
772
773    pub fn share(self) -> CoordPair<&'a C> {
774        self.map(|a| &*a)
775    }
776}
777
778impl<C> CoordPair<Option<C>> {
779    pub fn transpose(self) -> Option<CoordPair<C>> {
780        Some(CoordPair { y: self.y?, x: self.x? })
781    }
782
783    pub fn from_transposed(transposed: Option<CoordPair<C>>) -> Self {
784        match transposed {
785            Some(pair) => pair.map(Some),
786            None => Self::from_axes(|_| None),
787        }
788    }
789}
790
791impl<C, E> CoordPair<Result<C, E>> {
792    pub fn transpose(self) -> Result<CoordPair<C>, E> {
793        Ok(CoordPair { y: self.y?, x: self.x? })
794    }
795
796    pub fn from_transposed(transposed: Result<CoordPair<C>, E>) -> Self
797    where
798        E: Clone,
799    {
800        match transposed {
801            Ok(pair) => pair.map(Ok),
802            Err(error) => Self { y: Err(error.clone()), x: Err(error) },
803        }
804    }
805}
806
807impl<C> Index<Axis> for CoordPair<C> {
808    type Output = C;
809
810    fn index(&self, index: Axis) -> &Self::Output {
811        match index {
812            Axis::Y => &self.y,
813            Axis::X => &self.x,
814        }
815    }
816}
817
818impl<C> IndexMut<Axis> for CoordPair<C> {
819    fn index_mut(&mut self, index: Axis) -> &mut Self::Output {
820        match index {
821            Axis::Y => &mut self.y,
822            Axis::X => &mut self.x,
823        }
824    }
825}
826
827impl<C> fmt::Display for CoordPair<C>
828where
829    C: fmt::Display,
830{
831    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
832        write!(f, "(x={}, y={})", self.x, self.y)
833    }
834}
835
836impl<C> Add for CoordPair<C>
837where
838    C: Add,
839{
840    type Output = CoordPair<C::Output>;
841
842    fn add(self, rhs: Self) -> Self::Output {
843        self.zip2_with(rhs, |a, b| a + b)
844    }
845}
846
847impl<C> Add<C> for CoordPair<C>
848where
849    C: Add + Clone,
850{
851    type Output = CoordPair<C::Output>;
852
853    fn add(self, rhs: C) -> Self::Output {
854        CoordPair { y: self.y + rhs.clone(), x: self.x + rhs }
855    }
856}
857
858impl<C> AddAssign for CoordPair<C>
859where
860    C: AddAssign,
861{
862    fn add_assign(&mut self, rhs: Self) {
863        self.as_mut().zip2_with(rhs, |a, b| *a += b);
864    }
865}
866
867impl<C> AddAssign<C> for CoordPair<C>
868where
869    C: AddAssign + Clone,
870{
871    fn add_assign(&mut self, rhs: C) {
872        self.x += rhs.clone();
873        self.y += rhs;
874    }
875}
876
877impl<C> Sub for CoordPair<C>
878where
879    C: Sub,
880{
881    type Output = CoordPair<C::Output>;
882
883    fn sub(self, rhs: Self) -> Self::Output {
884        self.zip2_with(rhs, |a, b| a - b)
885    }
886}
887
888impl<C> Sub<C> for CoordPair<C>
889where
890    C: Sub + Clone,
891{
892    type Output = CoordPair<C::Output>;
893
894    fn sub(self, rhs: C) -> Self::Output {
895        CoordPair { y: self.y - rhs.clone(), x: self.x - rhs }
896    }
897}
898
899impl<C> SubAssign for CoordPair<C>
900where
901    C: SubAssign,
902{
903    fn sub_assign(&mut self, rhs: Self) {
904        self.as_mut().zip2_with(rhs, |a, b| *a -= b);
905    }
906}
907
908impl<C> SubAssign<C> for CoordPair<C>
909where
910    C: SubAssign + Clone,
911{
912    fn sub_assign(&mut self, rhs: C) {
913        self.x -= rhs.clone();
914        self.y -= rhs;
915    }
916}
917
918impl<C> Mul for CoordPair<C>
919where
920    C: Mul,
921{
922    type Output = CoordPair<C::Output>;
923
924    fn mul(self, rhs: Self) -> Self::Output {
925        self.zip2_with(rhs, |a, b| a * b)
926    }
927}
928
929impl<C> Mul<C> for CoordPair<C>
930where
931    C: Mul + Clone,
932{
933    type Output = CoordPair<C::Output>;
934
935    fn mul(self, rhs: C) -> Self::Output {
936        CoordPair { y: self.y * rhs.clone(), x: self.x * rhs }
937    }
938}
939
940impl<C> MulAssign for CoordPair<C>
941where
942    C: MulAssign,
943{
944    fn mul_assign(&mut self, rhs: Self) {
945        self.as_mut().zip2_with(rhs, |a, b| *a *= b);
946    }
947}
948
949impl<C> MulAssign<C> for CoordPair<C>
950where
951    C: MulAssign + Clone,
952{
953    fn mul_assign(&mut self, rhs: C) {
954        self.x *= rhs.clone();
955        self.y *= rhs;
956    }
957}
958
959impl<C> Div for CoordPair<C>
960where
961    C: Div,
962{
963    type Output = CoordPair<C::Output>;
964
965    fn div(self, rhs: Self) -> Self::Output {
966        self.zip2_with(rhs, |a, b| a / b)
967    }
968}
969
970impl<C> Div<C> for CoordPair<C>
971where
972    C: Div + Clone,
973{
974    type Output = CoordPair<C::Output>;
975
976    fn div(self, rhs: C) -> Self::Output {
977        CoordPair { y: self.y / rhs.clone(), x: self.x / rhs }
978    }
979}
980
981impl<C> DivAssign for CoordPair<C>
982where
983    C: DivAssign,
984{
985    fn div_assign(&mut self, rhs: Self) {
986        self.as_mut().zip2_with(rhs, |a, b| *a /= b);
987    }
988}
989
990impl<C> DivAssign<C> for CoordPair<C>
991where
992    C: DivAssign + Clone,
993{
994    fn div_assign(&mut self, rhs: C) {
995        self.x /= rhs.clone();
996        self.y /= rhs;
997    }
998}
999
1000impl<C> Rem for CoordPair<C>
1001where
1002    C: Rem,
1003{
1004    type Output = CoordPair<C::Output>;
1005
1006    fn rem(self, rhs: Self) -> Self::Output {
1007        self.zip2_with(rhs, |a, b| a % b)
1008    }
1009}
1010
1011impl<C> Rem<C> for CoordPair<C>
1012where
1013    C: Rem + Clone,
1014{
1015    type Output = CoordPair<C::Output>;
1016
1017    fn rem(self, rhs: C) -> Self::Output {
1018        CoordPair { y: self.y % rhs.clone(), x: self.x % rhs }
1019    }
1020}
1021
1022impl<C> RemAssign for CoordPair<C>
1023where
1024    C: RemAssign,
1025{
1026    fn rem_assign(&mut self, rhs: Self) {
1027        self.as_mut().zip2_with(rhs, |a, b| *a %= b);
1028    }
1029}
1030
1031impl<C> RemAssign<C> for CoordPair<C>
1032where
1033    C: RemAssign + Clone,
1034{
1035    fn rem_assign(&mut self, rhs: C) {
1036        self.x %= rhs.clone();
1037        self.y %= rhs;
1038    }
1039}
1040
1041impl<C> Zero for CoordPair<C>
1042where
1043    C: Zero + PartialEq,
1044{
1045    fn zero() -> Self {
1046        Self::from_axes(|_| C::zero())
1047    }
1048
1049    fn is_zero(&self) -> bool {
1050        *self == Self::zero()
1051    }
1052}
1053
1054impl<C> One for CoordPair<C>
1055where
1056    C: One,
1057{
1058    fn one() -> Self {
1059        Self::from_axes(|_| C::one())
1060    }
1061}
1062
1063impl<C> Neg for CoordPair<C>
1064where
1065    C: Neg,
1066{
1067    type Output = CoordPair<C::Output>;
1068
1069    fn neg(self) -> Self::Output {
1070        self.map(|a| -a)
1071    }
1072}
1073
1074impl<C> CheckedAdd for CoordPair<C>
1075where
1076    C: CheckedAdd,
1077{
1078    fn checked_add(&self, other: &Self) -> Option<Self> {
1079        self.as_ref().checked_add_by_ref(other.as_ref())
1080    }
1081}
1082
1083impl<C> CheckedSub for CoordPair<C>
1084where
1085    C: CheckedSub,
1086{
1087    fn checked_sub(&self, other: &Self) -> Option<Self> {
1088        self.as_ref().checked_sub_by_ref(other.as_ref())
1089    }
1090}
1091
1092impl<C> CheckedMul for CoordPair<C>
1093where
1094    C: CheckedMul,
1095{
1096    fn checked_mul(&self, other: &Self) -> Option<Self> {
1097        self.as_ref().checked_mul_by_ref(other.as_ref())
1098    }
1099}
1100
1101impl<C> CheckedDiv for CoordPair<C>
1102where
1103    C: CheckedDiv,
1104{
1105    fn checked_div(&self, other: &Self) -> Option<Self> {
1106        self.as_ref().checked_div_by_ref(other.as_ref())
1107    }
1108}
1109
1110impl<C> CheckedRem for CoordPair<C>
1111where
1112    C: CheckedRem,
1113{
1114    fn checked_rem(&self, other: &Self) -> Option<Self> {
1115        self.as_ref().checked_rem_by_ref(other.as_ref())
1116    }
1117}
1118
1119impl<C> SaturatingAdd for CoordPair<C>
1120where
1121    C: SaturatingAdd,
1122{
1123    fn saturating_add(&self, other: &Self) -> Self {
1124        self.as_ref().saturating_add_by_ref(other.as_ref())
1125    }
1126}
1127
1128impl<C> SaturatingSub for CoordPair<C>
1129where
1130    C: SaturatingSub,
1131{
1132    fn saturating_sub(&self, other: &Self) -> Self {
1133        self.as_ref().saturating_sub_by_ref(other.as_ref())
1134    }
1135}
1136
1137impl<C> SaturatingMul for CoordPair<C>
1138where
1139    C: SaturatingMul,
1140{
1141    fn saturating_mul(&self, other: &Self) -> Self {
1142        self.as_ref().saturating_mul_by_ref(other.as_ref())
1143    }
1144}
1145
1146pub type CoordPairBounds<T> = CoordPair<(Bound<T>, Bound<T>)>;
1147
1148#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
1149pub struct CoordRange<Ry, Rx> {
1150    pub y: Ry,
1151    pub x: Rx,
1152}
1153
1154impl<Ry, Rx> CoordRange<Ry, Rx> {
1155    pub fn with_order(first: Ry, second: Rx) -> Self {
1156        Self { y: first, x: second }
1157    }
1158
1159    pub fn as_bounds<T>(&self) -> CoordPairBounds<&T>
1160    where
1161        Ry: RangeBounds<T>,
1162        Rx: RangeBounds<T>,
1163    {
1164        CoordPair {
1165            y: (self.y.start_bound(), self.y.end_bound()),
1166            x: (self.x.start_bound(), self.x.end_bound()),
1167        }
1168    }
1169
1170    pub fn to_bounds<T>(&self) -> CoordPairBounds<T>
1171    where
1172        Ry: RangeBounds<T>,
1173        Rx: RangeBounds<T>,
1174        T: Clone,
1175    {
1176        CoordPair {
1177            y: (self.y.start_bound().cloned(), self.y.end_bound().cloned()),
1178            x: (self.x.start_bound().cloned(), self.x.end_bound().cloned()),
1179        }
1180    }
1181}
1182
1183impl<'a, Ry, Rx, T> From<&'a CoordRange<Ry, Rx>> for CoordPairBounds<&'a T>
1184where
1185    Ry: RangeBounds<T>,
1186    Rx: RangeBounds<T>,
1187{
1188    fn from(ranges: &'a CoordRange<Ry, Rx>) -> Self {
1189        ranges.as_bounds()
1190    }
1191}