fe_common/
span.rs

1use crate::files::SourceFileId;
2use serde::{Deserialize, Serialize};
3use std::cmp;
4use std::fmt::{Debug, Formatter};
5use std::ops::{Add, AddAssign, Range};
6
7/// An exclusive span of byte offsets in a source file.
8#[derive(Serialize, Deserialize, PartialEq, Copy, Clone, Hash, Eq)]
9pub struct Span {
10    #[serde(skip_serializing)]
11    pub file_id: SourceFileId,
12    /// A byte offset specifying the inclusive start of a span.
13    pub start: usize,
14    /// A byte offset specifying the exclusive end of a span.
15    pub end: usize,
16}
17
18impl Span {
19    pub fn new(file_id: SourceFileId, start: usize, end: usize) -> Self {
20        Span {
21            file_id,
22            start: cmp::min(start, end),
23            end: cmp::max(start, end),
24        }
25    }
26
27    pub fn zero(file_id: SourceFileId) -> Self {
28        Span {
29            file_id,
30            start: 0,
31            end: 0,
32        }
33    }
34
35    pub fn dummy() -> Self {
36        Self {
37            file_id: SourceFileId::dummy_file(),
38            start: usize::MAX,
39            end: usize::MAX,
40        }
41    }
42
43    pub fn is_dummy(&self) -> bool {
44        self == &Self::dummy()
45    }
46
47    pub fn from_pair<S, E>(start_elem: S, end_elem: E) -> Self
48    where
49        S: Into<Span>,
50        E: Into<Span>,
51    {
52        let start_span: Span = start_elem.into();
53        let end_span: Span = end_elem.into();
54
55        let file_id = if start_span.file_id == end_span.file_id {
56            start_span.file_id
57        } else {
58            panic!("file ids are not equal")
59        };
60
61        Self {
62            file_id,
63            start: start_span.start,
64            end: end_span.end,
65        }
66    }
67}
68
69impl Debug for Span {
70    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
71        write!(f, "{:?}", Range::from(*self))
72    }
73}
74
75pub trait Spanned {
76    fn span(&self) -> Span;
77}
78
79impl Add for Span {
80    type Output = Self;
81
82    fn add(self, other: Self) -> Self {
83        use std::cmp::{max, min};
84
85        let file_id = if self.file_id == other.file_id {
86            self.file_id
87        } else {
88            panic!("file ids are not equal")
89        };
90
91        Self {
92            file_id,
93            start: min(self.start, other.start),
94            end: max(self.end, other.end),
95        }
96    }
97}
98
99impl Add<Option<Span>> for Span {
100    type Output = Self;
101
102    fn add(self, other: Option<Span>) -> Self {
103        if let Some(other) = other {
104            self + other
105        } else {
106            self
107        }
108    }
109}
110
111impl<'a, T> Add<Option<&'a T>> for Span
112where
113    Span: Add<&'a T, Output = Self>,
114{
115    type Output = Self;
116
117    fn add(self, other: Option<&'a T>) -> Self {
118        if let Some(other) = other {
119            self + other
120        } else {
121            self
122        }
123    }
124}
125
126impl<'a, T> Add<&'a T> for Span
127where
128    T: Spanned,
129{
130    type Output = Self;
131
132    fn add(self, other: &'a T) -> Self {
133        self + other.span()
134    }
135}
136
137impl<T> AddAssign<T> for Span
138where
139    Span: Add<T, Output = Self>,
140{
141    fn add_assign(&mut self, other: T) {
142        *self = *self + other
143    }
144}
145
146impl From<Span> for Range<usize> {
147    fn from(span: Span) -> Self {
148        Range {
149            start: span.start,
150            end: span.end,
151        }
152    }
153}