graphcal_compiler/syntax/
span.rs1#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
3pub struct Span {
4 offset: usize,
5 len: usize,
6}
7
8impl Span {
9 #[must_use]
10 pub const fn new(offset: usize, len: usize) -> Self {
11 Self { offset, len }
12 }
13
14 #[must_use]
16 pub const fn offset(self) -> usize {
17 self.offset
18 }
19
20 #[must_use]
22 pub const fn len(self) -> usize {
23 self.len
24 }
25
26 #[must_use]
28 pub const fn is_empty(self) -> bool {
29 self.len == 0
30 }
31
32 #[must_use]
34 pub fn merge(self, other: Self) -> Self {
35 let start = self.offset.min(other.offset);
36 let end = (self.offset + self.len).max(other.offset + other.len);
37 Self::new(start, end - start)
38 }
39}
40
41impl From<Span> for miette::SourceSpan {
42 fn from(s: Span) -> Self {
43 (s.offset, s.len).into()
44 }
45}
46
47#[derive(Debug, Clone, PartialEq, Eq, Hash)]
49pub struct Spanned<T> {
50 pub value: T,
51 pub span: Span,
52}
53
54impl<T> Spanned<T> {
55 pub const fn new(value: T, span: Span) -> Self {
57 Self { value, span }
58 }
59}
60
61impl<T> std::ops::Deref for Spanned<T> {
62 type Target = T;
63
64 fn deref(&self) -> &Self::Target {
65 &self.value
66 }
67}
68
69impl<T: std::fmt::Display> std::fmt::Display for Spanned<T> {
70 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
71 self.value.fmt(f)
72 }
73}
74
75#[cfg(test)]
76mod tests {
77 use super::*;
78
79 #[test]
80 fn span_merge() {
81 let a = Span::new(0, 5);
82 let b = Span::new(10, 3);
83 let merged = a.merge(b);
84 assert_eq!(merged.offset(), 0);
85 assert_eq!(merged.len(), 13);
86 }
87
88 #[test]
89 fn span_merge_overlapping() {
90 let a = Span::new(2, 5);
91 let b = Span::new(4, 6);
92 let merged = a.merge(b);
93 assert_eq!(merged.offset(), 2);
94 assert_eq!(merged.len(), 8);
95 }
96
97 #[test]
98 fn span_to_miette() {
99 let s = Span::new(10, 5);
100 let ms: miette::SourceSpan = s.into();
101 assert_eq!(ms.offset(), 10);
102 assert_eq!(ms.len(), 5);
103 }
104
105 #[test]
106 fn spanned_eq_considers_span() {
107 use crate::syntax::names::DeclName;
108
109 let a = Spanned::new(DeclName::new("x"), Span::new(0, 1));
110 let b = Spanned::new(DeclName::new("x"), Span::new(10, 11));
111 assert_ne!(a, b);
112 }
113
114 #[test]
115 fn spanned_ne_different_value() {
116 use crate::syntax::names::DeclName;
117
118 let a = Spanned::new(DeclName::new("x"), Span::new(0, 1));
119 let b = Spanned::new(DeclName::new("y"), Span::new(0, 1));
120 assert_ne!(a, b);
121 }
122
123 #[test]
124 fn spanned_hash_considers_span() {
125 use crate::syntax::names::DeclName;
126 use std::hash::{DefaultHasher, Hash, Hasher};
127
128 let a = Spanned::new(DeclName::new("x"), Span::new(0, 1));
129 let b = Spanned::new(DeclName::new("x"), Span::new(10, 11));
130 let mut ha = DefaultHasher::new();
131 a.hash(&mut ha);
132 let mut hb = DefaultHasher::new();
133 b.hash(&mut hb);
134 assert_ne!(ha.finish(), hb.finish());
135 }
136}