#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct Span {
pub start: usize,
pub end: usize,
}
impl Span {
#[inline]
pub fn new(start: usize, end: usize) -> Self {
debug_assert!(start <= end, "Span start ({start}) > end ({end})");
Self { start, end }
}
#[inline]
pub fn empty(offset: usize) -> Self {
Self {
start: offset,
end: offset,
}
}
#[inline]
pub fn len(&self) -> usize {
self.end - self.start
}
#[inline]
pub fn is_empty(&self) -> bool {
self.start == self.end
}
#[inline]
pub fn contains(&self, other: &Span) -> bool {
self.start <= other.start && other.end <= self.end
}
#[inline]
pub fn merge(&self, other: &Span) -> Span {
Span {
start: self.start.min(other.start),
end: self.end.max(other.end),
}
}
#[inline]
pub fn slice<'a>(&self, source: &'a str) -> &'a str {
&source[self.start..self.end]
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct NodeId(pub usize);
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn span_basics() {
let s = Span::new(2, 7);
assert_eq!(s.len(), 5);
assert!(!s.is_empty());
let e = Span::empty(3);
assert_eq!(e.len(), 0);
assert!(e.is_empty());
}
#[test]
fn span_contains() {
let outer = Span::new(0, 10);
let inner = Span::new(2, 5);
assert!(outer.contains(&inner));
assert!(!inner.contains(&outer));
}
#[test]
fn span_merge() {
let a = Span::new(0, 5);
let b = Span::new(3, 10);
let m = a.merge(&b);
assert_eq!(m, Span::new(0, 10));
}
#[test]
fn span_slice() {
let src = "hello world";
let s = Span::new(6, 11);
assert_eq!(s.slice(src), "world");
}
}