1use std::{
  2    fmt::{Debug, Display},
  3    marker::PhantomData,
  4    ops::{Add, AddAssign, Sub, SubAssign},
  5};
  6use text::Point;
  7
  8#[repr(transparent)]
  9pub struct TypedOffset<T> {
 10    pub value: usize,
 11    _marker: PhantomData<T>,
 12}
 13
 14#[repr(transparent)]
 15pub struct TypedPoint<T> {
 16    pub value: Point,
 17    _marker: PhantomData<T>,
 18}
 19
 20#[repr(transparent)]
 21pub struct TypedRow<T> {
 22    pub value: u32,
 23    _marker: PhantomData<T>,
 24}
 25
 26impl<T> TypedOffset<T> {
 27    pub fn new(offset: usize) -> Self {
 28        Self {
 29            value: offset,
 30            _marker: PhantomData,
 31        }
 32    }
 33
 34    pub fn saturating_sub(self, n: TypedOffset<T>) -> Self {
 35        Self {
 36            value: self.value.saturating_sub(n.value),
 37            _marker: PhantomData,
 38        }
 39    }
 40
 41    pub fn zero() -> Self {
 42        Self::new(0)
 43    }
 44
 45    pub fn is_zero(&self) -> bool {
 46        self.value == 0
 47    }
 48}
 49
 50impl<T> TypedPoint<T> {
 51    pub fn new(row: u32, column: u32) -> Self {
 52        Self {
 53            value: Point::new(row, column),
 54            _marker: PhantomData,
 55        }
 56    }
 57
 58    pub fn wrap(point: Point) -> Self {
 59        Self {
 60            value: point,
 61            _marker: PhantomData,
 62        }
 63    }
 64
 65    pub fn row(&self) -> u32 {
 66        self.value.row
 67    }
 68
 69    pub fn column(&self) -> u32 {
 70        self.value.column
 71    }
 72
 73    pub fn zero() -> Self {
 74        Self::wrap(Point::zero())
 75    }
 76
 77    pub fn is_zero(&self) -> bool {
 78        self.value.is_zero()
 79    }
 80}
 81
 82impl<T> TypedRow<T> {
 83    pub fn new(row: u32) -> Self {
 84        Self {
 85            value: row,
 86            _marker: PhantomData,
 87        }
 88    }
 89}
 90
 91impl<T> Copy for TypedOffset<T> {}
 92impl<T> Copy for TypedPoint<T> {}
 93impl<T> Copy for TypedRow<T> {}
 94
 95impl<T> Clone for TypedOffset<T> {
 96    fn clone(&self) -> Self {
 97        *self
 98    }
 99}
100impl<T> Clone for TypedPoint<T> {
101    fn clone(&self) -> Self {
102        *self
103    }
104}
105impl<T> Clone for TypedRow<T> {
106    fn clone(&self) -> Self {
107        *self
108    }
109}
110
111impl<T> Default for TypedOffset<T> {
112    fn default() -> Self {
113        Self::new(0)
114    }
115}
116impl<T> Default for TypedPoint<T> {
117    fn default() -> Self {
118        Self::wrap(Point::default())
119    }
120}
121impl<T> Default for TypedRow<T> {
122    fn default() -> Self {
123        Self::new(0)
124    }
125}
126
127impl<T> PartialOrd for TypedOffset<T> {
128    fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
129        Some(self.cmp(other))
130    }
131}
132impl<T> PartialOrd for TypedPoint<T> {
133    fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
134        Some(self.cmp(other))
135    }
136}
137impl<T> PartialOrd for TypedRow<T> {
138    fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
139        Some(self.cmp(other))
140    }
141}
142
143impl<T> Ord for TypedOffset<T> {
144    fn cmp(&self, other: &Self) -> std::cmp::Ordering {
145        self.value.cmp(&other.value)
146    }
147}
148impl<T> Ord for TypedPoint<T> {
149    fn cmp(&self, other: &Self) -> std::cmp::Ordering {
150        self.value.cmp(&other.value)
151    }
152}
153impl<T> Ord for TypedRow<T> {
154    fn cmp(&self, other: &Self) -> std::cmp::Ordering {
155        self.value.cmp(&other.value)
156    }
157}
158
159impl<T> PartialEq for TypedOffset<T> {
160    fn eq(&self, other: &Self) -> bool {
161        self.value == other.value
162    }
163}
164impl<T> PartialEq for TypedPoint<T> {
165    fn eq(&self, other: &Self) -> bool {
166        self.value == other.value
167    }
168}
169impl<T> PartialEq for TypedRow<T> {
170    fn eq(&self, other: &Self) -> bool {
171        self.value == other.value
172    }
173}
174
175impl<T> Eq for TypedOffset<T> {}
176impl<T> Eq for TypedPoint<T> {}
177impl<T> Eq for TypedRow<T> {}
178
179impl<T> Debug for TypedOffset<T> {
180    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
181        write!(f, "{}Offset({})", type_name::<T>(), self.value)
182    }
183}
184impl<T> Debug for TypedPoint<T> {
185    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
186        write!(
187            f,
188            "{}Point({}, {})",
189            type_name::<T>(),
190            self.value.row,
191            self.value.column
192        )
193    }
194}
195impl<T> Debug for TypedRow<T> {
196    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
197        write!(f, "{}Row({})", type_name::<T>(), self.value)
198    }
199}
200
201impl<T> Display for TypedOffset<T> {
202    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
203        Display::fmt(&self.value, f)
204    }
205}
206impl<T> Display for TypedRow<T> {
207    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
208        Display::fmt(&self.value, f)
209    }
210}
211
212fn type_name<T>() -> &'static str {
213    std::any::type_name::<T>().split("::").last().unwrap()
214}
215
216impl<T> Add<TypedOffset<T>> for TypedOffset<T> {
217    type Output = Self;
218
219    fn add(self, other: Self) -> Self {
220        TypedOffset::new(self.value + other.value)
221    }
222}
223impl<T> Add<TypedPoint<T>> for TypedPoint<T> {
224    type Output = Self;
225
226    fn add(self, other: Self) -> Self {
227        TypedPoint::wrap(self.value + other.value)
228    }
229}
230
231impl<T> Sub<TypedOffset<T>> for TypedOffset<T> {
232    type Output = Self;
233    fn sub(self, other: Self) -> Self {
234        TypedOffset::new(self.value - other.value)
235    }
236}
237impl<T> Sub<TypedPoint<T>> for TypedPoint<T> {
238    type Output = Self;
239    fn sub(self, other: Self) -> Self {
240        TypedPoint::wrap(self.value - other.value)
241    }
242}
243
244impl<T> AddAssign<TypedOffset<T>> for TypedOffset<T> {
245    fn add_assign(&mut self, other: Self) {
246        self.value += other.value;
247    }
248}
249impl<T> AddAssign<TypedPoint<T>> for TypedPoint<T> {
250    fn add_assign(&mut self, other: Self) {
251        self.value += other.value;
252    }
253}
254
255impl<T> SubAssign<Self> for TypedOffset<T> {
256    fn sub_assign(&mut self, other: Self) {
257        self.value -= other.value;
258    }
259}
260impl<T> SubAssign<Self> for TypedRow<T> {
261    fn sub_assign(&mut self, other: Self) {
262        self.value -= other.value;
263    }
264}