Skip to main content

litedoc_core/
span.rs

1//! Source location tracking for AST nodes.
2//!
3//! Every AST node includes a `Span` indicating its position in the source text.
4//! This enables precise error reporting and source mapping.
5
6/// A byte range in the source text.
7///
8/// Spans use byte offsets (not character offsets) for efficiency.
9/// Both `start` and `end` are inclusive-exclusive: `[start, end)`.
10///
11/// # Example
12///
13/// ```rust
14/// use litedoc_core::span::Span;
15///
16/// let span = Span::new(0, 10);
17/// assert_eq!(span.len(), 10);
18/// ```
19#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
20pub struct Span {
21    /// Starting byte offset (inclusive).
22    pub start: u32,
23    /// Ending byte offset (exclusive).
24    pub end: u32,
25}
26
27impl Span {
28    /// Create a new span from byte offsets.
29    #[inline]
30    pub const fn new(start: u32, end: u32) -> Self {
31        Self { start, end }
32    }
33
34    /// Get the length of this span in bytes.
35    #[inline]
36    pub const fn len(&self) -> u32 {
37        self.end.saturating_sub(self.start)
38    }
39
40    /// Check if this span is empty.
41    #[inline]
42    pub const fn is_empty(&self) -> bool {
43        self.start >= self.end
44    }
45
46    /// Check if this span contains a byte offset.
47    #[inline]
48    pub const fn contains(&self, offset: u32) -> bool {
49        offset >= self.start && offset < self.end
50    }
51
52    /// Merge two spans into one covering both.
53    #[inline]
54    pub fn merge(self, other: Span) -> Span {
55        Span {
56            start: self.start.min(other.start),
57            end: self.end.max(other.end),
58        }
59    }
60}