1use std::cmp::{Ord, Ordering};
19use std::fmt;
20use std::ops::{self, Add, AddAssign, Deref, Range, Sub, SubAssign};
21
22use serde::{Deserialize, Serialize};
23
24use crate::term::RenderableCell;
25
26#[derive(Debug, Copy, Clone, Eq, PartialEq)]
28pub enum Side {
29 Left,
30 Right,
31}
32
33#[derive(Debug, Clone, Copy, Default, Eq, PartialEq, PartialOrd)]
35pub struct Point<L = Line> {
36 pub line: L,
37 pub col: Column,
38}
39
40impl<L> Point<L> {
41 pub fn new(line: L, col: Column) -> Point<L> {
42 Point { line, col }
43 }
44
45 #[inline]
46 #[must_use = "this returns the result of the operation, without modifying the original"]
47 pub fn sub(mut self, num_cols: usize, length: usize, absolute_indexing: bool) -> Point<L>
48 where
49 L: Copy + Add<usize, Output = L> + Sub<usize, Output = L>,
50 {
51 let line_changes = f32::ceil(length.saturating_sub(self.col.0) as f32 / num_cols as f32);
52 if absolute_indexing {
53 self.line = self.line + line_changes as usize;
54 } else {
55 self.line = self.line - line_changes as usize;
56 }
57 self.col = Column((num_cols + self.col.0 - length % num_cols) % num_cols);
58 self
59 }
60
61 #[inline]
62 #[must_use = "this returns the result of the operation, without modifying the original"]
63 pub fn add(mut self, num_cols: usize, length: usize, absolute_indexing: bool) -> Point<L>
64 where
65 L: Copy + Add<usize, Output = L> + Sub<usize, Output = L>,
66 {
67 let line_changes = (length + self.col.0) / num_cols;
68 if absolute_indexing {
69 self.line = self.line - line_changes;
70 } else {
71 self.line = self.line + line_changes;
72 }
73 self.col = Column((self.col.0 + length) % num_cols);
74 self
75 }
76}
77
78impl Ord for Point {
79 fn cmp(&self, other: &Point) -> Ordering {
80 use std::cmp::Ordering::*;
81 match (self.line.cmp(&other.line), self.col.cmp(&other.col)) {
82 (Equal, Equal) => Equal,
83 (Equal, ord) | (ord, Equal) => ord,
84 (Less, _) => Less,
85 (Greater, _) => Greater,
86 }
87 }
88}
89
90impl From<Point<usize>> for Point<isize> {
91 fn from(point: Point<usize>) -> Self {
92 Point::new(point.line as isize, point.col)
93 }
94}
95
96impl From<Point<usize>> for Point<Line> {
97 fn from(point: Point<usize>) -> Self {
98 Point::new(Line(point.line), point.col)
99 }
100}
101
102impl From<Point<isize>> for Point<usize> {
103 fn from(point: Point<isize>) -> Self {
104 Point::new(point.line as usize, point.col)
105 }
106}
107
108impl From<Point> for Point<usize> {
109 fn from(point: Point) -> Self {
110 Point::new(point.line.0, point.col)
111 }
112}
113
114impl From<RenderableCell> for Point<Line> {
115 fn from(cell: RenderableCell) -> Self {
116 Point::new(cell.line, cell.column)
117 }
118}
119
120#[derive(Debug, Copy, Clone, Eq, PartialEq, Default, Ord, PartialOrd, Serialize, Deserialize)]
124pub struct Line(pub usize);
125
126impl fmt::Display for Line {
127 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
128 write!(f, "{}", self.0)
129 }
130}
131
132#[derive(Debug, Copy, Clone, Eq, PartialEq, Default, Ord, PartialOrd, Serialize, Deserialize)]
136pub struct Column(pub usize);
137
138impl fmt::Display for Column {
139 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
140 write!(f, "{}", self.0)
141 }
142}
143
144#[derive(Debug, Copy, Clone, Eq, PartialEq, Default, Ord, PartialOrd, Serialize, Deserialize)]
148pub struct Linear(pub usize);
149
150impl Linear {
151 pub fn new(columns: Column, column: Column, line: Line) -> Self {
152 Linear(line.0 * columns.0 + column.0)
153 }
154
155 pub fn from_point(columns: Column, point: Point<usize>) -> Self {
156 Linear(point.line * columns.0 + point.col.0)
157 }
158}
159
160impl fmt::Display for Linear {
161 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
162 write!(f, "Linear({})", self.0)
163 }
164}
165
166macro_rules! forward_ref_binop {
179 (impl $imp:ident, $method:ident for $t:ty, $u:ty) => {
180 impl<'a> $imp<$u> for &'a $t {
181 type Output = <$t as $imp<$u>>::Output;
182
183 #[inline]
184 fn $method(self, other: $u) -> <$t as $imp<$u>>::Output {
185 $imp::$method(*self, other)
186 }
187 }
188
189 impl<'a> $imp<&'a $u> for $t {
190 type Output = <$t as $imp<$u>>::Output;
191
192 #[inline]
193 fn $method(self, other: &'a $u) -> <$t as $imp<$u>>::Output {
194 $imp::$method(self, *other)
195 }
196 }
197
198 impl<'a, 'b> $imp<&'a $u> for &'b $t {
199 type Output = <$t as $imp<$u>>::Output;
200
201 #[inline]
202 fn $method(self, other: &'a $u) -> <$t as $imp<$u>>::Output {
203 $imp::$method(*self, *other)
204 }
205 }
206 };
207}
208
209macro_rules! deref {
211 ($ty:ty, $target:ty) => {
212 impl Deref for $ty {
213 type Target = $target;
214
215 #[inline]
216 fn deref(&self) -> &$target {
217 &self.0
218 }
219 }
220 };
221}
222
223macro_rules! add {
224 ($ty:ty, $construct:expr) => {
225 impl ops::Add<$ty> for $ty {
226 type Output = $ty;
227
228 #[inline]
229 fn add(self, rhs: $ty) -> $ty {
230 $construct(self.0 + rhs.0)
231 }
232 }
233 };
234}
235
236macro_rules! sub {
237 ($ty:ty, $construct:expr) => {
238 impl ops::Sub<$ty> for $ty {
239 type Output = $ty;
240
241 #[inline]
242 fn sub(self, rhs: $ty) -> $ty {
243 $construct(self.0 - rhs.0)
244 }
245 }
246
247 impl<'a> ops::Sub<$ty> for &'a $ty {
248 type Output = $ty;
249
250 #[inline]
251 fn sub(self, rhs: $ty) -> $ty {
252 $construct(self.0 - rhs.0)
253 }
254 }
255
256 impl<'a> ops::Sub<&'a $ty> for $ty {
257 type Output = $ty;
258
259 #[inline]
260 fn sub(self, rhs: &'a $ty) -> $ty {
261 $construct(self.0 - rhs.0)
262 }
263 }
264
265 impl<'a, 'b> ops::Sub<&'a $ty> for &'b $ty {
266 type Output = $ty;
267
268 #[inline]
269 fn sub(self, rhs: &'a $ty) -> $ty {
270 $construct(self.0 - rhs.0)
271 }
272 }
273 };
274}
275
276pub struct IndexRange<T>(pub Range<T>);
281
282impl<T> From<Range<T>> for IndexRange<T> {
283 fn from(from: Range<T>) -> Self {
284 IndexRange(from)
285 }
286}
287
288macro_rules! ops {
289 ($ty:ty, $construct:expr) => {
290 add!($ty, $construct);
291 sub!($ty, $construct);
292 deref!($ty, usize);
293 forward_ref_binop!(impl Add, add for $ty, $ty);
294
295 impl $ty {
296 #[inline]
297 fn steps_between(start: $ty, end: $ty, by: $ty) -> Option<usize> {
298 if by == $construct(0) { return None; }
299 if start < end {
300 let diff = (end - start).0;
302 let by = by.0;
303 if diff % by > 0 {
304 Some(diff / by + 1)
305 } else {
306 Some(diff / by)
307 }
308 } else {
309 Some(0)
310 }
311 }
312
313 #[inline]
314 fn steps_between_by_one(start: $ty, end: $ty) -> Option<usize> {
315 Self::steps_between(start, end, $construct(1))
316 }
317 }
318
319 impl Iterator for IndexRange<$ty> {
320 type Item = $ty;
321 #[inline]
322 fn next(&mut self) -> Option<$ty> {
323 if self.0.start < self.0.end {
324 let old = self.0.start;
325 self.0.start = old + 1;
326 Some(old)
327 } else {
328 None
329 }
330 }
331 #[inline]
332 fn size_hint(&self) -> (usize, Option<usize>) {
333 match Self::Item::steps_between_by_one(self.0.start, self.0.end) {
334 Some(hint) => (hint, Some(hint)),
335 None => (0, None)
336 }
337 }
338 }
339
340 impl DoubleEndedIterator for IndexRange<$ty> {
341 #[inline]
342 fn next_back(&mut self) -> Option<$ty> {
343 if self.0.start < self.0.end {
344 let new = self.0.end - 1;
345 self.0.end = new;
346 Some(new)
347 } else {
348 None
349 }
350 }
351 }
352 impl AddAssign<$ty> for $ty {
353 #[inline]
354 fn add_assign(&mut self, rhs: $ty) {
355 self.0 += rhs.0
356 }
357 }
358
359 impl SubAssign<$ty> for $ty {
360 #[inline]
361 fn sub_assign(&mut self, rhs: $ty) {
362 self.0 -= rhs.0
363 }
364 }
365
366 impl AddAssign<usize> for $ty {
367 #[inline]
368 fn add_assign(&mut self, rhs: usize) {
369 self.0 += rhs
370 }
371 }
372
373 impl SubAssign<usize> for $ty {
374 #[inline]
375 fn sub_assign(&mut self, rhs: usize) {
376 self.0 -= rhs
377 }
378 }
379
380 impl From<usize> for $ty {
381 #[inline]
382 fn from(val: usize) -> $ty {
383 $construct(val)
384 }
385 }
386
387 impl Add<usize> for $ty {
388 type Output = $ty;
389
390 #[inline]
391 fn add(self, rhs: usize) -> $ty {
392 $construct(self.0 + rhs)
393 }
394 }
395
396 impl Sub<usize> for $ty {
397 type Output = $ty;
398
399 #[inline]
400 fn sub(self, rhs: usize) -> $ty {
401 $construct(self.0 - rhs)
402 }
403 }
404 }
405}
406
407ops!(Line, Line);
408ops!(Column, Column);
409ops!(Linear, Linear);
410
411#[cfg(test)]
412mod tests {
413 use super::{Column, Line, Point};
414
415 #[test]
416 fn location_ordering() {
417 assert!(Point::new(Line(0), Column(0)) == Point::new(Line(0), Column(0)));
418 assert!(Point::new(Line(1), Column(0)) > Point::new(Line(0), Column(0)));
419 assert!(Point::new(Line(0), Column(1)) > Point::new(Line(0), Column(0)));
420 assert!(Point::new(Line(1), Column(1)) > Point::new(Line(0), Column(0)));
421 assert!(Point::new(Line(1), Column(1)) > Point::new(Line(0), Column(1)));
422 assert!(Point::new(Line(1), Column(1)) > Point::new(Line(1), Column(0)));
423 }
424}