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 parse_str(s: &str) -> Self {
27 let mut point = Self::zero();
28 for (row, line) in s.split('\n').enumerate() {
29 point.row = row as u32;
30 point.column = line.len() as u32;
31 }
32 point
33 }
34
35 pub fn is_zero(&self) -> bool {
36 self.row == 0 && self.column == 0
37 }
38
39 pub fn saturating_sub(self, other: Self) -> Self {
40 if self < other {
41 Self::zero()
42 } else {
43 self - other
44 }
45 }
46}
47
48impl<'a> Add<&'a Self> for Point {
49 type Output = Point;
50
51 fn add(self, other: &'a Self) -> Self::Output {
52 self + *other
53 }
54}
55
56impl Add for Point {
57 type Output = Point;
58
59 fn add(self, other: Self) -> Self::Output {
60 if other.row == 0 {
61 Point::new(self.row, self.column + other.column)
62 } else {
63 Point::new(self.row + other.row, other.column)
64 }
65 }
66}
67
68impl<'a> Sub<&'a Self> for Point {
69 type Output = Point;
70
71 fn sub(self, other: &'a Self) -> Self::Output {
72 self - *other
73 }
74}
75
76impl Sub for Point {
77 type Output = Point;
78
79 fn sub(self, other: Self) -> Self::Output {
80 debug_assert!(other <= self);
81
82 if self.row == other.row {
83 Point::new(0, self.column - other.column)
84 } else {
85 Point::new(self.row - other.row, self.column)
86 }
87 }
88}
89
90impl<'a> AddAssign<&'a Self> for Point {
91 fn add_assign(&mut self, other: &'a Self) {
92 *self += *other;
93 }
94}
95
96impl AddAssign<Self> for Point {
97 fn add_assign(&mut self, other: Self) {
98 if other.row == 0 {
99 self.column += other.column;
100 } else {
101 self.row += other.row;
102 self.column = other.column;
103 }
104 }
105}
106
107impl PartialOrd for Point {
108 fn partial_cmp(&self, other: &Point) -> Option<Ordering> {
109 Some(self.cmp(other))
110 }
111}
112
113impl Ord for Point {
114 #[cfg(target_pointer_width = "64")]
115 fn cmp(&self, other: &Point) -> Ordering {
116 let a = (self.row as usize) << 32 | self.column as usize;
117 let b = (other.row as usize) << 32 | other.column as usize;
118 a.cmp(&b)
119 }
120
121 #[cfg(target_pointer_width = "32")]
122 fn cmp(&self, other: &Point) -> Ordering {
123 match self.row.cmp(&other.row) {
124 Ordering::Equal => self.column.cmp(&other.column),
125 comparison @ _ => comparison,
126 }
127 }
128}