Skip to main content

php_ast/
span.rs

1#[cfg(feature = "serde")]
2use serde::Serialize;
3
4/// Half-open byte range into the source.
5#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
6#[cfg_attr(feature = "serde", derive(Serialize))]
7pub struct Span {
8    /// Start byte offset.
9    pub start: u32,
10    /// End byte offset (exclusive).
11    pub end: u32,
12}
13
14impl Span {
15    /// Span with both offsets zero, used for synthesised nodes.
16    pub const DUMMY: Span = Span { start: 0, end: 0 };
17
18    /// Creates a span from start and end offsets.
19    pub fn new(start: u32, end: u32) -> Self {
20        Self { start, end }
21    }
22
23    /// Smallest span covering both spans.
24    pub fn merge(self, other: Span) -> Span {
25        Span {
26            start: self.start.min(other.start),
27            end: self.end.max(other.end),
28        }
29    }
30
31    /// Length in bytes.
32    pub fn len(self) -> u32 {
33        self.end - self.start
34    }
35
36    /// Whether the span covers no bytes.
37    pub fn is_empty(self) -> bool {
38        self.start == self.end
39    }
40}
41
42impl Default for Span {
43    fn default() -> Self {
44        Self::DUMMY
45    }
46}
47
48#[cfg(test)]
49mod tests {
50    use super::*;
51
52    #[test]
53    fn test_span_new() {
54        let span = Span::new(5, 10);
55        assert_eq!(span.start, 5);
56        assert_eq!(span.end, 10);
57    }
58
59    #[test]
60    fn test_span_merge() {
61        let a = Span::new(5, 10);
62        let b = Span::new(8, 15);
63        let merged = a.merge(b);
64        assert_eq!(merged.start, 5);
65        assert_eq!(merged.end, 15);
66    }
67
68    #[test]
69    fn test_span_merge_non_overlapping() {
70        let a = Span::new(0, 5);
71        let b = Span::new(10, 20);
72        let merged = a.merge(b);
73        assert_eq!(merged.start, 0);
74        assert_eq!(merged.end, 20);
75    }
76
77    #[test]
78    fn test_span_len() {
79        let span = Span::new(3, 10);
80        assert_eq!(span.len(), 7);
81    }
82
83    #[test]
84    fn test_span_is_empty() {
85        assert!(Span::new(5, 5).is_empty());
86        assert!(!Span::new(5, 6).is_empty());
87    }
88
89    #[test]
90    fn test_span_dummy() {
91        assert_eq!(Span::DUMMY, Span::new(0, 0));
92        assert!(Span::DUMMY.is_empty());
93    }
94
95    #[test]
96    fn test_span_default() {
97        assert_eq!(Span::default(), Span::DUMMY);
98    }
99}