spade_codespan/
span.rs

1#[cfg(feature = "serialization")]
2use serde::{Deserialize, Serialize};
3use std::fmt;
4use std::ops::Range;
5
6use crate::{ByteIndex, RawIndex};
7
8#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
9#[cfg_attr(feature = "serialization", derive(Deserialize, Serialize))]
10pub struct Span {
11    start: ByteIndex,
12    end: ByteIndex,
13}
14
15impl Span {
16    /// Create a new span from a starting and ending span.
17    pub fn new(start: impl Into<ByteIndex>, end: impl Into<ByteIndex>) -> Span {
18        let start = start.into();
19        let end = end.into();
20
21        assert!(end >= start);
22
23        Span { start, end }
24    }
25
26    /// Gives an empty span at the start of a source.
27    pub const fn initial() -> Span {
28        Span {
29            start: ByteIndex(0),
30            end: ByteIndex(0),
31        }
32    }
33
34    /// Measure the span of a string.
35    ///
36    /// ```rust
37    /// use codespan::{ByteIndex, Span};
38    ///
39    /// let span = Span::from_str("hello");
40    ///
41    /// assert_eq!(span, Span::new(0, 5));
42    /// ```
43    pub fn from_str(s: &str) -> Span {
44        Span::new(0, s.len() as u32)
45    }
46
47    /// Combine two spans by taking the start of the earlier span
48    /// and the end of the later span.
49    ///
50    /// Note: this will work even if the two spans are disjoint.
51    /// If this doesn't make sense in your application, you should handle it yourself.
52    /// In that case, you can use `Span::disjoint` as a convenience function.
53    ///
54    /// ```rust
55    /// use codespan::Span;
56    ///
57    /// let span1 = Span::new(0, 4);
58    /// let span2 = Span::new(10, 16);
59    ///
60    /// assert_eq!(Span::merge(span1, span2), Span::new(0, 16));
61    /// ```
62    pub fn merge(self, other: Span) -> Span {
63        use std::cmp::{max, min};
64
65        let start = min(self.start, other.start);
66        let end = max(self.end, other.end);
67        Span::new(start, end)
68    }
69
70    /// A helper function to tell whether two spans do not overlap.
71    ///
72    /// ```
73    /// use codespan::Span;
74    /// let span1 = Span::new(0, 4);
75    /// let span2 = Span::new(10, 16);
76    /// assert!(span1.disjoint(span2));
77    /// ```
78    pub fn disjoint(self, other: Span) -> bool {
79        let (first, last) = if self.end < other.end {
80            (self, other)
81        } else {
82            (other, self)
83        };
84        first.end <= last.start
85    }
86
87    /// Get the starting byte index.
88    ///
89    /// ```rust
90    /// use codespan::{ByteIndex, Span};
91    ///
92    /// let span = Span::new(0, 4);
93    ///
94    /// assert_eq!(span.start(), ByteIndex::from(0));
95    /// ```
96    pub fn start(self) -> ByteIndex {
97        self.start
98    }
99
100    /// Get the ending byte index.
101    ///
102    /// ```rust
103    /// use codespan::{ByteIndex, Span};
104    ///
105    /// let span = Span::new(0, 4);
106    ///
107    /// assert_eq!(span.end(), ByteIndex::from(4));
108    /// ```
109    pub fn end(self) -> ByteIndex {
110        self.end
111    }
112}
113
114impl Default for Span {
115    fn default() -> Span {
116        Span::initial()
117    }
118}
119
120impl fmt::Display for Span {
121    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
122        write!(
123            f,
124            "[{start}, {end})",
125            start = self.start(),
126            end = self.end(),
127        )
128    }
129}
130
131impl<I> From<Range<I>> for Span
132where
133    I: Into<ByteIndex>,
134{
135    fn from(range: Range<I>) -> Span {
136        Span::new(range.start, range.end)
137    }
138}
139
140impl From<Span> for Range<usize> {
141    fn from(span: Span) -> Range<usize> {
142        span.start.into()..span.end.into()
143    }
144}
145
146impl From<Span> for Range<RawIndex> {
147    fn from(span: Span) -> Range<RawIndex> {
148        span.start.0..span.end.0
149    }
150}
151
152#[cfg(test)]
153mod test {
154    #[test]
155    fn test_merge() {
156        use super::Span;
157
158        // overlap
159        let a = Span::from(1..5);
160        let b = Span::from(3..10);
161        assert_eq!(a.merge(b), Span::from(1..10));
162        assert_eq!(b.merge(a), Span::from(1..10));
163
164        // subset
165        let two_four = (2..4).into();
166        assert_eq!(a.merge(two_four), (1..5).into());
167        assert_eq!(two_four.merge(a), (1..5).into());
168
169        // disjoint
170        let ten_twenty = (10..20).into();
171        assert_eq!(a.merge(ten_twenty), (1..20).into());
172        assert_eq!(ten_twenty.merge(a), (1..20).into());
173
174        // identity
175        assert_eq!(a.merge(a), a);
176    }
177
178    #[test]
179    fn test_disjoint() {
180        use super::Span;
181
182        // overlap
183        let a = Span::from(1..5);
184        let b = Span::from(3..10);
185        assert!(!a.disjoint(b));
186        assert!(!b.disjoint(a));
187
188        // subset
189        let two_four = (2..4).into();
190        assert!(!a.disjoint(two_four));
191        assert!(!two_four.disjoint(a));
192
193        // disjoint
194        let ten_twenty = (10..20).into();
195        assert!(a.disjoint(ten_twenty));
196        assert!(ten_twenty.disjoint(a));
197
198        // identity
199        assert!(!a.disjoint(a));
200
201        // off by one (upper bound)
202        let c = Span::from(5..10);
203        assert!(a.disjoint(c));
204        assert!(c.disjoint(a));
205        // off by one (lower bound)
206        let d = Span::from(0..1);
207        assert!(a.disjoint(d));
208        assert!(d.disjoint(a));
209    }
210}