Skip to main content

php_ast/
span.rs

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