chisel_common/char/
coords.rs

1#![allow(dead_code)]
2use std::cmp::Ordering;
3use std::fmt::{Display, Formatter};
4
5/// A [Coords] represents a single location within the parser input
6#[derive(Debug, Copy, Clone, PartialEq)]
7pub struct Coords {
8    /// The absolute character position
9    pub absolute: usize,
10    /// The row position
11    pub line: usize,
12    /// The column position
13    pub column: usize,
14}
15
16/// Associated functions for the [Coords] struct
17impl Coords {
18    /// Create a new coordinate based on a coordinate reference
19    pub fn from_coords(value: &Coords) -> Self {
20        Coords {
21            line: value.line,
22            column: value.column,
23            absolute: value.absolute,
24        }
25    }
26
27    /// Create a new coordinate starting on a specific line
28    pub fn from_line(line: usize) -> Self {
29        Coords {
30            absolute: 0,
31            line,
32            column: 0,
33        }
34    }
35
36    /// Check whether this coordinate is strictly *before* another coordinate
37    pub fn is_before(&self, other: &Coords) -> bool {
38        self < other
39    }
40
41    /// Check whether this coordinate is strictly *after* another coordinate
42    pub fn is_after(&self, other: &Coords) -> bool {
43        self > other
44    }
45
46    /// Take all the values of the supplied [Coords] instance
47    #[inline]
48    pub fn copy_from(&mut self, other: &Coords) {
49        self.line = other.line;
50        self.column = other.column;
51        self.absolute = other.absolute;
52    }
53
54    /// In place increment
55    #[inline]
56    pub fn increment(&mut self) {
57        self.column += 1;
58        self.absolute += 1;
59    }
60
61    /// In place decrement
62    #[inline]
63    pub fn decrement(&mut self) {
64        self.column -= 1;
65        self.absolute -= 1;
66    }
67
68    /// In place increment with a line return
69    #[inline]
70    pub fn increment_newline(&mut self) {
71        self.column = 0;
72        self.line += 1;
73        self.absolute += 1;
74    }
75
76    /// Increment the coordinate within the current line and return new struct
77    #[inline]
78    pub fn copy_increment(&self) -> Self {
79        Coords {
80            line: self.line,
81            column: self.column + 1,
82            absolute: self.absolute + 1,
83        }
84    }
85
86    /// Increment the coordinates and bump the line number (assumes that the new line will start
87    /// in column zero) and return new struct
88    #[inline]
89    pub fn copy_increment_newline(&self) -> Self {
90        Coords {
91            line: self.line + 1,
92            column: 1,
93            absolute: self.absolute + 1,
94        }
95    }
96
97    /// Decrement the coordinate within the current line, but panic if we try and decrement
98    /// column or absolute below zero, return a new struct
99    #[inline]
100    pub fn copy_decrement(&mut self) -> Self {
101        Coords {
102            line: self.line,
103            column: self.column - 1,
104            absolute: self.absolute - 1,
105        }
106    }
107}
108
109impl Display for Coords {
110    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
111        write!(
112            f,
113            "[abs: {}, line: {}, column: {}]",
114            self.absolute, self.line, self.column
115        )
116    }
117}
118
119impl Default for Coords {
120    /// The default set of coordinates are positioned at the start of the first row
121    fn default() -> Self {
122        Coords {
123            absolute: 0,
124            line: 0,
125            column: 0,
126        }
127    }
128}
129
130impl Eq for Coords {}
131
132impl PartialOrd<Self> for Coords {
133    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
134        match self.absolute.cmp(&other.absolute) {
135            Ordering::Less => Some(Ordering::Less),
136            Ordering::Equal => Some(Ordering::Equal),
137            Ordering::Greater => Some(Ordering::Greater),
138        }
139    }
140}
141
142impl Ord for Coords {
143    fn cmp(&self, other: &Self) -> Ordering {
144        self.absolute.cmp(&other.absolute)
145    }
146}
147
148#[cfg(test)]
149mod test {
150    use crate::char::coords::Coords;
151
152    #[test]
153    fn is_before_behaves_as_you_would_expect() {
154        let c1 = Coords {
155            line: 1,
156            column: 1,
157            absolute: 1,
158        };
159        let c2 = Coords {
160            line: 1,
161            column: 12,
162            absolute: 12,
163        };
164        assert!(c1.is_before(&c2));
165        assert!(!c2.is_before(&c1));
166    }
167
168    #[test]
169    fn is_after_behaves_correctly() {
170        let c1 = Coords {
171            line: 1,
172            column: 1,
173            absolute: 1,
174        };
175        let c2 = Coords {
176            line: 1,
177            column: 12,
178            absolute: 12,
179        };
180        assert!(!c1.is_after(&c2));
181        assert!(c2.is_after(&c1))
182    }
183
184    #[test]
185    fn equality_between_coords() {
186        let c1 = Coords {
187            line: 1,
188            column: 1,
189            absolute: 1,
190        };
191        let c2 = Coords {
192            line: 1,
193            column: 1,
194            absolute: 1,
195        };
196        assert_eq!(c1, c2)
197    }
198
199    #[test]
200    fn inc_works() {
201        let mut c1 = Coords::from_line(1);
202        for _ in 1..=5 {
203            c1 = c1.copy_increment();
204        }
205        assert_eq!(
206            c1,
207            Coords {
208                line: 1,
209                column: 5,
210                absolute: 5
211            }
212        )
213    }
214
215    #[test]
216    fn inc_newline_works() {
217        let mut c1 = Coords::default();
218        let mut c2 = Coords::default();
219        assert_eq!(c1, c2);
220        c1 = c1.copy_increment_newline();
221        assert!(c1 > c2);
222        c2 = c2.copy_increment_newline();
223        assert_eq!(c1, c2)
224    }
225
226    #[test]
227    fn dec_works() {
228        let mut c1 = Coords::from_line(1);
229        for _ in 1..=5 {
230            c1.increment();
231        }
232        for _ in 1..=3 {
233            c1.decrement()
234        }
235        assert_eq!(
236            c1,
237            Coords {
238                line: 1,
239                column: 2,
240                absolute: 2
241            }
242        )
243    }
244
245    #[test]
246    #[should_panic]
247    fn dec_panics() {
248        let mut c1 = Coords::from_line(1);
249        for _ in 1..=5 {
250            c1.increment();
251        }
252        for _ in 1..=6 {
253            c1.decrement()
254        }
255    }
256
257    #[test]
258    fn merge_should_take_all_values_from_source() {
259        let c1 = Coords::default().copy_increment();
260        let mut c2 = Coords::default();
261        c2.copy_from(&c1);
262        assert_eq!(c1, c2)
263    }
264}