Skip to main content

oneyaml_core/
span.rs

1//! Source spans.
2
3/// A UTF-8 byte range `start..end` into the source text.
4///
5/// ```
6/// use oneyaml_core::Span;
7///
8/// let src = "key: value";
9/// let s = Span::new(5, 10);
10/// assert_eq!((&src[s.start..s.end], s.len()), ("value", 5));
11/// assert!(Span::empty(5).is_empty()); // an insertion point
12/// ```
13#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Default)]
14pub struct Span {
15    /// First byte of the range.
16    pub start: usize,
17    /// One past the last byte of the range.
18    pub end: usize,
19}
20
21impl Span {
22    /// Creates the span `start..end`.
23    #[must_use]
24    pub const fn new(start: usize, end: usize) -> Self {
25        Self { start, end }
26    }
27
28    /// A zero-width span at `at`.
29    #[must_use]
30    pub const fn empty(at: usize) -> Self {
31        Self { start: at, end: at }
32    }
33
34    /// Length in bytes; `0` for an inverted span.
35    #[must_use]
36    pub const fn len(&self) -> usize {
37        self.end.saturating_sub(self.start)
38    }
39
40    /// `true` when the span covers no bytes.
41    #[must_use]
42    pub const fn is_empty(&self) -> bool {
43        self.len() == 0
44    }
45}
46
47#[cfg(test)]
48mod tests {
49    use super::*;
50
51    #[test]
52    fn len_and_empty() {
53        assert_eq!(Span::new(2, 5).len(), 3);
54        assert!(Span::empty(4).is_empty());
55        assert_eq!(Span::empty(4), Span::new(4, 4));
56        assert_eq!(Span::new(5, 2).len(), 0);
57        assert!(!Span::new(0, 1).is_empty());
58    }
59}