1use std::ops::Range;
2
3#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)]
5pub struct SourceSpan {
6 pub start: usize,
7 pub end: usize,
8}
9
10impl SourceSpan {
11 #[must_use]
12 pub const fn new(start: usize, end: usize) -> Self {
13 Self { start, end }
14 }
15
16 #[must_use]
17 pub const fn is_empty(self) -> bool {
18 self.start >= self.end
19 }
20
21 #[must_use]
22 pub const fn range(self) -> Range<usize> {
23 self.start..self.end
24 }
25}
26
27impl From<Range<usize>> for SourceSpan {
28 fn from(range: Range<usize>) -> Self {
29 Self {
30 start: range.start,
31 end: range.end,
32 }
33 }
34}
35
36#[derive(Debug, Clone, PartialEq, Eq, Default)]
38pub struct SourceLoc {
39 pub span: SourceSpan,
40 pub note: Option<String>,
41}
42
43impl SourceLoc {
44 #[must_use]
45 pub fn new(span: impl Into<SourceSpan>) -> Self {
46 Self {
47 span: span.into(),
48 note: None,
49 }
50 }
51
52 #[must_use]
53 pub fn with_note(mut self, note: impl Into<String>) -> Self {
54 self.note = Some(note.into());
55 self
56 }
57}
58
59impl std::fmt::Display for SourceLoc {
60 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
61 write!(f, "{}..{}", self.span.start, self.span.end)?;
62 if let Some(note) = &self.note {
63 write!(f, " ({note})")?;
64 }
65 Ok(())
66 }
67}