Skip to main content

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, Order},
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    pub fn diagonal_direction_to(
520        self,
521        other: Self,
522    ) -> CoordPair<Option<DirectionVec<C>>>
523    where
524        C: PartialOrd + Sub<Output = C>,
525    {
526        self.zip2_with_axes(other, |a, b, axis| {
527            Some(match a.partial_cmp(&b)? {
528                Ordering::Less => DirectionVec {
529                    direction: Direction::new(axis, Order::Forwards),
530                    magnitude: b - a,
531                },
532                Ordering::Greater => DirectionVec {
533                    direction: Direction::new(axis, Order::Backwards),
534                    magnitude: a - b,
535                },
536                Ordering::Equal => None?,
537            })
538        })
539    }
540
541    pub fn diagonal_direction_from(
542        self,
543        other: Self,
544    ) -> CoordPair<Option<DirectionVec<C>>>
545    where
546        C: PartialOrd + Sub<Output = C>,
547    {
548        other.diagonal_direction_to(self)
549    }
550
551    pub fn max_axis(&self) -> Axis
552    where
553        C: Ord,
554    {
555        self.max_axis_by_key(|v| v)
556    }
557
558    pub fn min_axis(&self) -> Axis
559    where
560        C: Ord,
561    {
562        self.min_axis_by_key(|v| v)
563    }
564
565    pub fn max_axis_by<'a, F>(&'a self, compare: F) -> Axis
566    where
567        F: FnOnce(&'a C, &'a C) -> Ordering,
568    {
569        if compare(&self.y, &self.x) >= Ordering::Equal {
570            Axis::Y
571        } else {
572            Axis::X
573        }
574    }
575
576    pub fn min_axis_by<'a, F>(&'a self, compare: F) -> Axis
577    where
578        F: FnOnce(&'a C, &'a C) -> Ordering,
579    {
580        if compare(&self.y, &self.x) <= Ordering::Equal {
581            Axis::Y
582        } else {
583            Axis::X
584        }
585    }
586
587    pub fn max_axis_by_key<'a, F, D>(&'a self, mut mapper: F) -> Axis
588    where
589        F: FnMut(&'a C) -> D,
590        D: Ord,
591    {
592        self.max_axis_by(|a, b| mapper(a).cmp(&mapper(b)))
593    }
594
595    pub fn min_axis_by_key<'a, F, D>(&'a self, mut mapper: F) -> Axis
596    where
597        F: FnMut(&'a C) -> D,
598        D: Ord,
599    {
600        self.min_axis_by(|a, b| mapper(a).cmp(&mapper(b)))
601    }
602
603    pub fn max_with_axis_by<F>(self, compare: F) -> (Axis, C)
604    where
605        F: for<'a> FnOnce(&'a C, &'a C) -> Ordering,
606    {
607        let axis = self.max_axis_by(compare);
608        (axis, self.extract(axis))
609    }
610
611    pub fn min_with_axis_by<F>(self, compare: F) -> (Axis, C)
612    where
613        F: for<'a> FnOnce(&'a C, &'a C) -> Ordering,
614    {
615        let axis = self.min_axis_by(compare);
616        (axis, self.extract(axis))
617    }
618
619    pub fn max_with_axis_by_key<F, D>(self, mut mapper: F) -> (Axis, C)
620    where
621        F: for<'a> FnMut(&'a C) -> D,
622        D: Ord,
623    {
624        self.max_with_axis_by(|a, b| mapper(a).cmp(&mapper(b)))
625    }
626
627    pub fn min_with_axis_by_key<F, D>(self, mut mapper: F) -> (Axis, C)
628    where
629        F: for<'a> FnMut(&'a C) -> D,
630        D: Ord,
631    {
632        self.min_with_axis_by(|a, b| mapper(a).cmp(&mapper(b)))
633    }
634
635    pub fn max_with_axis(self) -> (Axis, C)
636    where
637        C: Ord,
638    {
639        let axis = self.max_axis();
640        (axis, self.extract(axis))
641    }
642
643    pub fn min_with_axis(self) -> (Axis, C)
644    where
645        C: Ord,
646    {
647        let axis = self.min_axis();
648        (axis, self.extract(axis))
649    }
650}
651
652impl<'a, C> CoordPair<&'a C> {
653    pub fn copied(self) -> CoordPair<C>
654    where
655        C: Copy,
656    {
657        self.map(|a| *a)
658    }
659
660    pub fn cloned(self) -> CoordPair<C>
661    where
662        C: Clone,
663    {
664        self.map(C::clone)
665    }
666
667    pub fn checked_add_by_ref(self, other: Self) -> Option<CoordPair<C>>
668    where
669        C: CheckedAdd,
670    {
671        self.zip2_with(other, C::checked_add).transpose()
672    }
673
674    pub fn checked_add_by_ref_to(self, other: &C) -> Option<CoordPair<C>>
675    where
676        C: CheckedAdd,
677    {
678        self.checked_add_by_ref(CoordPair::from_axes(|_| other))
679    }
680
681    pub fn checked_sub_by_ref(self, other: Self) -> Option<CoordPair<C>>
682    where
683        C: CheckedSub,
684    {
685        self.zip2_with(other, C::checked_sub).transpose()
686    }
687
688    pub fn checked_sub_by_ref_except(self, other: &C) -> Option<CoordPair<C>>
689    where
690        C: CheckedSub,
691    {
692        self.checked_sub_by_ref(CoordPair::from_axes(|_| other))
693    }
694
695    pub fn checked_sub_by_ref_from(self, other: &C) -> Option<CoordPair<C>>
696    where
697        C: CheckedSub,
698    {
699        CoordPair::from_axes(|_| other).checked_sub_by_ref(self)
700    }
701
702    pub fn checked_mul_by_ref(self, other: Self) -> Option<CoordPair<C>>
703    where
704        C: CheckedMul,
705    {
706        self.zip2_with(other, C::checked_mul).transpose()
707    }
708
709    pub fn checked_mul_by_ref_scalar(self, other: &C) -> Option<CoordPair<C>>
710    where
711        C: CheckedMul,
712    {
713        self.checked_mul_by_ref(CoordPair::from_axes(|_| other))
714    }
715
716    pub fn checked_div_by_ref(self, other: Self) -> Option<CoordPair<C>>
717    where
718        C: CheckedDiv,
719    {
720        self.zip2_with(other, C::checked_div).transpose()
721    }
722
723    pub fn checked_div_by_ref_by(self, other: &C) -> Option<CoordPair<C>>
724    where
725        C: CheckedDiv,
726    {
727        self.checked_div_by_ref(CoordPair::from_axes(|_| other))
728    }
729
730    pub fn checked_div_by_ref_on(self, other: &C) -> Option<CoordPair<C>>
731    where
732        C: CheckedDiv,
733    {
734        CoordPair::from_axes(|_| other).checked_div_by_ref(self)
735    }
736
737    pub fn checked_rem_by_ref(self, other: Self) -> Option<CoordPair<C>>
738    where
739        C: CheckedRem,
740    {
741        self.zip2_with(other, C::checked_rem).transpose()
742    }
743
744    pub fn checked_rem_by_ref_by(self, other: &C) -> Option<CoordPair<C>>
745    where
746        C: CheckedRem,
747    {
748        self.checked_rem_by_ref(CoordPair::from_axes(|_| other))
749    }
750
751    pub fn checked_rem_by_ref_on(self, other: &C) -> Option<CoordPair<C>>
752    where
753        C: CheckedRem,
754    {
755        CoordPair::from_axes(|_| other).checked_rem_by_ref(self)
756    }
757
758    pub fn saturating_add_by_ref(self, other: Self) -> CoordPair<C>
759    where
760        C: SaturatingAdd,
761    {
762        self.zip2_with(other, C::saturating_add)
763    }
764
765    pub fn saturating_add_by_ref_to(self, other: &C) -> CoordPair<C>
766    where
767        C: SaturatingAdd,
768    {
769        self.saturating_add_by_ref(CoordPair::from_axes(|_| other))
770    }
771
772    pub fn saturating_sub_by_ref(self, other: Self) -> CoordPair<C>
773    where
774        C: SaturatingSub,
775    {
776        self.zip2_with(other, C::saturating_sub)
777    }
778
779    pub fn saturating_sub_by_ref_except(self, other: &C) -> CoordPair<C>
780    where
781        C: SaturatingSub,
782    {
783        self.saturating_sub_by_ref(CoordPair::from_axes(|_| other))
784    }
785
786    pub fn saturating_sub_by_ref_from(self, other: &C) -> CoordPair<C>
787    where
788        C: SaturatingSub,
789    {
790        self.saturating_sub_by_ref(CoordPair::from_axes(|_| other))
791    }
792
793    pub fn saturating_mul_by_ref(self, other: Self) -> CoordPair<C>
794    where
795        C: SaturatingMul,
796    {
797        self.zip2_with(other, C::saturating_mul)
798    }
799
800    pub fn saturating_mul_by_ref_scalar(self, other: &C) -> CoordPair<C>
801    where
802        C: SaturatingMul,
803    {
804        self.saturating_mul_by_ref(CoordPair::from_axes(|_| other))
805    }
806
807    pub fn div_floor_by_ref_by(self, divisor: &C) -> CoordPair<C>
808    where
809        C: Integer,
810    {
811        self.map(|dividend| dividend.div_floor(divisor))
812    }
813
814    pub fn div_ceil_by_ref_by(self, divisor: &C) -> CoordPair<C>
815    where
816        C: Integer,
817    {
818        self.map(|dividend| dividend.div_ceil(divisor))
819    }
820
821    pub fn div_floor_by_ref_on(self, dividend: &C) -> CoordPair<C>
822    where
823        C: Integer,
824    {
825        self.map(|divisor| divisor.div_floor(dividend))
826    }
827
828    pub fn div_ceil_by_ref_on(self, dividend: &C) -> CoordPair<C>
829    where
830        C: Integer,
831    {
832        self.map(|divisor| divisor.div_ceil(dividend))
833    }
834
835    pub fn div_floor_by_ref(self, other: Self) -> CoordPair<C>
836    where
837        C: Integer,
838    {
839        self.zip2_with(other, C::div_floor)
840    }
841
842    pub fn div_ceil_by_ref(self, other: Self) -> CoordPair<C>
843    where
844        C: Integer,
845    {
846        self.zip2_with(other, C::div_ceil)
847    }
848
849    pub fn checked_move_unit_by_ref(
850        self,
851        direction: Direction,
852    ) -> Option<CoordPair<C>>
853    where
854        C: CheckedAdd + CheckedSub + One + Clone,
855    {
856        direction.checked_move_unit_by_ref(self)
857    }
858
859    pub fn saturating_move_unit_by_ref(
860        self,
861        direction: Direction,
862    ) -> CoordPair<C>
863    where
864        C: SaturatingAdd + SaturatingSub + One + Clone,
865    {
866        direction.saturating_move_unit_by_ref(self)
867    }
868
869    pub fn checked_move_by_ref_by(
870        self,
871        vector: DirectionVec<&C>,
872    ) -> Option<CoordPair<C>>
873    where
874        C: CheckedAdd + CheckedSub + Clone,
875    {
876        vector.checked_move_by_ref(self)
877    }
878
879    pub fn saturating_move_by_ref_by(
880        self,
881        vector: DirectionVec<&C>,
882    ) -> CoordPair<C>
883    where
884        C: SaturatingAdd + SaturatingSub + Clone,
885    {
886        vector.saturating_move_by_ref(self)
887    }
888}
889
890impl<'a, C> CoordPair<&'a mut C> {
891    pub fn copied(self) -> CoordPair<C>
892    where
893        C: Copy,
894    {
895        self.map(|a| *a)
896    }
897
898    pub fn cloned(self) -> CoordPair<C>
899    where
900        C: Clone,
901    {
902        self.map(|a| a.clone())
903    }
904
905    pub fn share(self) -> CoordPair<&'a C> {
906        self.map(|a| &*a)
907    }
908}
909
910impl<C> CoordPair<Option<C>> {
911    pub fn transpose(self) -> Option<CoordPair<C>> {
912        Some(CoordPair { y: self.y?, x: self.x? })
913    }
914
915    pub fn from_transposed(transposed: Option<CoordPair<C>>) -> Self {
916        match transposed {
917            Some(pair) => pair.map(Some),
918            None => Self::from_axes(|_| None),
919        }
920    }
921}
922
923impl<C, E> CoordPair<Result<C, E>> {
924    pub fn transpose(self) -> Result<CoordPair<C>, E> {
925        Ok(CoordPair { y: self.y?, x: self.x? })
926    }
927
928    pub fn from_transposed(transposed: Result<CoordPair<C>, E>) -> Self
929    where
930        E: Clone,
931    {
932        match transposed {
933            Ok(pair) => pair.map(Ok),
934            Err(error) => Self { y: Err(error.clone()), x: Err(error) },
935        }
936    }
937}
938
939impl<C> Index<Axis> for CoordPair<C> {
940    type Output = C;
941
942    fn index(&self, index: Axis) -> &Self::Output {
943        match index {
944            Axis::Y => &self.y,
945            Axis::X => &self.x,
946        }
947    }
948}
949
950impl<C> IndexMut<Axis> for CoordPair<C> {
951    fn index_mut(&mut self, index: Axis) -> &mut Self::Output {
952        match index {
953            Axis::Y => &mut self.y,
954            Axis::X => &mut self.x,
955        }
956    }
957}
958
959impl<C> fmt::Display for CoordPair<C>
960where
961    C: fmt::Display,
962{
963    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
964        write!(f, "(x={}, y={})", self.x, self.y)
965    }
966}
967
968impl<C> Add for CoordPair<C>
969where
970    C: Add,
971{
972    type Output = CoordPair<C::Output>;
973
974    fn add(self, rhs: Self) -> Self::Output {
975        self.zip2_with(rhs, |a, b| a + b)
976    }
977}
978
979impl<C> Add<C> for CoordPair<C>
980where
981    C: Add + Clone,
982{
983    type Output = CoordPair<C::Output>;
984
985    fn add(self, rhs: C) -> Self::Output {
986        CoordPair { y: self.y + rhs.clone(), x: self.x + rhs }
987    }
988}
989
990impl<C> AddAssign for CoordPair<C>
991where
992    C: AddAssign,
993{
994    fn add_assign(&mut self, rhs: Self) {
995        self.as_mut().zip2_with(rhs, |a, b| *a += b);
996    }
997}
998
999impl<C> AddAssign<C> for CoordPair<C>
1000where
1001    C: AddAssign + Clone,
1002{
1003    fn add_assign(&mut self, rhs: C) {
1004        self.x += rhs.clone();
1005        self.y += rhs;
1006    }
1007}
1008
1009impl<C> Sub for CoordPair<C>
1010where
1011    C: Sub,
1012{
1013    type Output = CoordPair<C::Output>;
1014
1015    fn sub(self, rhs: Self) -> Self::Output {
1016        self.zip2_with(rhs, |a, b| a - b)
1017    }
1018}
1019
1020impl<C> Sub<C> for CoordPair<C>
1021where
1022    C: Sub + Clone,
1023{
1024    type Output = CoordPair<C::Output>;
1025
1026    fn sub(self, rhs: C) -> Self::Output {
1027        CoordPair { y: self.y - rhs.clone(), x: self.x - rhs }
1028    }
1029}
1030
1031impl<C> SubAssign for CoordPair<C>
1032where
1033    C: SubAssign,
1034{
1035    fn sub_assign(&mut self, rhs: Self) {
1036        self.as_mut().zip2_with(rhs, |a, b| *a -= b);
1037    }
1038}
1039
1040impl<C> SubAssign<C> for CoordPair<C>
1041where
1042    C: SubAssign + Clone,
1043{
1044    fn sub_assign(&mut self, rhs: C) {
1045        self.x -= rhs.clone();
1046        self.y -= rhs;
1047    }
1048}
1049
1050impl<C> Mul for CoordPair<C>
1051where
1052    C: Mul,
1053{
1054    type Output = CoordPair<C::Output>;
1055
1056    fn mul(self, rhs: Self) -> Self::Output {
1057        self.zip2_with(rhs, |a, b| a * b)
1058    }
1059}
1060
1061impl<C> Mul<C> for CoordPair<C>
1062where
1063    C: Mul + Clone,
1064{
1065    type Output = CoordPair<C::Output>;
1066
1067    fn mul(self, rhs: C) -> Self::Output {
1068        CoordPair { y: self.y * rhs.clone(), x: self.x * rhs }
1069    }
1070}
1071
1072impl<C> MulAssign for CoordPair<C>
1073where
1074    C: MulAssign,
1075{
1076    fn mul_assign(&mut self, rhs: Self) {
1077        self.as_mut().zip2_with(rhs, |a, b| *a *= b);
1078    }
1079}
1080
1081impl<C> MulAssign<C> for CoordPair<C>
1082where
1083    C: MulAssign + Clone,
1084{
1085    fn mul_assign(&mut self, rhs: C) {
1086        self.x *= rhs.clone();
1087        self.y *= rhs;
1088    }
1089}
1090
1091impl<C> Div for CoordPair<C>
1092where
1093    C: Div,
1094{
1095    type Output = CoordPair<C::Output>;
1096
1097    fn div(self, rhs: Self) -> Self::Output {
1098        self.zip2_with(rhs, |a, b| a / b)
1099    }
1100}
1101
1102impl<C> Div<C> for CoordPair<C>
1103where
1104    C: Div + Clone,
1105{
1106    type Output = CoordPair<C::Output>;
1107
1108    fn div(self, rhs: C) -> Self::Output {
1109        CoordPair { y: self.y / rhs.clone(), x: self.x / rhs }
1110    }
1111}
1112
1113impl<C> DivAssign for CoordPair<C>
1114where
1115    C: DivAssign,
1116{
1117    fn div_assign(&mut self, rhs: Self) {
1118        self.as_mut().zip2_with(rhs, |a, b| *a /= b);
1119    }
1120}
1121
1122impl<C> DivAssign<C> for CoordPair<C>
1123where
1124    C: DivAssign + Clone,
1125{
1126    fn div_assign(&mut self, rhs: C) {
1127        self.x /= rhs.clone();
1128        self.y /= rhs;
1129    }
1130}
1131
1132impl<C> Rem for CoordPair<C>
1133where
1134    C: Rem,
1135{
1136    type Output = CoordPair<C::Output>;
1137
1138    fn rem(self, rhs: Self) -> Self::Output {
1139        self.zip2_with(rhs, |a, b| a % b)
1140    }
1141}
1142
1143impl<C> Rem<C> for CoordPair<C>
1144where
1145    C: Rem + Clone,
1146{
1147    type Output = CoordPair<C::Output>;
1148
1149    fn rem(self, rhs: C) -> Self::Output {
1150        CoordPair { y: self.y % rhs.clone(), x: self.x % rhs }
1151    }
1152}
1153
1154impl<C> RemAssign for CoordPair<C>
1155where
1156    C: RemAssign,
1157{
1158    fn rem_assign(&mut self, rhs: Self) {
1159        self.as_mut().zip2_with(rhs, |a, b| *a %= b);
1160    }
1161}
1162
1163impl<C> RemAssign<C> for CoordPair<C>
1164where
1165    C: RemAssign + Clone,
1166{
1167    fn rem_assign(&mut self, rhs: C) {
1168        self.x %= rhs.clone();
1169        self.y %= rhs;
1170    }
1171}
1172
1173impl<C> Zero for CoordPair<C>
1174where
1175    C: Zero + PartialEq,
1176{
1177    fn zero() -> Self {
1178        Self::from_axes(|_| C::zero())
1179    }
1180
1181    fn is_zero(&self) -> bool {
1182        *self == Self::zero()
1183    }
1184}
1185
1186impl<C> One for CoordPair<C>
1187where
1188    C: One,
1189{
1190    fn one() -> Self {
1191        Self::from_axes(|_| C::one())
1192    }
1193}
1194
1195impl<C> Neg for CoordPair<C>
1196where
1197    C: Neg,
1198{
1199    type Output = CoordPair<C::Output>;
1200
1201    fn neg(self) -> Self::Output {
1202        self.map(|a| -a)
1203    }
1204}
1205
1206impl<C> CheckedAdd for CoordPair<C>
1207where
1208    C: CheckedAdd,
1209{
1210    fn checked_add(&self, other: &Self) -> Option<Self> {
1211        self.as_ref().checked_add_by_ref(other.as_ref())
1212    }
1213}
1214
1215impl<C> CheckedSub for CoordPair<C>
1216where
1217    C: CheckedSub,
1218{
1219    fn checked_sub(&self, other: &Self) -> Option<Self> {
1220        self.as_ref().checked_sub_by_ref(other.as_ref())
1221    }
1222}
1223
1224impl<C> CheckedMul for CoordPair<C>
1225where
1226    C: CheckedMul,
1227{
1228    fn checked_mul(&self, other: &Self) -> Option<Self> {
1229        self.as_ref().checked_mul_by_ref(other.as_ref())
1230    }
1231}
1232
1233impl<C> CheckedDiv for CoordPair<C>
1234where
1235    C: CheckedDiv,
1236{
1237    fn checked_div(&self, other: &Self) -> Option<Self> {
1238        self.as_ref().checked_div_by_ref(other.as_ref())
1239    }
1240}
1241
1242impl<C> CheckedRem for CoordPair<C>
1243where
1244    C: CheckedRem,
1245{
1246    fn checked_rem(&self, other: &Self) -> Option<Self> {
1247        self.as_ref().checked_rem_by_ref(other.as_ref())
1248    }
1249}
1250
1251impl<C> SaturatingAdd for CoordPair<C>
1252where
1253    C: SaturatingAdd,
1254{
1255    fn saturating_add(&self, other: &Self) -> Self {
1256        self.as_ref().saturating_add_by_ref(other.as_ref())
1257    }
1258}
1259
1260impl<C> SaturatingSub for CoordPair<C>
1261where
1262    C: SaturatingSub,
1263{
1264    fn saturating_sub(&self, other: &Self) -> Self {
1265        self.as_ref().saturating_sub_by_ref(other.as_ref())
1266    }
1267}
1268
1269impl<C> SaturatingMul for CoordPair<C>
1270where
1271    C: SaturatingMul,
1272{
1273    fn saturating_mul(&self, other: &Self) -> Self {
1274        self.as_ref().saturating_mul_by_ref(other.as_ref())
1275    }
1276}
1277
1278pub type CoordPairBounds<T> = CoordPair<(Bound<T>, Bound<T>)>;
1279
1280#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
1281pub struct CoordRange<Ry, Rx> {
1282    pub y: Ry,
1283    pub x: Rx,
1284}
1285
1286impl<Ry, Rx> CoordRange<Ry, Rx> {
1287    pub fn with_order(first: Ry, second: Rx) -> Self {
1288        Self { y: first, x: second }
1289    }
1290
1291    pub fn as_bounds<T>(&self) -> CoordPairBounds<&T>
1292    where
1293        Ry: RangeBounds<T>,
1294        Rx: RangeBounds<T>,
1295    {
1296        CoordPair {
1297            y: (self.y.start_bound(), self.y.end_bound()),
1298            x: (self.x.start_bound(), self.x.end_bound()),
1299        }
1300    }
1301
1302    pub fn to_bounds<T>(&self) -> CoordPairBounds<T>
1303    where
1304        Ry: RangeBounds<T>,
1305        Rx: RangeBounds<T>,
1306        T: Clone,
1307    {
1308        CoordPair {
1309            y: (self.y.start_bound().cloned(), self.y.end_bound().cloned()),
1310            x: (self.x.start_bound().cloned(), self.x.end_bound().cloned()),
1311        }
1312    }
1313}
1314
1315impl<'a, Ry, Rx, T> From<&'a CoordRange<Ry, Rx>> for CoordPairBounds<&'a T>
1316where
1317    Ry: RangeBounds<T>,
1318    Rx: RangeBounds<T>,
1319{
1320    fn from(ranges: &'a CoordRange<Ry, Rx>) -> Self {
1321        ranges.as_bounds()
1322    }
1323}