1#![cfg(not(feature = "no_position"))]
3
4#[cfg(feature = "no_std")]
5use std::prelude::v1::*;
6use std::{
7 fmt,
8 ops::{Add, AddAssign},
9};
10
11#[derive(Eq, PartialEq, Ord, PartialOrd, Hash, Clone, Copy)]
20pub struct Position {
21 line: u16,
23 pos: u16,
25}
26
27impl Position {
28 pub const NONE: Self = Self { line: 0, pos: 0 };
30 pub const START: Self = Self { line: 1, pos: 0 };
32
33 #[inline]
43 #[must_use]
44 pub const fn new(line: u16, position: u16) -> Self {
45 assert!(line != 0, "line cannot be zero");
46
47 let _pos = position;
48
49 Self { line, pos: _pos }
50 }
51 #[inline]
55 #[must_use]
56 pub const fn line(self) -> Option<usize> {
57 if self.is_none() {
58 None
59 } else {
60 Some(self.line as usize)
61 }
62 }
63 #[inline]
67 #[must_use]
68 pub const fn position(self) -> Option<usize> {
69 if self.is_none() || self.pos == 0 {
70 None
71 } else {
72 Some(self.pos as usize)
73 }
74 }
75 #[inline]
77 pub(crate) fn advance(&mut self) {
78 assert!(!self.is_none(), "cannot advance Position::NONE");
79 self.pos = self.pos.saturating_add(1);
80 }
81 #[inline]
87 pub(crate) fn rewind(&mut self) {
88 assert!(!self.is_none(), "cannot rewind Position::NONE");
89 assert!(self.pos > 0, "cannot rewind at position 0");
90 self.pos = self.pos.saturating_sub(1);
91 }
92 #[inline]
94 pub(crate) fn new_line(&mut self) {
95 assert!(!self.is_none(), "cannot advance Position::NONE");
96
97 self.line = self.line.saturating_add(1);
99 self.pos = 0;
100 }
101 #[inline]
105 #[must_use]
106 pub const fn is_beginning_of_line(self) -> bool {
107 self.pos == 0 && !self.is_none()
108 }
109 #[inline]
113 #[must_use]
114 pub const fn is_none(self) -> bool {
115 self.line == 0 && self.pos == 0
116 }
117 #[inline]
121 #[must_use]
122 pub const fn or_else(self, pos: Self) -> Self {
123 if self.is_none() {
124 pos
125 } else {
126 self
127 }
128 }
129}
130
131impl Default for Position {
132 #[inline(always)]
133 fn default() -> Self {
134 Self::START
135 }
136}
137
138impl fmt::Display for Position {
139 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
140 if self.is_none() {
141 write!(f, "none")
142 } else {
143 write!(f, "line {}, position {}", self.line, self.pos)
144 }
145 }
146}
147
148impl fmt::Debug for Position {
149 #[cold]
150 #[inline(never)]
151 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
152 if self.is_none() {
153 f.write_str("none")
154 } else if self.is_beginning_of_line() {
155 write!(f, "{}", self.line)
156 } else {
157 write!(f, "{}:{}", self.line, self.pos)
158 }
159 }
160}
161
162impl Add for Position {
163 type Output = Self;
164
165 fn add(self, rhs: Self) -> Self::Output {
166 if rhs.is_none() {
167 self
168 } else {
169 Self {
170 line: self.line + rhs.line - 1,
171 pos: if rhs.is_beginning_of_line() {
172 self.pos
173 } else {
174 self.pos + rhs.pos - 1
175 },
176 }
177 }
178 }
179}
180
181impl AddAssign for Position {
182 fn add_assign(&mut self, rhs: Self) {
183 *self = *self + rhs;
184 }
185}
186
187#[derive(Eq, PartialEq, Ord, PartialOrd, Hash, Clone, Copy)]
190pub struct Span {
191 start: Position,
193 end: Position,
195}
196
197impl Default for Span {
198 #[inline(always)]
199 fn default() -> Self {
200 Self::NONE
201 }
202}
203
204impl Span {
205 pub const NONE: Self = Self::new(Position::NONE, Position::NONE);
207
208 #[inline(always)]
210 #[must_use]
211 pub const fn new(start: Position, end: Position) -> Self {
212 Self { start, end }
213 }
214 #[inline(always)]
218 #[must_use]
219 pub const fn is_none(self) -> bool {
220 self.start.is_none() && self.end.is_none()
221 }
222 #[inline(always)]
226 #[must_use]
227 pub const fn start(self) -> Position {
228 self.start
229 }
230 #[inline(always)]
234 #[must_use]
235 pub const fn end(self) -> Position {
236 self.end
237 }
238}
239
240impl fmt::Display for Span {
241 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
242 let _f = f;
243
244 match (self.start(), self.end()) {
245 (Position::NONE, Position::NONE) => write!(_f, "{:?}", Position::NONE),
246 (Position::NONE, end) => write!(_f, "..{end:?}"),
247 (start, Position::NONE) => write!(_f, "{start:?}"),
248 (start, end) if start.line() != end.line() => {
249 write!(_f, "{start:?}-{end:?}")
250 }
251 (start, end) => write!(
252 _f,
253 "{}:{}-{}",
254 start.line().unwrap(),
255 start.position().unwrap_or(0),
256 end.position().unwrap_or(0)
257 ),
258 }
259 }
260}
261
262impl fmt::Debug for Span {
263 #[cold]
264 #[inline(never)]
265 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
266 fmt::Display::fmt(self, f)
267 }
268}