1use std::{
2 cmp::Ordering,
3 ops::{Add, AddAssign, Sub},
4};
5
6#[derive(Clone, Copy, Default, Eq, PartialEq, Debug, Hash)]
7pub struct Point {
8 pub row: u32,
9 pub column: u32,
10}
11
12impl Point {
13 pub const MAX: Self = Self {
14 row: u32::MAX,
15 column: u32::MAX,
16 };
17
18 pub fn new(row: u32, column: u32) -> Self {
19 Point { row, column }
20 }
21
22 pub fn zero() -> Self {
23 Point::new(0, 0)
24 }
25
26 pub fn is_zero(&self) -> bool {
27 self.row == 0 && self.column == 0
28 }
29}
30
31impl<'a> Add<&'a Self> for Point {
32 type Output = Point;
33
34 fn add(self, other: &'a Self) -> Self::Output {
35 self + *other
36 }
37}
38
39impl Add for Point {
40 type Output = Point;
41
42 fn add(self, other: Self) -> Self::Output {
43 if other.row == 0 {
44 Point::new(self.row, self.column + other.column)
45 } else {
46 Point::new(self.row + other.row, other.column)
47 }
48 }
49}
50
51impl<'a> Sub<&'a Self> for Point {
52 type Output = Point;
53
54 fn sub(self, other: &'a Self) -> Self::Output {
55 self - *other
56 }
57}
58
59impl Sub for Point {
60 type Output = Point;
61
62 fn sub(self, other: Self) -> Self::Output {
63 debug_assert!(other <= self);
64
65 if self.row == other.row {
66 Point::new(0, self.column - other.column)
67 } else {
68 Point::new(self.row - other.row, self.column)
69 }
70 }
71}
72
73impl<'a> AddAssign<&'a Self> for Point {
74 fn add_assign(&mut self, other: &'a Self) {
75 *self += *other;
76 }
77}
78
79impl AddAssign<Self> for Point {
80 fn add_assign(&mut self, other: Self) {
81 if other.row == 0 {
82 self.column += other.column;
83 } else {
84 self.row += other.row;
85 self.column = other.column;
86 }
87 }
88}
89
90impl PartialOrd for Point {
91 fn partial_cmp(&self, other: &Point) -> Option<Ordering> {
92 Some(self.cmp(other))
93 }
94}
95
96impl Ord for Point {
97 #[cfg(target_pointer_width = "64")]
98 fn cmp(&self, other: &Point) -> Ordering {
99 let a = (self.row as usize) << 32 | self.column as usize;
100 let b = (other.row as usize) << 32 | other.column as usize;
101 a.cmp(&b)
102 }
103
104 #[cfg(target_pointer_width = "32")]
105 fn cmp(&self, other: &Point) -> Ordering {
106 match self.row.cmp(&other.row) {
107 Ordering::Equal => self.column.cmp(&other.column),
108 comparison @ _ => comparison,
109 }
110 }
111}