Skip to main content

device_driver_common/
span.rs

1use std::{
2    fmt::{Debug, Display},
3    ops::Range,
4};
5
6#[derive(Clone, Eq, PartialEq, Copy, Default, Hash)]
7pub struct Span {
8    pub start: usize,
9    pub end: usize,
10}
11
12impl Span {
13    pub const fn empty() -> Self {
14        Self { start: 0, end: 0 }
15    }
16
17    pub fn is_empty(&self) -> bool {
18        self.start == 0 && self.end == 0
19    }
20
21    /// Return self if not empty, or the other span if self is empty
22    #[must_use]
23    pub fn or(&self, other: Self) -> Self {
24        if self.is_empty() { other } else { *self }
25    }
26
27    /// Get the combined span that encompasses both spans.
28    /// The order does not matter.
29    #[must_use]
30    pub fn to(&self, other: Self) -> Self {
31        Self {
32            start: self.start.min(other.start),
33            end: self.end.max(other.end),
34        }
35    }
36
37    /// Take the current span, but skip the start until the `skip` span has been passed
38    #[must_use]
39    pub fn skip(&self, skip: Self) -> Self {
40        assert!(skip.end >= self.start);
41        assert!(skip.end <= self.end);
42        Self {
43            start: skip.end,
44            end: self.end,
45        }
46    }
47
48    /// Take the current span, but skip the first part and start from the given start span
49    #[must_use]
50    pub fn start_from(&self, start: Self) -> Self {
51        assert!(start.start >= self.start);
52        assert!(start.start <= self.end);
53        Self {
54            start: start.start,
55            end: self.end,
56        }
57    }
58
59    /// Discard the span and keep a zero-length span at the end value
60    #[must_use]
61    pub fn collapse_to_end(&self) -> Span {
62        Span {
63            start: self.end,
64            end: self.end,
65        }
66    }
67}
68
69impl chumsky::span::Span for Span {
70    type Context = ();
71
72    type Offset = usize;
73
74    fn new(_context: Self::Context, range: Range<Self::Offset>) -> Self {
75        range.into()
76    }
77
78    fn context(&self) -> Self::Context {}
79
80    fn start(&self) -> Self::Offset {
81        self.start
82    }
83
84    fn end(&self) -> Self::Offset {
85        self.end
86    }
87}
88
89impl Display for Span {
90    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
91        write!(f, "{}..{}", self.start, self.end)
92    }
93}
94impl Debug for Span {
95    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
96        write!(f, "{}", self)
97    }
98}
99
100impl From<(usize, usize)> for Span {
101    fn from(value: (usize, usize)) -> Self {
102        Self {
103            start: value.0,
104            end: value.1,
105        }
106    }
107}
108
109impl From<Range<usize>> for Span {
110    fn from(value: Range<usize>) -> Self {
111        Self {
112            start: value.start,
113            end: value.end,
114        }
115    }
116}
117
118impl From<Span> for Range<usize> {
119    fn from(value: Span) -> Self {
120        value.start..value.end
121    }
122}
123
124impl<'a> From<&'a Span> for Range<usize> {
125    fn from(value: &'a Span) -> Self {
126        value.start..value.end
127    }
128}
129
130#[derive(Debug, Clone, Eq, Copy)]
131pub struct Spanned<T> {
132    pub span: Span,
133    pub value: T,
134}
135
136impl<T: PartialEq> PartialEq for Spanned<T> {
137    fn eq(&self, other: &Self) -> bool {
138        // Only compare value. The span is transparent
139        self.value == other.value
140    }
141}
142
143impl<T: PartialEq> PartialEq<T> for Spanned<T> {
144    fn eq(&self, other: &T) -> bool {
145        // Only compare value. The span is transparent
146        &self.value == other
147    }
148}
149
150impl<T: std::hash::Hash> std::hash::Hash for Spanned<T> {
151    fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
152        self.value.hash(state);
153        // Only hash value. The span is transparent
154    }
155}
156
157impl<T: Default> Default for Spanned<T> {
158    fn default() -> Self {
159        Self {
160            span: (0, 0).into(),
161            value: Default::default(),
162        }
163    }
164}
165
166impl<T: Display> Display for Spanned<T> {
167    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
168        self.value.fmt(f)
169    }
170}
171
172impl<T> std::ops::Deref for Spanned<T> {
173    type Target = T;
174
175    fn deref(&self) -> &Self::Target {
176        &self.value
177    }
178}
179
180impl<T> std::ops::DerefMut for Spanned<T> {
181    fn deref_mut(&mut self) -> &mut Self::Target {
182        &mut self.value
183    }
184}
185
186impl<T> Spanned<T> {
187    pub fn new(span: Span, value: T) -> Self {
188        Self { span, value }
189    }
190}
191
192impl<T, S: Into<Span>> From<(T, S)> for Spanned<T> {
193    fn from((value, span): (T, S)) -> Self {
194        Self {
195            span: span.into(),
196            value,
197        }
198    }
199}
200
201impl<T: PartialOrd> PartialOrd<T> for Spanned<T> {
202    fn partial_cmp(&self, other: &T) -> Option<std::cmp::Ordering> {
203        self.value.partial_cmp(other)
204    }
205}
206
207pub trait SpanExt {
208    fn with_span(self, span: impl Into<Span>) -> Spanned<Self>
209    where
210        Self: Sized,
211    {
212        Spanned::new(span.into(), self)
213    }
214
215    /// Same as [`Self::with_span`], but can avoid name collisions
216    fn spanned(self, span: impl Into<Span>) -> Spanned<Self>
217    where
218        Self: Sized,
219    {
220        self.with_span(span)
221    }
222
223    fn with_dummy_span(self) -> Spanned<Self>
224    where
225        Self: Sized,
226    {
227        self.with_span((0, 0))
228    }
229
230    fn into_with_dummy_span<T>(self) -> Spanned<T>
231    where
232        Self: Into<T>,
233    {
234        self.into().with_dummy_span()
235    }
236}
237impl<T> SpanExt for T {}