1#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
5pub struct BytePos(pub u32);
6
7impl BytePos {
8 pub const fn new(offset: u32) -> Self {
9 Self(offset)
10 }
11
12 pub const fn as_usize(self) -> usize {
13 self.0 as usize
14 }
15}
16
17#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)]
19pub struct Span {
20 pub start: BytePos,
21 pub end: BytePos,
22}
23
24impl Span {
25 pub const fn new(start: BytePos, end: BytePos) -> Self {
26 Self { start, end }
27 }
28
29 pub fn from_offsets(start: usize, end: usize) -> Self {
30 Self {
31 start: BytePos(start as u32),
32 end: BytePos(end as u32),
33 }
34 }
35
36 pub const fn len(self) -> u32 {
37 self.end.0.saturating_sub(self.start.0)
38 }
39
40 pub fn merge(self, other: Span) -> Span {
41 Span {
42 start: self.start.min(other.start),
43 end: self.end.max(other.end),
44 }
45 }
46
47 pub fn line_col(self, source: &str) -> (usize, usize) {
49 let mut line = 1usize;
50 let mut col = 1usize;
51 for (i, ch) in source.char_indices() {
52 if i >= self.start.as_usize() {
53 break;
54 }
55 if ch == '\n' {
56 line += 1;
57 col = 1;
58 } else {
59 col += 1;
60 }
61 }
62 (line, col)
63 }
64}