roan_error/
position.rs

1use std::fmt;
2
3/// Represents a position in a text, consisting of line, column, and byte index.
4#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
5pub struct Position {
6    /// The current line number (starting from 1).
7    pub line: u32,
8    /// The current column number (starting from 1).
9    pub column: u32,
10    /// The current byte index in the text (starting from 0).
11    pub index: usize,
12}
13
14impl Position {
15    /// Creates a new `Position` with the given line, column, and index.
16    ///
17    /// # Arguments
18    ///
19    /// * `line` - The line number (1-based).
20    /// * `column` - The column number (1-based).
21    /// * `index` - The byte index in the text (0-based).
22    ///
23    /// # Example
24    ///
25    /// ```
26    /// use roan_error::Position;
27    /// let pos = Position::new(1, 1, 0);
28    /// assert_eq!(pos.line(), 1);
29    /// assert_eq!(pos.column(), 1);
30    /// assert_eq!(pos.index(), 0);
31    /// ```
32    pub fn new(line: u32, column: u32, index: usize) -> Self {
33        Self {
34            line,
35            column,
36            index,
37        }
38    }
39
40    /// Increments the line number, resets the column to 1, and increments the index by 1.
41    pub fn increment_line(&mut self) {
42        self.line += 1;
43        self.column = 1;
44        self.index += 1;
45    }
46
47    /// Increments the column number and the index by 1.
48    pub fn increment_column(&mut self) {
49        self.column += 1;
50        self.index += 1;
51    }
52
53    /// Returns the current line number.
54    ///
55    /// # Returns
56    ///
57    /// The line number (1-based).
58    pub fn line(&self) -> u32 {
59        self.line
60    }
61
62    /// Returns the current column number.
63    ///
64    /// # Returns
65    ///
66    /// The column number (1-based).
67    pub fn column(&self) -> u32 {
68        self.column
69    }
70
71    /// Returns the current byte index.
72    ///
73    /// # Returns
74    ///
75    /// The byte index (0-based).
76    pub fn index(&self) -> usize {
77        self.index
78    }
79}
80
81impl fmt::Display for Position {
82    /// Formats the position as `line:column (index: byte_index)`.
83    ///
84    /// # Example
85    ///
86    /// ```
87    /// use roan_error::Position;
88    /// let pos = Position::new(1, 1, 0);
89    /// assert_eq!(format!("{}", pos), "1:1 (index: 0)");
90    /// ```
91    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
92        write!(f, "{}:{} (index: {})", self.line, self.column, self.index)
93    }
94}
95
96impl Default for Position {
97    /// Returns a default `Position`, starting at line 1, column 1, and index 0.
98    ///
99    /// # Example
100    ///
101    /// ```
102    /// use roan_error::Position;
103    /// let default_pos = Position::default();
104    /// assert_eq!(default_pos, Position::new(1, 1, 0));
105    /// ```
106    fn default() -> Self {
107        Self::new(1, 1, 0)
108    }
109}
110
111#[cfg(test)]
112mod tests {
113    use super::*;
114
115    #[test]
116    fn test_position_new() {
117        let pos = Position::new(1, 1, 0);
118        assert_eq!(pos.line(), 1);
119        assert_eq!(pos.column(), 1);
120        assert_eq!(pos.index(), 0);
121    }
122
123    #[test]
124    fn test_position_increment_line() {
125        let mut pos = Position::new(1, 1, 0);
126        pos.increment_line();
127        assert_eq!(pos.line(), 2);
128        assert_eq!(pos.column(), 1);
129        assert_eq!(pos.index(), 1);
130    }
131
132    #[test]
133    fn test_position_increment_column() {
134        let mut pos = Position::new(1, 1, 0);
135        pos.increment_column();
136        assert_eq!(pos.line(), 1);
137        assert_eq!(pos.column(), 2);
138        assert_eq!(pos.index(), 1);
139    }
140
141    #[test]
142    fn test_position_display() {
143        let pos = Position::new(1, 1, 0);
144        assert_eq!(format!("{}", pos), "1:1 (index: 0)");
145    }
146
147    #[test]
148    fn test_position_default() {
149        let default_pos = Position::default();
150        assert_eq!(default_pos, Position::new(1, 1, 0));
151    }
152}