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