use std::{fmt, ops::Deref};
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct Span {
start: usize,
end: usize,
}
impl Span {
pub fn new(range: std::ops::Range<usize>) -> Self {
Self {
start: range.start,
end: range.end,
}
}
pub fn empty() -> Self {
Self::new(0..0)
}
pub fn start(&self) -> usize {
self.start
}
pub fn end(&self) -> usize {
self.end
}
pub fn len(&self) -> usize {
if self.end >= self.start {
self.end - self.start
} else {
panic!("Invalid span: end offset is less than start offset");
}
}
pub fn is_empty(&self) -> bool {
self.start == self.end
}
pub fn union(&self, other: Span) -> Span {
if self.is_empty() {
return other;
}
if other.is_empty() {
return *self;
}
Self {
start: self.start.min(other.start),
end: self.end.max(other.end),
}
}
pub fn shift(self, base: usize) -> Span {
Self {
start: self.start + base,
end: self.end + base,
}
}
}
impl Default for Span {
fn default() -> Self {
Self::empty()
}
}
impl From<std::ops::Range<usize>> for Span {
fn from(range: std::ops::Range<usize>) -> Self {
Self::new(range)
}
}
#[derive(Debug, Default, Clone, Eq)]
pub struct Spanned<T> {
value: T,
span: Span,
}
impl<T> Spanned<T> {
pub fn new(value: T, span: Span) -> Self {
Self { value, span }
}
pub fn span(&self) -> Span {
self.span
}
pub fn map<F, U>(&self, f: F) -> Spanned<U>
where
F: FnOnce(&T) -> U,
{
Spanned {
value: f(&self.value),
span: self.span,
}
}
pub fn inner(&self) -> &T {
&self.value
}
#[allow(dead_code)]
pub fn into_inner(self) -> T {
self.value
}
}
impl<T> Deref for Spanned<T> {
type Target = T;
fn deref(&self) -> &Self::Target {
&self.value
}
}
impl<T: fmt::Display> fmt::Display for Spanned<T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
self.value.fmt(f)
}
}
impl<T: PartialEq> PartialEq for Spanned<T> {
fn eq(&self, other: &Self) -> bool {
self.value.eq(&other.value)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_span_basic_functionality() {
let span = Span::new(5..10);
assert_eq!(span.start(), 5);
assert_eq!(span.end(), 10);
assert_eq!(span.len(), 5);
assert!(!span.is_empty());
}
#[test]
fn test_span_empty() {
let span = Span::new(5..5);
assert_eq!(span.len(), 0);
assert!(span.is_empty());
}
#[test]
fn test_span_union() {
let span1 = Span::new(5..10);
let span2 = Span::new(15..20);
let union = span1.union(span2);
assert_eq!(union.start(), 5);
assert_eq!(union.end(), 20);
}
#[test]
fn test_span_shift() {
let span = Span::new(5..10);
let shifted = span.shift(100);
assert_eq!(shifted.start(), 105);
assert_eq!(shifted.end(), 110);
assert_eq!(shifted.len(), 5);
}
#[test]
fn test_span_shift_zero_is_identity() {
let span = Span::new(5..10);
assert_eq!(span.shift(0), span);
}
#[test]
fn test_spanned_with_new_span() {
let span = Span::new(5..10);
let spanned = Spanned::new("test", span);
assert_eq!(spanned.span().start(), 5);
assert_eq!(spanned.span().len(), 5);
assert_eq!(*spanned.inner(), "test");
}
#[test]
fn test_span_empty_constructor() {
let span = Span::empty();
assert_eq!(span.start(), 0);
assert_eq!(span.end(), 0);
assert_eq!(span.len(), 0);
assert!(span.is_empty());
}
#[test]
fn test_span_default_is_empty() {
let span = Span::default();
assert_eq!(span, Span::empty());
assert!(span.is_empty());
}
#[test]
fn test_span_union_with_left_empty() {
let empty = Span::empty();
let span = Span::new(5..10);
let union = empty.union(span);
assert_eq!(union, span);
}
#[test]
fn test_span_union_with_right_empty() {
let span = Span::new(5..10);
let empty = Span::empty();
let union = span.union(empty);
assert_eq!(union, span);
}
#[test]
fn test_span_union_both_empty() {
let union = Span::empty().union(Span::empty());
assert!(union.is_empty());
}
#[test]
fn test_spanned_eq_ignores_span() {
let a = Spanned::new(42, Span::new(0..5));
let b = Spanned::new(42, Span::new(10..20));
assert_eq!(a, b);
}
#[test]
fn test_spanned_ne_different_values() {
let a = Spanned::new(1, Span::new(0..5));
let b = Spanned::new(2, Span::new(0..5));
assert_ne!(a, b);
}
#[test]
fn test_spanned_map() {
let spanned = Spanned::new(5, Span::new(0..10));
let mapped = spanned.map(|v| v * 2);
assert_eq!(*mapped.inner(), 10);
assert_eq!(mapped.span(), spanned.span());
}
#[test]
fn test_spanned_into_inner() {
let spanned = Spanned::new(String::from("hello"), Span::new(0..5));
let value = spanned.into_inner();
assert_eq!(value, "hello");
}
#[test]
fn test_spanned_deref() {
let spanned = Spanned::new(String::from("hello"), Span::new(0..5));
assert_eq!(spanned.len(), 5);
assert!(spanned.starts_with("he"));
}
#[test]
fn test_spanned_display() {
let spanned = Spanned::new(42, Span::new(0..5));
assert_eq!(format!("{spanned}"), "42");
}
}