1use std::fmt;
4
5#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
7pub struct Position {
8 pub line: usize,
10 pub column: usize,
12 pub index: usize,
14}
15
16impl Position {
17 pub const fn new() -> Self {
19 Self {
20 line: 1,
21 column: 1,
22 index: 0,
23 }
24 }
25
26 pub const fn at(line: usize, column: usize, index: usize) -> Self {
28 Self {
29 line,
30 column,
31 index,
32 }
33 }
34
35 pub const fn start() -> Self {
37 Self::new()
38 }
39
40 pub const fn advance(self, ch: char) -> Self {
42 if ch == '\n' {
43 Self::at(self.line + 1, 1, self.index + ch.len_utf8())
44 } else {
45 Self::at(self.line, self.column + 1, self.index + ch.len_utf8())
46 }
47 }
48
49 pub fn advance_str(mut self, s: &str) -> Self {
51 for ch in s.chars() {
52 self = self.advance(ch);
53 }
54 self
55 }
56
57 pub const fn advance_by(mut self, count: usize, is_newline: bool) -> Self {
59 if is_newline {
60 self.line += count;
61 self.column = 1;
62 } else {
63 self.column += count;
64 }
65 self.index += count;
66 self
67 }
68}
69
70impl fmt::Display for Position {
71 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
72 write!(f, "line {}, column {}", self.line, self.column)
73 }
74}
75
76impl Default for Position {
77 fn default() -> Self {
78 Self::start()
79 }
80}
81
82#[cfg(feature = "serde")]
83impl serde::Serialize for Position {
84 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
85 where
86 S: serde::Serializer,
87 {
88 use serde::ser::SerializeStruct;
89 let mut state = serializer.serialize_struct("Position", 3)?;
90 state.serialize_field("line", &self.line)?;
91 state.serialize_field("column", &self.column)?;
92 state.serialize_field("index", &self.index)?;
93 state.end()
94 }
95}
96
97#[cfg(feature = "serde")]
98impl<'de> serde::Deserialize<'de> for Position {
99 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
100 where
101 D: serde::Deserializer<'de>,
102 {
103 use serde::de::{self, MapAccess, Visitor};
104 use std::fmt;
105
106 #[derive(serde::Deserialize)]
107 #[serde(field_identifier, rename_all = "lowercase")]
108 enum Field {
109 Line,
110 Column,
111 Index,
112 }
113
114 struct PositionVisitor;
115
116 impl<'de> Visitor<'de> for PositionVisitor {
117 type Value = Position;
118
119 fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
120 formatter.write_str("struct Position")
121 }
122
123 fn visit_map<V>(self, mut map: V) -> Result<Position, V::Error>
124 where
125 V: MapAccess<'de>,
126 {
127 let mut line = None;
128 let mut column = None;
129 let mut index = None;
130 while let Some(key) = map.next_key()? {
131 match key {
132 Field::Line => {
133 if line.is_some() {
134 return Err(de::Error::duplicate_field("line"));
135 }
136 line = Some(map.next_value()?);
137 }
138 Field::Column => {
139 if column.is_some() {
140 return Err(de::Error::duplicate_field("column"));
141 }
142 column = Some(map.next_value()?);
143 }
144 Field::Index => {
145 if index.is_some() {
146 return Err(de::Error::duplicate_field("index"));
147 }
148 index = Some(map.next_value()?);
149 }
150 }
151 }
152 let line = line.ok_or_else(|| de::Error::missing_field("line"))?;
153 let column = column.ok_or_else(|| de::Error::missing_field("column"))?;
154 let index = index.ok_or_else(|| de::Error::missing_field("index"))?;
155 Ok(Position::at(line, column, index))
156 }
157 }
158
159 const FIELDS: &[&str] = &["line", "column", "index"];
160 deserializer.deserialize_struct("Position", FIELDS, PositionVisitor)
161 }
162}
163
164#[cfg(test)]
165mod tests {
166 use super::*;
167
168 #[test]
169 fn test_position_creation() {
170 let pos = Position::at(5, 10, 42);
171 assert_eq!(pos.line, 5);
172 assert_eq!(pos.column, 10);
173 assert_eq!(pos.index, 42);
174 }
175
176 #[test]
177 fn test_position_start() {
178 let pos = Position::start();
179 assert_eq!(pos.line, 1);
180 assert_eq!(pos.column, 1);
181 assert_eq!(pos.index, 0);
182 }
183
184 #[test]
185 fn test_position_advance() {
186 let pos = Position::start();
187
188 let pos1 = pos.advance('a');
189 assert_eq!(pos1.line, 1);
190 assert_eq!(pos1.column, 2);
191 assert_eq!(pos1.index, 1);
192
193 let pos2 = pos1.advance('\n');
194 assert_eq!(pos2.line, 2);
195 assert_eq!(pos2.column, 1);
196 assert_eq!(pos2.index, 2);
197 }
198
199 #[test]
200 fn test_position_advance_str() {
201 let pos = Position::start();
202 let pos1 = pos.advance_str("hello\nworld");
203 assert_eq!(pos1.line, 2);
204 assert_eq!(pos1.column, 6);
205 assert_eq!(pos1.index, 11);
206 }
207
208 #[test]
209 fn test_position_display() {
210 let pos = Position::at(42, 13, 1000);
211 assert_eq!(format!("{}", pos), "line 42, column 13");
212 }
213
214 #[test]
215 fn test_position_ordering() {
216 let pos1 = Position::at(1, 5, 10);
217 let pos2 = Position::at(2, 3, 20);
218 let pos3 = Position::at(1, 6, 11);
219
220 assert!(pos1 < pos2);
221 assert!(pos1 < pos3);
222 assert!(pos3 < pos2);
223 }
224
225 }