term_model/
index.rs

1// Copyright 2016 Joe Wilm, The Alacritty Project Contributors
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//     http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15//! Line and Column newtypes for strongly typed tty/grid/terminal APIs
16
17/// Indexing types and implementations for Grid and Line
18use 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/// The side of a cell
27#[derive(Debug, Copy, Clone, Eq, PartialEq)]
28pub enum Side {
29    Left,
30    Right,
31}
32
33/// Index in the grid using row, column notation
34#[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/// A line
121///
122/// Newtype to avoid passing values incorrectly
123#[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/// A column
133///
134/// Newtype to avoid passing values incorrectly
135#[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/// A linear index
145///
146/// Newtype to avoid passing values incorrectly
147#[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
166// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
167// file at the top-level directory of this distribution and at
168// http://rust-lang.org/COPYRIGHT.
169//
170// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
171// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
172// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
173// option. This file may not be copied, modified, or distributed
174// except according to those terms.
175//
176// implements binary operators "&T op U", "T op &U", "&T op &U"
177// based on "T op U" where T and U are expected to be `Copy`able
178macro_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
209/// Macro for deriving deref
210macro_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
276/// This exists because we can't implement Iterator on Range
277/// and the existing impl needs the unstable Step trait
278/// This should be removed and replaced with a Step impl
279/// in the ops macro when `step_by` is stabilized
280pub 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                    // Note: We assume $t <= usize here
301                    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}