spade_codespan/
index.rs

1//! Wrapper types that specify positions in a source file
2
3#[cfg(feature = "serialization")]
4use serde::{Deserialize, Serialize};
5use std::fmt;
6use std::ops::{Add, AddAssign, Neg, Sub, SubAssign};
7
8/// The raw, untyped index. We use a 32-bit integer here for space efficiency,
9/// assuming we won't be working with sources larger than 4GB.
10pub type RawIndex = u32;
11
12/// The raw, untyped offset.
13pub type RawOffset = i64;
14
15/// A zero-indexed line offset into a source file
16#[derive(Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
17#[cfg_attr(feature = "serialization", derive(Deserialize, Serialize))]
18#[derive(Default)]
19pub struct LineIndex(pub RawIndex);
20
21impl LineIndex {
22    /// The 1-indexed line number. Useful for pretty printing source locations.
23    ///
24    /// ```rust
25    /// use codespan::{LineIndex, LineNumber};
26    ///
27    /// assert_eq!(format!("{}", LineIndex(0).number()), "1");
28    /// assert_eq!(format!("{}", LineIndex(3).number()), "4");
29    /// ```
30    pub const fn number(self) -> LineNumber {
31        LineNumber(self.0 + 1)
32    }
33
34    /// Convert the index into a `usize`, for use in array indexing
35    pub const fn to_usize(self) -> usize {
36        self.0 as usize
37    }
38}
39
40impl fmt::Debug for LineIndex {
41    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
42        write!(f, "LineIndex(")?;
43        self.0.fmt(f)?;
44        write!(f, ")")
45    }
46}
47
48impl fmt::Display for LineIndex {
49    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
50        self.0.fmt(f)
51    }
52}
53
54/// A 1-indexed line number. Useful for pretty printing source locations.
55#[derive(Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
56#[cfg_attr(feature = "serialization", derive(Deserialize, Serialize))]
57pub struct LineNumber(RawIndex);
58
59impl LineNumber {
60    /// Convert the number into a `usize`
61    pub const fn to_usize(self) -> usize {
62        self.0 as usize
63    }
64}
65
66impl fmt::Debug for LineNumber {
67    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
68        write!(f, "LineNumber(")?;
69        self.0.fmt(f)?;
70        write!(f, ")")
71    }
72}
73
74impl fmt::Display for LineNumber {
75    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
76        self.0.fmt(f)
77    }
78}
79
80/// A line offset in a source file
81#[derive(Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
82#[cfg_attr(feature = "serialization", derive(Deserialize, Serialize))]
83#[derive(Default)]
84pub struct LineOffset(pub RawOffset);
85
86impl fmt::Debug for LineOffset {
87    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
88        write!(f, "LineOffset(")?;
89        self.0.fmt(f)?;
90        write!(f, ")")
91    }
92}
93
94impl fmt::Display for LineOffset {
95    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
96        self.0.fmt(f)
97    }
98}
99
100/// A zero-indexed column offset into a source file
101#[derive(Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
102#[cfg_attr(feature = "serialization", derive(Deserialize, Serialize))]
103#[derive(Default)]
104pub struct ColumnIndex(pub RawIndex);
105
106impl ColumnIndex {
107    /// The 1-indexed column number. Useful for pretty printing source locations.
108    ///
109    /// ```rust
110    /// use codespan::{ColumnIndex, ColumnNumber};
111    ///
112    /// assert_eq!(format!("{}", ColumnIndex(0).number()), "1");
113    /// assert_eq!(format!("{}", ColumnIndex(3).number()), "4");
114    /// ```
115    pub const fn number(self) -> ColumnNumber {
116        ColumnNumber(self.0 + 1)
117    }
118
119    /// Convert the index into a `usize`, for use in array indexing
120    pub const fn to_usize(self) -> usize {
121        self.0 as usize
122    }
123}
124
125impl fmt::Debug for ColumnIndex {
126    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
127        write!(f, "ColumnIndex(")?;
128        self.0.fmt(f)?;
129        write!(f, ")")
130    }
131}
132
133impl fmt::Display for ColumnIndex {
134    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
135        self.0.fmt(f)
136    }
137}
138
139/// A 1-indexed column number. Useful for pretty printing source locations.
140#[derive(Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
141#[cfg_attr(feature = "serialization", derive(Deserialize, Serialize))]
142pub struct ColumnNumber(RawIndex);
143
144impl fmt::Debug for ColumnNumber {
145    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
146        write!(f, "ColumnNumber(")?;
147        self.0.fmt(f)?;
148        write!(f, ")")
149    }
150}
151
152impl fmt::Display for ColumnNumber {
153    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
154        self.0.fmt(f)
155    }
156}
157
158/// A column offset in a source file
159#[derive(Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
160#[cfg_attr(feature = "serialization", derive(Deserialize, Serialize))]
161#[derive(Default)]
162pub struct ColumnOffset(pub RawOffset);
163
164impl fmt::Debug for ColumnOffset {
165    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
166        write!(f, "ColumnOffset(")?;
167        self.0.fmt(f)?;
168        write!(f, ")")
169    }
170}
171
172impl fmt::Display for ColumnOffset {
173    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
174        self.0.fmt(f)
175    }
176}
177
178/// A byte position in a source file.
179#[derive(Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
180#[cfg_attr(feature = "serialization", derive(Deserialize, Serialize))]
181#[derive(Default)]
182pub struct ByteIndex(pub RawIndex);
183
184impl ByteIndex {
185    /// Convert the position into a `usize`, for use in array indexing
186    pub const fn to_usize(self) -> usize {
187        self.0 as usize
188    }
189}
190
191impl fmt::Debug for ByteIndex {
192    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
193        write!(f, "ByteIndex(")?;
194        self.0.fmt(f)?;
195        write!(f, ")")
196    }
197}
198
199impl fmt::Display for ByteIndex {
200    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
201        self.0.fmt(f)
202    }
203}
204
205/// A byte offset in a source file
206#[derive(Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
207#[cfg_attr(feature = "serialization", derive(Deserialize, Serialize))]
208pub struct ByteOffset(pub RawOffset);
209
210impl ByteOffset {
211    /// Create a byte offset from a UTF8-encoded character
212    ///
213    /// ```rust
214    /// use codespan::ByteOffset;
215    ///
216    /// assert_eq!(ByteOffset::from_char_len('A').to_usize(), 1);
217    /// assert_eq!(ByteOffset::from_char_len('ß').to_usize(), 2);
218    /// assert_eq!(ByteOffset::from_char_len('ℝ').to_usize(), 3);
219    /// assert_eq!(ByteOffset::from_char_len('💣').to_usize(), 4);
220    /// ```
221    pub fn from_char_len(ch: char) -> ByteOffset {
222        ByteOffset(ch.len_utf8() as RawOffset)
223    }
224
225    /// Create a byte offset from a UTF- encoded string
226    ///
227    /// ```rust
228    /// use codespan::ByteOffset;
229    ///
230    /// assert_eq!(ByteOffset::from_str_len("A").to_usize(), 1);
231    /// assert_eq!(ByteOffset::from_str_len("ß").to_usize(), 2);
232    /// assert_eq!(ByteOffset::from_str_len("ℝ").to_usize(), 3);
233    /// assert_eq!(ByteOffset::from_str_len("💣").to_usize(), 4);
234    /// ```
235    pub fn from_str_len(value: &str) -> ByteOffset {
236        ByteOffset(value.len() as RawOffset)
237    }
238
239    /// Convert the offset into a `usize`, for use in array indexing
240    pub const fn to_usize(self) -> usize {
241        self.0 as usize
242    }
243}
244
245impl Default for ByteOffset {
246    #[inline]
247    fn default() -> ByteOffset {
248        ByteOffset(0)
249    }
250}
251
252impl fmt::Debug for ByteOffset {
253    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
254        write!(f, "ByteOffset(")?;
255        self.0.fmt(f)?;
256        write!(f, ")")
257    }
258}
259
260impl fmt::Display for ByteOffset {
261    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
262        self.0.fmt(f)
263    }
264}
265
266/// A relative offset between two indices
267///
268/// These can be thought of as 1-dimensional vectors
269pub trait Offset: Copy + Ord
270where
271    Self: Neg<Output = Self>,
272    Self: Add<Self, Output = Self>,
273    Self: AddAssign<Self>,
274    Self: Sub<Self, Output = Self>,
275    Self: SubAssign<Self>,
276{
277    const ZERO: Self;
278}
279
280/// Index types
281///
282/// These can be thought of as 1-dimensional points
283pub trait Index: Copy + Ord
284where
285    Self: Add<<Self as Index>::Offset, Output = Self>,
286    Self: AddAssign<<Self as Index>::Offset>,
287    Self: Sub<<Self as Index>::Offset, Output = Self>,
288    Self: SubAssign<<Self as Index>::Offset>,
289    Self: Sub<Self, Output = <Self as Index>::Offset>,
290{
291    type Offset: Offset;
292}
293
294macro_rules! impl_index {
295    ($Index:ident, $Offset:ident) => {
296        impl From<RawOffset> for $Offset {
297            #[inline]
298            fn from(i: RawOffset) -> Self {
299                $Offset(i)
300            }
301        }
302
303        impl From<RawIndex> for $Index {
304            #[inline]
305            fn from(i: RawIndex) -> Self {
306                $Index(i)
307            }
308        }
309
310        impl From<$Index> for RawIndex {
311            #[inline]
312            fn from(index: $Index) -> RawIndex {
313                index.0
314            }
315        }
316
317        impl From<$Offset> for RawOffset {
318            #[inline]
319            fn from(offset: $Offset) -> RawOffset {
320                offset.0
321            }
322        }
323
324        impl From<$Index> for usize {
325            #[inline]
326            fn from(index: $Index) -> usize {
327                index.0 as usize
328            }
329        }
330
331        impl From<$Offset> for usize {
332            #[inline]
333            fn from(offset: $Offset) -> usize {
334                offset.0 as usize
335            }
336        }
337
338        impl Offset for $Offset {
339            const ZERO: $Offset = $Offset(0);
340        }
341
342        impl Index for $Index {
343            type Offset = $Offset;
344        }
345
346        impl Add<$Offset> for $Index {
347            type Output = $Index;
348
349            #[inline]
350            fn add(self, rhs: $Offset) -> $Index {
351                $Index((self.0 as RawOffset + rhs.0) as RawIndex)
352            }
353        }
354
355        impl AddAssign<$Offset> for $Index {
356            #[inline]
357            fn add_assign(&mut self, rhs: $Offset) {
358                *self = *self + rhs;
359            }
360        }
361
362        impl Neg for $Offset {
363            type Output = $Offset;
364
365            #[inline]
366            fn neg(self) -> $Offset {
367                $Offset(-self.0)
368            }
369        }
370
371        impl Add<$Offset> for $Offset {
372            type Output = $Offset;
373
374            #[inline]
375            fn add(self, rhs: $Offset) -> $Offset {
376                $Offset(self.0 + rhs.0)
377            }
378        }
379
380        impl AddAssign<$Offset> for $Offset {
381            #[inline]
382            fn add_assign(&mut self, rhs: $Offset) {
383                self.0 += rhs.0;
384            }
385        }
386
387        impl Sub<$Offset> for $Offset {
388            type Output = $Offset;
389
390            #[inline]
391            fn sub(self, rhs: $Offset) -> $Offset {
392                $Offset(self.0 - rhs.0)
393            }
394        }
395
396        impl SubAssign<$Offset> for $Offset {
397            #[inline]
398            fn sub_assign(&mut self, rhs: $Offset) {
399                self.0 -= rhs.0;
400            }
401        }
402
403        impl Sub for $Index {
404            type Output = $Offset;
405
406            #[inline]
407            fn sub(self, rhs: $Index) -> $Offset {
408                $Offset(self.0 as RawOffset - rhs.0 as RawOffset)
409            }
410        }
411
412        impl Sub<$Offset> for $Index {
413            type Output = $Index;
414
415            #[inline]
416            fn sub(self, rhs: $Offset) -> $Index {
417                $Index((self.0 as RawOffset - rhs.0 as RawOffset) as u32)
418            }
419        }
420
421        impl SubAssign<$Offset> for $Index {
422            #[inline]
423            fn sub_assign(&mut self, rhs: $Offset) {
424                self.0 = (self.0 as RawOffset - rhs.0) as RawIndex;
425            }
426        }
427    };
428}
429
430impl_index!(LineIndex, LineOffset);
431impl_index!(ColumnIndex, ColumnOffset);
432impl_index!(ByteIndex, ByteOffset);