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#[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
429pub 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#[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 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 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 #[inline]
588 pub const fn width(self) -> u32 {
589 self.0.x as u32
590 }
591
592 #[inline]
594 pub const fn height(self) -> u32 {
595 self.0.y as u32
596 }
597
598 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
673pub fn ucoord(width: u32, height: u32) -> UCoord {
675 UCoord::new(width, height)
676}
677
678pub 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}