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 from_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
40impl<'a> Add<&'a Self> for Point {
41 type Output = Point;
42
43 fn add(self, other: &'a Self) -> Self::Output {
44 self + *other
45 }
46}
47
48impl Add for Point {
49 type Output = Point;
50
51 fn add(self, other: Self) -> Self::Output {
52 if other.row == 0 {
53 Point::new(self.row, self.column + other.column)
54 } else {
55 Point::new(self.row + other.row, other.column)
56 }
57 }
58}
59
60impl<'a> Sub<&'a Self> for Point {
61 type Output = Point;
62
63 fn sub(self, other: &'a Self) -> Self::Output {
64 self - *other
65 }
66}
67
68impl Sub for Point {
69 type Output = Point;
70
71 fn sub(self, other: Self) -> Self::Output {
72 debug_assert!(other <= self);
73
74 if self.row == other.row {
75 Point::new(0, self.column - other.column)
76 } else {
77 Point::new(self.row - other.row, self.column)
78 }
79 }
80}
81
82impl<'a> AddAssign<&'a Self> for Point {
83 fn add_assign(&mut self, other: &'a Self) {
84 *self += *other;
85 }
86}
87
88impl AddAssign<Self> for Point {
89 fn add_assign(&mut self, other: Self) {
90 if other.row == 0 {
91 self.column += other.column;
92 } else {
93 self.row += other.row;
94 self.column = other.column;
95 }
96 }
97}
98
99impl PartialOrd for Point {
100 fn partial_cmp(&self, other: &Point) -> Option<Ordering> {
101 Some(self.cmp(other))
102 }
103}
104
105impl Ord for Point {
106 #[cfg(target_pointer_width = "64")]
107 fn cmp(&self, other: &Point) -> Ordering {
108 let a = (self.row as usize) << 32 | self.column as usize;
109 let b = (other.row as usize) << 32 | other.column as usize;
110 a.cmp(&b)
111 }
112
113 #[cfg(target_pointer_width = "32")]
114 fn cmp(&self, other: &Point) -> Ordering {
115 match self.row.cmp(&other.row) {
116 Ordering::Equal => self.column.cmp(&other.column),
117 comparison @ _ => comparison,
118 }
119 }
120}