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: u32,
9    pub end: u32,
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    pub fn len(&self) -> u32 {
22        self.end - self.start
23    }
24
25    /// Return self if not empty, or the other span if self is empty
26    #[must_use]
27    pub fn or(&self, other: Self) -> Self {
28        if self.is_empty() { other } else { *self }
29    }
30
31    /// Get the combined span that encompasses both spans.
32    /// The order does not matter.
33    #[must_use]
34    pub fn to(&self, other: Self) -> Self {
35        Self {
36            start: self.start.min(other.start),
37            end: self.end.max(other.end),
38        }
39    }
40
41    /// Take the current span, but skip the start until the `skip` span has been passed
42    #[must_use]
43    pub fn skip(&self, skip: Self) -> Self {
44        assert!(skip.end >= self.start);
45        assert!(skip.end <= self.end);
46        Self {
47            start: skip.end,
48            end: self.end,
49        }
50    }
51
52    /// Take the current span, but skip the first part and start from the given start span
53    #[must_use]
54    pub fn start_from(&self, start: Self) -> Self {
55        assert!(start.start >= self.start);
56        assert!(start.start <= self.end);
57        Self {
58            start: start.start,
59            end: self.end,
60        }
61    }
62
63    /// Discard the span and keep a zero-length span at the end value
64    #[must_use]
65    pub fn collapse_to_end(&self) -> Span {
66        Span {
67            start: self.end,
68            end: self.end,
69        }
70    }
71
72    /// Discard the span and keep a zero-length span at the start value
73    #[must_use]
74    pub fn collapse_to_start(&self) -> Span {
75        Span {
76            start: self.start,
77            end: self.start,
78        }
79    }
80
81    /// Returns true if the two spans have some overlap
82    pub fn overlaps(&self, other: Self) -> bool {
83        self.start < other.end && other.start < self.end
84    }
85
86    /// Returns true if a cursor at the given offset would select the span
87    ///
88    /// Note that one offset can select multiple non-overlapping (but touching) spans!
89    pub fn is_selected_at(&self, offset: u32) -> bool {
90        // Normally end is exclusive, but that's not how cursor positions work
91        // We want to be able to put the cursor right after a word and have it select the word
92        self.start <= offset && offset <= self.end
93    }
94
95    /// Take the start of self until the end of other (max is end of self)
96    pub fn until_end_of(&self, other: Self) -> Self {
97        Self {
98            start: self.start,
99            end: self.end.min(other.end),
100        }
101    }
102
103    /// Take the start of self until the start of other (max is end of self)
104    pub fn until_start_of(&self, other: Self) -> Self {
105        Self {
106            start: self.start,
107            end: self.end.min(other.start),
108        }
109    }
110}
111
112impl chumsky::span::Span for Span {
113    type Context = ();
114
115    type Offset = u32;
116
117    fn new(_context: Self::Context, range: Range<Self::Offset>) -> Self {
118        range.into()
119    }
120
121    fn context(&self) -> Self::Context {}
122
123    fn start(&self) -> Self::Offset {
124        self.start
125    }
126
127    fn end(&self) -> Self::Offset {
128        self.end
129    }
130}
131
132impl Display for Span {
133    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
134        write!(f, "{}..{}", self.start, self.end)
135    }
136}
137impl Debug for Span {
138    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
139        write!(f, "{}", self)
140    }
141}
142
143impl From<(u32, u32)> for Span {
144    fn from(value: (u32, u32)) -> Self {
145        Self {
146            start: value.0,
147            end: value.1,
148        }
149    }
150}
151
152impl From<Range<u32>> for Span {
153    fn from(value: Range<u32>) -> Self {
154        Self {
155            start: value.start,
156            end: value.end,
157        }
158    }
159}
160
161impl From<Range<usize>> for Span {
162    fn from(value: Range<usize>) -> Self {
163        Self {
164            start: value.start as u32,
165            end: value.end as u32,
166        }
167    }
168}
169
170impl From<Span> for Range<u32> {
171    fn from(value: Span) -> Self {
172        value.start..value.end
173    }
174}
175
176impl From<Span> for Range<usize> {
177    fn from(value: Span) -> Self {
178        value.start as usize..value.end as usize
179    }
180}
181
182impl<'a> From<&'a Span> for Range<u32> {
183    fn from(value: &'a Span) -> Self {
184        value.start..value.end
185    }
186}
187
188impl<'a> From<&'a Span> for Range<usize> {
189    fn from(value: &'a Span) -> Self {
190        value.start as usize..value.end as usize
191    }
192}
193
194#[derive(Clone, Eq, Copy)]
195pub struct Spanned<T> {
196    pub span: Span,
197    pub value: T,
198}
199
200impl<T: PartialEq> PartialEq for Spanned<T> {
201    fn eq(&self, other: &Self) -> bool {
202        // Only compare value. The span is transparent
203        self.value == other.value
204    }
205}
206
207impl<T: PartialEq> PartialEq<T> for Spanned<T> {
208    fn eq(&self, other: &T) -> bool {
209        // Only compare value. The span is transparent
210        &self.value == other
211    }
212}
213
214impl<T: std::hash::Hash> std::hash::Hash for Spanned<T> {
215    fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
216        self.value.hash(state);
217        // Only hash value. The span is transparent
218    }
219}
220
221impl<T: Default> Default for Spanned<T> {
222    fn default() -> Self {
223        Self {
224            span: (0, 0).into(),
225            value: Default::default(),
226        }
227    }
228}
229
230impl<T: Display> Display for Spanned<T> {
231    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
232        self.value.fmt(f)
233    }
234}
235
236impl<T: Debug> Debug for Spanned<T> {
237    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
238        self.value.fmt(f)
239    }
240}
241
242impl<T> std::ops::Deref for Spanned<T> {
243    type Target = T;
244
245    fn deref(&self) -> &Self::Target {
246        &self.value
247    }
248}
249
250impl<T> std::ops::DerefMut for Spanned<T> {
251    fn deref_mut(&mut self) -> &mut Self::Target {
252        &mut self.value
253    }
254}
255
256impl<T> Spanned<T> {
257    pub fn new(span: Span, value: T) -> Self {
258        Self { span, value }
259    }
260}
261
262impl<T, S: Into<Span>> From<(T, S)> for Spanned<T> {
263    fn from((value, span): (T, S)) -> Self {
264        Self {
265            span: span.into(),
266            value,
267        }
268    }
269}
270
271impl<T: PartialOrd> PartialOrd<T> for Spanned<T> {
272    fn partial_cmp(&self, other: &T) -> Option<std::cmp::Ordering> {
273        self.value.partial_cmp(other)
274    }
275}
276
277pub trait SpanExt {
278    fn with_span(self, span: impl Into<Span>) -> Spanned<Self>
279    where
280        Self: Sized,
281    {
282        Spanned::new(span.into(), self)
283    }
284
285    /// Same as [`Self::with_span`], but can avoid name collisions
286    fn spanned(self, span: impl Into<Span>) -> Spanned<Self>
287    where
288        Self: Sized,
289    {
290        self.with_span(span)
291    }
292
293    fn with_dummy_span(self) -> Spanned<Self>
294    where
295        Self: Sized,
296    {
297        self.with_span((0, 0))
298    }
299
300    fn into_with_dummy_span<T>(self) -> Spanned<T>
301    where
302        Self: Into<T>,
303    {
304        self.into().with_dummy_span()
305    }
306}
307impl<T> SpanExt for T {}