Skip to main content

coord_2d/
coord.rs

1#[cfg(feature = "serialize")]
2use serde::{Deserialize, Serialize};
3
4#[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))]
5#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq, PartialOrd, Ord)]
6pub enum Axis {
7    X,
8    Y,
9}
10
11impl Axis {
12    pub const fn other(self) -> Self {
13        match self {
14            Axis::X => Axis::Y,
15            Axis::Y => Axis::X,
16        }
17    }
18    pub const fn new_icoord(self, this_axis: i32, other_axis: i32) -> ICoord {
19        match self {
20            Axis::X => ICoord::new(this_axis, other_axis),
21            Axis::Y => ICoord::new(other_axis, this_axis),
22        }
23    }
24    pub fn new_ucoord(self, this_axis: u32, other_axis: u32) -> UCoord {
25        match self {
26            Axis::X => UCoord::new(this_axis, other_axis),
27            Axis::Y => UCoord::new(other_axis, this_axis),
28        }
29    }
30}
31
32pub trait StaticAxis: private::Sealed {
33    type Other: StaticAxis;
34    fn axis() -> Axis;
35    fn new_icoord(this_axis: i32, other_axis: i32) -> ICoord;
36    fn icoord_get(icoord: ICoord) -> i32;
37    fn icoord_get_mut(icoord: &mut ICoord) -> &mut i32;
38    fn icoord_with_axis<F: FnMut(i32) -> i32>(icoord: ICoord, f: F) -> ICoord;
39    fn icoord_set(icoord: ICoord, value: i32) -> ICoord;
40    fn icoord_set_in_place(icoord: &mut ICoord, value: i32);
41    fn ucoord_get(ucoord: UCoord) -> u32;
42    fn ucoord_with_axis<F: FnMut(u32) -> u32>(ucoord: UCoord, f: F) -> UCoord;
43    fn ucoord_set(ucoord: UCoord, value: u32) -> UCoord;
44    fn ucoord_set_in_place(ucoord: &mut UCoord, value: u32);
45    fn new_ucoord(this_axis: u32, other_axis: u32) -> UCoord;
46}
47
48pub mod static_axis {
49    pub struct X;
50    pub struct Y;
51}
52
53fn check_ucoord_limit(value: u32) {
54    assert!(
55        value <= MAX_UCOORD_FIELD,
56        "Value {} is too large for ucoord field",
57        value
58    );
59}
60
61impl StaticAxis for static_axis::X {
62    type Other = static_axis::Y;
63    fn axis() -> Axis {
64        Axis::X
65    }
66    fn new_icoord(this_axis: i32, other_axis: i32) -> ICoord {
67        ICoord::new(this_axis, other_axis)
68    }
69    fn icoord_get(icoord: ICoord) -> i32 {
70        icoord.x
71    }
72    fn icoord_get_mut(icoord: &mut ICoord) -> &mut i32 {
73        &mut icoord.x
74    }
75    fn icoord_with_axis<F: FnMut(i32) -> i32>(icoord: ICoord, mut f: F) -> ICoord {
76        ICoord {
77            x: f(icoord.x),
78            ..icoord
79        }
80    }
81    fn icoord_set(icoord: ICoord, value: i32) -> ICoord {
82        ICoord { x: value, ..icoord }
83    }
84    fn icoord_set_in_place(icoord: &mut ICoord, value: i32) {
85        icoord.x = value
86    }
87    fn ucoord_get(ucoord: UCoord) -> u32 {
88        ucoord.width()
89    }
90    fn ucoord_with_axis<F: FnMut(u32) -> u32>(ucoord: UCoord, mut f: F) -> UCoord {
91        ucoord.set_width(f(ucoord.width()))
92    }
93    fn ucoord_set(ucoord: UCoord, value: u32) -> UCoord {
94        ucoord.set_width(value)
95    }
96    fn ucoord_set_in_place(ucoord: &mut UCoord, value: u32) {
97        ucoord.set_width_in_place(value);
98    }
99    fn new_ucoord(this_axis: u32, other_axis: u32) -> UCoord {
100        UCoord::new(this_axis, other_axis)
101    }
102}
103
104impl StaticAxis for static_axis::Y {
105    type Other = static_axis::X;
106    fn axis() -> Axis {
107        Axis::Y
108    }
109    fn new_icoord(this_axis: i32, other_axis: i32) -> ICoord {
110        ICoord::new(other_axis, this_axis)
111    }
112    fn icoord_get(icoord: ICoord) -> i32 {
113        icoord.y
114    }
115    fn icoord_get_mut(icoord: &mut ICoord) -> &mut i32 {
116        &mut icoord.y
117    }
118    fn icoord_with_axis<F: FnMut(i32) -> i32>(icoord: ICoord, mut f: F) -> ICoord {
119        ICoord {
120            y: f(icoord.y),
121            ..icoord
122        }
123    }
124    fn icoord_set(icoord: ICoord, value: i32) -> ICoord {
125        ICoord { y: value, ..icoord }
126    }
127    fn icoord_set_in_place(icoord: &mut ICoord, value: i32) {
128        icoord.y = value
129    }
130    fn ucoord_get(ucoord: UCoord) -> u32 {
131        ucoord.height()
132    }
133    fn ucoord_with_axis<F: FnMut(u32) -> u32>(ucoord: UCoord, mut f: F) -> UCoord {
134        ucoord.set_height(f(ucoord.height()))
135    }
136    fn ucoord_set(ucoord: UCoord, value: u32) -> UCoord {
137        ucoord.set_height(value)
138    }
139
140    fn ucoord_set_in_place(ucoord: &mut UCoord, value: u32) {
141        ucoord.set_height_in_place(value);
142    }
143
144    fn new_ucoord(this_axis: u32, other_axis: u32) -> UCoord {
145        UCoord::new(other_axis, this_axis)
146    }
147}
148
149mod private {
150    pub trait Sealed {}
151
152    impl Sealed for super::static_axis::X {}
153    impl Sealed for super::static_axis::Y {}
154}
155
156/// General purpose icoordinate
157#[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))]
158#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq, Default, PartialOrd, Ord)]
159pub struct ICoord {
160    pub x: i32,
161    pub y: i32,
162}
163
164impl core::fmt::Display for ICoord {
165    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
166        write!(f, "({}, {})", self.x, self.y)
167    }
168}
169
170#[derive(Debug)]
171pub struct NegativeDimension;
172
173#[derive(Debug)]
174pub struct DimensionTooLargeForUCoord;
175
176#[derive(Debug)]
177pub struct DimensionTooLargeForICoord;
178
179impl ICoord {
180    pub const fn new(x: i32, y: i32) -> Self {
181        Self { x, y }
182    }
183    pub const fn from_ucoord(ucoord: UCoord) -> Self {
184        ucoord.to_icoord()
185    }
186    #[cfg(feature = "rand")]
187    pub fn random_within<R: rand::Rng>(ucoord: UCoord, rng: &mut R) -> Self {
188        let x = rng.random_range(0..ucoord.width() as i32);
189        let y = rng.random_range(0..ucoord.height() as i32);
190        Self { x, y }
191    }
192    pub fn to_ucoord(self) -> UCoord {
193        assert!(
194            self.x >= 0 && self.y >= 0,
195            "ICoord {} can't be converted to UCoord as it contains a negative component.",
196            self
197        );
198        UCoord(self)
199    }
200    const fn normalize_part(value: i32, ucoord: u32) -> i32 {
201        let value = value % ucoord as i32;
202        if value < 0 {
203            value + ucoord as i32
204        } else {
205            value
206        }
207    }
208    pub const fn normalize(self, ucoord: UCoord) -> Self {
209        Self {
210            x: Self::normalize_part(self.x, ucoord.width()),
211            y: Self::normalize_part(self.y, ucoord.height()),
212        }
213    }
214    pub const fn is_valid(self, ucoord: UCoord) -> bool {
215        if self.x < 0 || self.y < 0 {
216            return false;
217        }
218        let x = self.x as u32;
219        let y = self.y as u32;
220        x < ucoord.width() && y < ucoord.height()
221    }
222    pub const fn constrain(mut self, ucoord: UCoord) -> Option<Self> {
223        if self.x < 0 {
224            self.x = 0;
225        }
226        if self.y < 0 {
227            self.y = 0;
228        }
229        let max_x = if let Some(max_x) = ucoord.width().checked_sub(1) {
230            max_x as i32
231        } else {
232            return None;
233        };
234        if self.x > max_x {
235            self.x = max_x;
236        }
237        let max_y = if let Some(max_y) = ucoord.height().checked_sub(1) {
238            max_y as i32
239        } else {
240            return None;
241        };
242        if self.y > max_y {
243            self.y = max_y;
244        }
245        Some(self)
246    }
247    pub const fn get(self, axis: Axis) -> i32 {
248        match axis {
249            Axis::X => self.x,
250            Axis::Y => self.y,
251        }
252    }
253    pub fn get_mut(&mut self, axis: Axis) -> &mut i32 {
254        match axis {
255            Axis::X => &mut self.x,
256            Axis::Y => &mut self.y,
257        }
258    }
259    pub fn with_axis<F: FnMut(i32) -> i32>(self, axis: Axis, mut f: F) -> Self {
260        match axis {
261            Axis::X => Self {
262                x: f(self.x),
263                ..self
264            },
265            Axis::Y => Self {
266                y: f(self.y),
267                ..self
268            },
269        }
270    }
271
272    #[must_use]
273    pub const fn set(self, axis: Axis, value: i32) -> Self {
274        match axis {
275            Axis::X => Self::new(value, self.y),
276            Axis::Y => Self::new(self.x, value),
277        }
278    }
279    pub fn set_in_place(&mut self, axis: Axis, value: i32) {
280        match axis {
281            Axis::X => self.x = value,
282            Axis::Y => self.y = value,
283        }
284    }
285    pub const fn new_axis(this_axis: i32, other_axis: i32, axis: Axis) -> Self {
286        axis.new_icoord(this_axis, other_axis)
287    }
288    pub fn get_static<A: StaticAxis>(self) -> i32 {
289        A::icoord_get(self)
290    }
291    pub fn get_static_mut<A: StaticAxis>(&mut self) -> &mut i32 {
292        A::icoord_get_mut(self)
293    }
294    pub fn with_static_axis<A: StaticAxis, F: FnMut(i32) -> i32>(self, f: F) -> Self {
295        A::icoord_with_axis(self, f)
296    }
297    pub fn set_static<A: StaticAxis>(self, value: i32) -> Self {
298        A::icoord_set(self, value)
299    }
300    pub fn set_static_in_place<A: StaticAxis>(&mut self, value: i32) {
301        A::icoord_set_in_place(self, value)
302    }
303    pub fn new_static_axis<A: StaticAxis>(this_axis: i32, other_axis: i32) -> Self {
304        A::new_icoord(this_axis, other_axis)
305    }
306    #[must_use]
307    pub const fn set_x(self, x: i32) -> Self {
308        Self { x, ..self }
309    }
310    #[must_use]
311    pub const fn set_y(self, y: i32) -> Self {
312        Self { y, ..self }
313    }
314    pub fn set_x_in_place(&mut self, x: i32) {
315        self.x = x;
316    }
317    pub fn set_y_in_place(&mut self, y: i32) {
318        self.y = y;
319    }
320    pub fn checked_add(self, rhs: Self) -> Option<Self> {
321        self.x
322            .checked_add(rhs.x)
323            .and_then(|x| self.y.checked_add(rhs.y).map(|y| Self::new(x, y)))
324    }
325    pub fn checked_sub(self, rhs: Self) -> Option<Self> {
326        self.x
327            .checked_sub(rhs.x)
328            .and_then(|x| self.y.checked_sub(rhs.y).map(|y| Self::new(x, y)))
329    }
330    pub fn checked_mul(self, rhs: i32) -> Option<Self> {
331        self.x
332            .checked_mul(rhs)
333            .and_then(|x| self.y.checked_mul(rhs).map(|y| Self::new(x, y)))
334    }
335    pub fn checked_div(self, rhs: i32) -> Option<Self> {
336        self.x
337            .checked_div(rhs)
338            .and_then(|x| self.y.checked_div(rhs).map(|y| Self::new(x, y)))
339    }
340    pub const fn magnitude2(self) -> u32 {
341        (self.x * self.x) as u32 + (self.y * self.y) as u32
342    }
343    pub const fn distance2(self, other: Self) -> u32 {
344        Self {
345            x: self.x - other.x,
346            y: self.y - other.y,
347        }
348        .magnitude2()
349    }
350    pub const fn manhattan_magnitude(self) -> u32 {
351        self.x.abs() as u32 + self.y.abs() as u32
352    }
353    pub const fn manhattan_distance(self, other: Self) -> u32 {
354        Self {
355            x: self.x - other.x,
356            y: self.y - other.y,
357        }
358        .manhattan_magnitude()
359    }
360    pub const fn opposite(self) -> Self {
361        Self {
362            x: -self.x,
363            y: -self.y,
364        }
365    }
366    pub const fn left90(self) -> Self {
367        Self {
368            x: self.y,
369            y: -self.x,
370        }
371    }
372    pub const fn right90(self) -> Self {
373        Self {
374            x: -self.y,
375            y: self.x,
376        }
377    }
378    pub const fn cardinal_left45(self) -> Self {
379        Self {
380            x: self.y + self.x,
381            y: self.y - self.x,
382        }
383    }
384    pub const fn cardinal_right45(self) -> Self {
385        Self {
386            x: self.x - self.y,
387            y: self.y + self.x,
388        }
389    }
390    pub const fn cardinal_left135(self) -> Self {
391        Self {
392            x: self.y - self.x,
393            y: -self.x - self.y,
394        }
395    }
396    pub const fn cardinal_right135(self) -> Self {
397        Self {
398            x: -self.y - self.x,
399            y: self.x - self.y,
400        }
401    }
402
403    pub const fn is_zero(self) -> bool {
404        self.x == 0 && self.y == 0
405    }
406
407    pub fn pairwise_max(self, other: Self) -> Self {
408        Self {
409            x: self.x.max(other.x),
410            y: self.y.max(other.y),
411        }
412    }
413
414    pub fn pairwise_min(self, other: Self) -> Self {
415        Self {
416            x: self.x.min(other.x),
417            y: self.y.min(other.y),
418        }
419    }
420
421    pub const fn transpose(self) -> Self {
422        Self {
423            x: self.y,
424            y: self.x,
425        }
426    }
427}
428
429/// Shorthand for ICoord::new
430pub const fn icoord(x: i32, y: i32) -> ICoord {
431    ICoord::new(x, y)
432}
433
434impl From<(i32, i32)> for ICoord {
435    fn from((x, y): (i32, i32)) -> Self {
436        ICoord::new(x, y)
437    }
438}
439
440impl From<ICoord> for (i32, i32) {
441    fn from(ICoord { x, y }: ICoord) -> Self {
442        (x, y)
443    }
444}
445
446impl From<[i32; 2]> for ICoord {
447    fn from(array: [i32; 2]) -> Self {
448        ICoord::new(array[0], array[1])
449    }
450}
451
452impl From<ICoord> for [i32; 2] {
453    fn from(ICoord { x, y }: ICoord) -> Self {
454        [x, y]
455    }
456}
457
458// Internally a UCoord is an ICoord, but we prevent UCoords from being created with negative
459// dimensions.
460#[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))]
461#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq, Default, PartialOrd, Ord)]
462pub struct UCoord(ICoord);
463
464pub const MAX_UCOORD_FIELD: u32 = ::core::i32::MAX as u32;
465
466pub const MAX_UCOORD: UCoord = UCoord(ICoord {
467    x: MAX_UCOORD_FIELD as i32,
468    y: MAX_UCOORD_FIELD as i32,
469});
470
471impl UCoord {
472    const fn new_unchecked(width: u32, height: u32) -> Self {
473        Self(ICoord {
474            x: width as i32,
475            y: height as i32,
476        })
477    }
478
479    /// Creates a new `UCoord`.
480    /// Panics if `width` or `height` is greater than `::core::i32::MAX`.
481    pub fn new(width: u32, height: u32) -> Self {
482        check_ucoord_limit(width);
483        check_ucoord_limit(height);
484        Self::new_unchecked(width, height)
485    }
486
487    /// Like new, but const and never panics as it's impossible to construct an invalid ucoord
488    pub const fn new_u16(width: u16, height: u16) -> Self {
489        Self(ICoord {
490            x: width as i32,
491            y: height as i32,
492        })
493    }
494
495    pub fn from_icoord(icoord: ICoord) -> Self {
496        icoord.to_ucoord()
497    }
498
499    pub const fn to_icoord(self) -> ICoord {
500        self.0
501    }
502
503    pub const fn get(self, axis: Axis) -> u32 {
504        match axis {
505            Axis::X => self.width(),
506            Axis::Y => self.height(),
507        }
508    }
509
510    pub fn with_axis<F: FnMut(u32) -> u32>(self, axis: Axis, mut f: F) -> Self {
511        match axis {
512            Axis::X => self.set_width(f(self.width())),
513            Axis::Y => self.set_height(f(self.height())),
514        }
515    }
516
517    #[must_use]
518    pub fn set(self, axis: Axis, value: u32) -> Self {
519        check_ucoord_limit(value);
520        match axis {
521            Axis::X => self.set_width(value),
522            Axis::Y => self.set_height(value),
523        }
524    }
525
526    pub fn set_in_place(&mut self, axis: Axis, value: u32) {
527        check_ucoord_limit(value);
528        match axis {
529            Axis::X => self.set_width_in_place(value),
530            Axis::Y => self.set_height_in_place(value),
531        }
532    }
533
534    pub fn new_axis(this_axis: u32, other_axis: u32, axis: Axis) -> Self {
535        let (width, height) = match axis {
536            Axis::X => (this_axis, other_axis),
537            Axis::Y => (other_axis, this_axis),
538        };
539        Self::new(width, height)
540    }
541
542    pub fn get_static<A: StaticAxis>(self) -> u32 {
543        A::ucoord_get(self)
544    }
545    pub fn with_static_axis<A: StaticAxis, F: FnMut(u32) -> u32>(self, f: F) -> Self {
546        A::ucoord_with_axis(self, f)
547    }
548
549    #[must_use]
550    pub fn set_static<A: StaticAxis>(self, value: u32) -> Self {
551        A::ucoord_set(self, value)
552    }
553
554    pub fn set_static_in_place<A: StaticAxis>(&mut self, value: u32) {
555        A::ucoord_set_in_place(self, value)
556    }
557
558    pub fn new_static_axis<A: StaticAxis>(this_axis: u32, other_axis: u32) -> Self {
559        A::new_ucoord(this_axis, other_axis)
560    }
561
562    #[must_use]
563    pub fn set_width(mut self, width: u32) -> Self {
564        check_ucoord_limit(width);
565        self.0.x = width as i32;
566        self
567    }
568
569    #[must_use]
570    pub fn set_height(mut self, height: u32) -> Self {
571        check_ucoord_limit(height);
572        self.0.y = height as i32;
573        self
574    }
575
576    pub fn set_width_in_place(&mut self, width: u32) {
577        check_ucoord_limit(width);
578        self.0.x = width as i32;
579    }
580
581    pub fn set_height_in_place(&mut self, height: u32) {
582        check_ucoord_limit(height);
583        self.0.y = height as i32;
584    }
585
586    /// Returns the width.
587    #[inline]
588    pub const fn width(self) -> u32 {
589        self.0.x as u32
590    }
591
592    /// Returns the height.
593    #[inline]
594    pub const fn height(self) -> u32 {
595        self.0.y as u32
596    }
597
598    /// Return the number of cells in a 2D grid of this size.
599    pub const fn count(self) -> usize {
600        (self.width() * self.height()) as usize
601    }
602
603    pub fn checked_sub(self, rhs: Self) -> Option<Self> {
604        self.width().checked_sub(rhs.width()).and_then(|width| {
605            self.height()
606                .checked_sub(rhs.height())
607                .map(|height| Self::new(width, height))
608        })
609    }
610
611    pub fn saturating_sub(self, rhs: Self) -> Self {
612        let width = self.width().saturating_sub(rhs.width());
613        let height = self.height().saturating_sub(rhs.height());
614        Self::new(width, height)
615    }
616
617    pub const fn max_field() -> u32 {
618        MAX_UCOORD_FIELD
619    }
620
621    pub const fn max() -> Self {
622        MAX_UCOORD
623    }
624
625    pub const fn is_zero(self) -> bool {
626        self.width() == 0 && self.height() == 0
627    }
628
629    pub const fn is_valid(self, icoord: ICoord) -> bool {
630        icoord.is_valid(self)
631    }
632
633    pub const fn constrain(self, icoord: ICoord) -> Option<ICoord> {
634        icoord.constrain(self)
635    }
636
637    pub const fn icoord_iter_row_major(self) -> ICoordIterRowMajor {
638        ICoordIterRowMajor::new(self)
639    }
640
641    pub fn pairwise_max(self, other: Self) -> Self {
642        Self::new_unchecked(
643            self.width().max(other.width()),
644            self.height().max(other.height()),
645        )
646    }
647
648    pub fn pairwise_min(self, other: Self) -> Self {
649        Self::new_unchecked(
650            self.width().min(other.width()),
651            self.height().min(other.height()),
652        )
653    }
654
655    pub const fn transpose(self) -> Self {
656        Self::new_unchecked(self.height(), self.width())
657    }
658
659    pub const fn is_empty(self) -> bool {
660        self.width() == 0 || self.height() == 0
661    }
662
663    pub const fn is_on_edge(self, ICoord { x, y }: ICoord) -> bool {
664        ((x == 0 || x == self.width() as i32 - 1) && y >= 0 && y < self.height() as i32)
665            || ((y == 0 || y == self.height() as i32 - 1) && x >= 0 && x < self.width() as i32)
666    }
667
668    pub fn edge_iter(self) -> EdgeIter {
669        edge_iter::make_iter(self)
670    }
671}
672
673/// Shorthand for UCoord::new
674pub fn ucoord(width: u32, height: u32) -> UCoord {
675    UCoord::new(width, height)
676}
677
678/// Shorthand for UCoord::new_u16
679pub const fn ucoord_u16(width: u16, height: u16) -> UCoord {
680    UCoord::new_u16(width, height)
681}
682
683mod edge_iter {
684    use super::{ICoord, ICoordIterRowMajor, UCoord};
685    use core::{
686        iter::{Chain, Rev},
687        ops::Range,
688    };
689
690    struct Top {
691        x_range: Range<i32>,
692    }
693
694    impl Iterator for Top {
695        type Item = ICoord;
696        fn next(&mut self) -> Option<Self::Item> {
697            self.x_range.next().map(|x| ICoord { x, y: 0 })
698        }
699    }
700
701    struct Right {
702        y_range: Range<i32>,
703        x: i32,
704    }
705
706    impl Iterator for Right {
707        type Item = ICoord;
708        fn next(&mut self) -> Option<Self::Item> {
709            self.y_range.next().map(|y| ICoord { x: self.x, y })
710        }
711    }
712
713    struct Bottom {
714        x_range: Rev<Range<i32>>,
715        y: i32,
716    }
717
718    impl Iterator for Bottom {
719        type Item = ICoord;
720        fn next(&mut self) -> Option<Self::Item> {
721            self.x_range.next().map(|x| ICoord { x, y: self.y })
722        }
723    }
724
725    struct Left {
726        y_range: Rev<Range<i32>>,
727    }
728
729    impl Iterator for Left {
730        type Item = ICoord;
731        fn next(&mut self) -> Option<Self::Item> {
732            self.y_range.next().map(|y| ICoord { x: 0, y })
733        }
734    }
735
736    type TwoDimensional = Chain<Chain<Chain<Top, Right>, Bottom>, Left>;
737
738    enum IterPrivate {
739        ZeroDimensional,
740        OneDimensional(ICoordIterRowMajor),
741        TwoDimensional(TwoDimensional),
742    }
743
744    impl Iterator for IterPrivate {
745        type Item = ICoord;
746        fn next(&mut self) -> Option<Self::Item> {
747            match self {
748                Self::ZeroDimensional => None,
749                Self::OneDimensional(iter) => iter.next(),
750                Self::TwoDimensional(iter) => iter.next(),
751            }
752        }
753    }
754
755    pub struct Iter(IterPrivate);
756
757    impl Iterator for Iter {
758        type Item = ICoord;
759        fn next(&mut self) -> Option<Self::Item> {
760            self.0.next()
761        }
762    }
763
764    pub fn make_iter(ucoord: UCoord) -> Iter {
765        let iter_private = if ucoord.is_empty() {
766            IterPrivate::ZeroDimensional
767        } else if ucoord.width() == 1 || ucoord.height() == 1 {
768            IterPrivate::OneDimensional(ucoord.icoord_iter_row_major())
769        } else {
770            let top = Top {
771                x_range: 0..ucoord.width() as i32 - 1,
772            };
773            let right = Right {
774                y_range: 0..ucoord.height() as i32 - 1,
775                x: ucoord.width() as i32 - 1,
776            };
777            let bottom = Bottom {
778                x_range: (1..ucoord.width() as i32).rev(),
779                y: ucoord.height() as i32 - 1,
780            };
781            let left = Left {
782                y_range: (1..ucoord.height() as i32).rev(),
783            };
784            let all = top.chain(right).chain(bottom).chain(left);
785            IterPrivate::TwoDimensional(all)
786        };
787        Iter(iter_private)
788    }
789}
790pub use edge_iter::Iter as EdgeIter;
791
792impl From<(u32, u32)> for UCoord {
793    fn from((x, y): (u32, u32)) -> Self {
794        UCoord::new(x, y)
795    }
796}
797
798impl From<[u32; 2]> for UCoord {
799    fn from(array: [u32; 2]) -> Self {
800        UCoord::new(array[0], array[1])
801    }
802}
803
804pub struct ICoordIterRowMajor {
805    icoord: ICoord,
806    ucoord: UCoord,
807}
808
809impl ICoordIterRowMajor {
810    pub const fn new(ucoord: UCoord) -> Self {
811        Self {
812            ucoord,
813            icoord: ICoord { x: 0, y: 0 },
814        }
815    }
816}
817
818impl Iterator for ICoordIterRowMajor {
819    type Item = ICoord;
820    fn next(&mut self) -> Option<Self::Item> {
821        if self.icoord.y == self.ucoord.height() as i32 {
822            return None;
823        }
824        let icoord = self.icoord;
825        self.icoord.x += 1;
826        if self.icoord.x == self.ucoord.width() as i32 {
827            self.icoord.x = 0;
828            self.icoord.y += 1;
829        }
830        Some(icoord)
831    }
832}
833
834#[cfg(test)]
835mod test {
836    use super::{ICoord, UCoord};
837
838    #[test]
839    fn normalize() {
840        assert_eq!(
841            ICoord::new(5, 2).normalize(UCoord::new(2, 3)),
842            ICoord::new(1, 2)
843        );
844        assert_eq!(
845            ICoord::new(-4, 3).normalize(UCoord::new(3, 1)),
846            ICoord::new(2, 0)
847        );
848    }
849
850    #[test]
851    fn manhattan_dsitance() {
852        assert_eq!(
853            ICoord::new(-2, 4).manhattan_distance(ICoord::new(5, -2)),
854            13
855        );
856    }
857
858    #[test]
859    fn rotation() {
860        assert_eq!(ICoord::new(2, -3).opposite(), ICoord::new(-2, 3));
861        assert_eq!(ICoord::new(2, -3).left90(), ICoord::new(-3, -2));
862        assert_eq!(ICoord::new(2, -3).right90(), ICoord::new(3, 2));
863        assert_eq!(ICoord::new(0, -1).cardinal_left135(), ICoord::new(-1, 1));
864        assert_eq!(ICoord::new(0, -1).cardinal_right135(), ICoord::new(1, 1));
865        assert_eq!(ICoord::new(-1, 0).cardinal_left135(), ICoord::new(1, 1));
866        assert_eq!(ICoord::new(-1, 0).cardinal_right135(), ICoord::new(1, -1));
867    }
868
869    #[test]
870    fn edge() {
871        assert!(UCoord::new(3, 5).is_on_edge(ICoord::new(0, 0)));
872        assert!(UCoord::new(3, 5).is_on_edge(ICoord::new(2, 0)));
873        assert!(UCoord::new(3, 5).is_on_edge(ICoord::new(0, 3)));
874        assert!(UCoord::new(3, 5).is_on_edge(ICoord::new(0, 4)));
875        assert!(UCoord::new(3, 5).is_on_edge(ICoord::new(1, 4)));
876        assert!(!UCoord::new(3, 5).is_on_edge(ICoord::new(1, 5)));
877    }
878
879    #[test]
880    #[cfg(feature = "std")]
881    fn edge_iter() {
882        use std::collections::BTreeSet;
883        fn test(ucoord: UCoord) {
884            let brute_forced = ucoord
885                .icoord_iter_row_major()
886                .filter(|&c| ucoord.is_on_edge(c))
887                .collect::<Vec<_>>();
888            let via_iter = ucoord.edge_iter().collect::<Vec<_>>();
889            assert_eq!(brute_forced.len(), via_iter.len());
890            assert_eq!(
891                brute_forced.iter().cloned().collect::<BTreeSet<_>>(),
892                via_iter.iter().cloned().collect::<BTreeSet<_>>(),
893            );
894        }
895        test(UCoord::new(0, 0));
896        test(UCoord::new(1, 1));
897        test(UCoord::new(1, 3));
898        test(UCoord::new(3, 1));
899        test(UCoord::new(2, 2));
900        test(UCoord::new(3, 5));
901    }
902}