1#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
11pub struct Position {
12 pub row: usize,
13 pub col: usize,
14}
15
16impl Position {
17 pub const fn new(row: usize, col: usize) -> Self {
18 Self { row, col }
19 }
20
21 pub fn byte_offset(self, line: &str) -> usize {
25 line.char_indices()
26 .nth(self.col)
27 .map(|(b, _)| b)
28 .unwrap_or(line.len())
29 }
30}
31
32#[cfg(test)]
33mod tests {
34 use super::Position;
35
36 #[test]
37 fn byte_offset_ascii() {
38 assert_eq!(Position::new(0, 0).byte_offset("hello"), 0);
39 assert_eq!(Position::new(0, 3).byte_offset("hello"), 3);
40 assert_eq!(Position::new(0, 5).byte_offset("hello"), 5);
41 assert_eq!(Position::new(0, 99).byte_offset("hello"), 5);
44 }
45
46 #[test]
47 fn byte_offset_utf8() {
48 let line = "tablé";
50 assert_eq!(Position::new(0, 4).byte_offset(line), 4);
51 assert_eq!(Position::new(0, 5).byte_offset(line), 6);
52 }
53
54 #[test]
55 fn ord_is_row_major() {
56 assert!(Position::new(0, 5) < Position::new(1, 0));
57 assert!(Position::new(2, 0) > Position::new(1, 999));
58 assert!(Position::new(1, 3) < Position::new(1, 4));
59 }
60}