Skip to main content

reading_liner/
location.rs

1//! Location types
2//!
3//! [Offset] is byte based offset.
4//!
5//! Line-column locations are further divided as. [line_column::ZeroBased] and [line_column::OneBased].
6
7use std::ops;
8
9/// Zero-based offset of bytes, only BYTES
10#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
11pub struct Offset(pub usize);
12
13impl Offset {
14    pub fn new(raw: usize) -> Self {
15        Self(raw)
16    }
17
18    pub fn raw(&self) -> usize {
19        self.0
20    }
21
22    fn plus(self, that: Self) -> Self {
23        Self(self.raw() + that.raw())
24    }
25
26    fn minus(self, that: Self) -> Self {
27        Self(self.raw() - that.raw())
28    }
29}
30
31impl From<usize> for Offset {
32    fn from(value: usize) -> Self {
33        Offset(value)
34    }
35}
36
37impl From<Offset> for usize {
38    fn from(value: Offset) -> Self {
39        value.raw()
40    }
41}
42
43impl Default for Offset {
44    fn default() -> Self {
45        Self(0)
46    }
47}
48
49impl ops::Add for Offset {
50    type Output = Offset;
51
52    fn add(self, rhs: Offset) -> Self::Output {
53        self.plus(rhs)
54    }
55}
56
57impl ops::Add<usize> for Offset {
58    type Output = Offset;
59
60    fn add(self, rhs: usize) -> Self::Output {
61        self.plus(Offset(rhs))
62    }
63}
64
65impl ops::AddAssign for Offset {
66    fn add_assign(&mut self, rhs: Self) {
67        self.0 += rhs.raw();
68    }
69}
70
71impl ops::AddAssign<usize> for Offset {
72    fn add_assign(&mut self, rhs: usize) {
73        self.0 += rhs;
74    }
75}
76
77impl ops::Sub for Offset {
78    type Output = Offset;
79
80    fn sub(self, rhs: Self) -> Self::Output {
81        self.minus(rhs)
82    }
83}
84
85impl ops::Sub<usize> for Offset {
86    type Output = Offset;
87
88    fn sub(self, rhs: usize) -> Self::Output {
89        self.minus(rhs.into())
90    }
91}
92
93/// For convenience
94pub trait OffsetRangeExt {
95    fn to_usize(self) -> ops::Range<usize>;
96}
97
98impl OffsetRangeExt for ops::Range<Offset> {
99    fn to_usize(self) -> ops::Range<usize> {
100        self.start.raw()..self.end.raw()
101    }
102}
103
104pub mod line_column {
105    use std::num::NonZeroUsize;
106
107    /// Zero-based (line, column) location
108    #[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
109    pub struct ZeroBased {
110        pub line: usize,
111        pub column: usize,
112    }
113
114    impl ZeroBased {
115        pub fn new(line: usize, column: usize) -> Self {
116            Self { line, column }
117        }
118
119        pub fn raw(&self) -> (usize, usize) {
120            (self.line, self.column)
121        }
122
123        /// Get one-based line and column numbers
124        pub fn one_based(&self) -> OneBased {
125            unsafe {
126                OneBased {
127                    line: NonZeroUsize::new_unchecked(self.line + 1),
128                    column: NonZeroUsize::new_unchecked(self.column + 1),
129                }
130            }
131        }
132    }
133
134    impl From<(usize, usize)> for ZeroBased {
135        fn from((line, column): (usize, usize)) -> Self {
136            ZeroBased { line, column }
137        }
138    }
139
140    /// One-based (line, column) location
141    #[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
142    pub struct OneBased {
143        pub line: NonZeroUsize,
144        pub column: NonZeroUsize,
145    }
146
147    impl OneBased {
148        pub fn new(line: usize, column: usize) -> Option<Self> {
149            let line = NonZeroUsize::new(line)?;
150            let column = NonZeroUsize::new(column)?;
151            Some(Self { line, column })
152        }
153
154        pub fn raw(&self) -> (usize, usize) {
155            (self.line.get(), self.column.get())
156        }
157
158        /// Get zero-based line and column numbers
159        pub fn zero_based(&self) -> ZeroBased {
160            ZeroBased {
161                line: self.line.get() - 1,
162                column: self.column.get() - 1,
163            }
164        }
165    }
166
167    impl From<(NonZeroUsize, NonZeroUsize)> for OneBased {
168        fn from((line, column): (NonZeroUsize, NonZeroUsize)) -> Self {
169            OneBased { line, column }
170        }
171    }
172}