rune/ast/
span.rs

1use core::cmp;
2use core::fmt;
3use core::ops;
4
5#[cfg(feature = "musli")]
6use musli::{Decode, Encode};
7#[cfg(feature = "serde")]
8use serde::{Deserialize, Serialize};
9
10use crate::ast::prelude::*;
11
12/// A span corresponding to a range in the source file being parsed.
13#[derive(Default, TryClone, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
14#[cfg_attr(feature = "musli", derive(Encode, Decode))]
15#[try_clone(copy)]
16pub struct Span {
17    /// The start of the span in bytes.
18    pub start: ByteIndex,
19    /// The end of the span in bytes.
20    pub end: ByteIndex,
21}
22
23impl Span {
24    /// Construct a new span.
25    ///
26    /// # Examples
27    ///
28    /// ```
29    /// use rune::ast::Span;
30    ///
31    /// let span = Span::new(42, 50);
32    /// assert!(span < Span::new(100, 101));
33    /// ```
34    #[inline]
35    pub fn new(
36        start: impl TryInto<ByteIndex, Error: fmt::Debug>,
37        end: impl TryInto<ByteIndex, Error: fmt::Debug>,
38    ) -> Self {
39        let start = start.try_into().expect("start out of bounds");
40        let end = end.try_into().expect("end out of bounds");
41
42        Self { start, end }
43    }
44
45    /// Get a span corresponding to a single point where both start and end are
46    /// the same byte offset.
47    ///
48    /// # Examples
49    ///
50    /// ```
51    /// use rune::ast::Span;
52    ///
53    /// assert_eq!(Span::point(42), Span::new(42, 42));
54    /// ```
55    #[inline]
56    pub fn point(pos: impl TryInto<ByteIndex, Error: fmt::Debug>) -> Self {
57        let pos = pos.try_into().expect("point out of bounds");
58
59        Self {
60            start: pos,
61            end: pos,
62        }
63    }
64
65    /// Constant function to build an empty span.
66    ///
67    /// # Examples
68    ///
69    /// ```
70    /// use rune::ast::Span;
71    ///
72    /// assert_eq!(Span::empty(), Span::new(0, 0));
73    /// ```
74    pub const fn empty() -> Self {
75        Self {
76            start: ByteIndex(0),
77            end: ByteIndex(0),
78        }
79    }
80
81    /// Get the head of the span.
82    pub fn head(self) -> Self {
83        Self {
84            start: self.start,
85            end: self.start,
86        }
87    }
88
89    /// Get the tail of the span.
90    pub fn tail(self) -> Self {
91        Self {
92            start: self.end,
93            end: self.end,
94        }
95    }
96
97    /// Join two spans creating the larger of the two spans.
98    ///
99    /// # Examples
100    ///
101    /// ```
102    /// use rune::ast::Span;
103    ///
104    /// let a = Span::new(10, 12);
105    /// let b = Span::new(20, 22);
106    ///
107    /// assert_eq!(a.join(b), Span::new(10, 22));
108    /// ```
109    pub fn join(self, other: Self) -> Self {
110        Self {
111            start: ByteIndex::min(self.start, other.start),
112            end: ByteIndex::max(self.end, other.end),
113        }
114    }
115
116    /// Narrow the span with the given amount.
117    ///
118    /// If the narrowing causes the span to become empty, the resulting span
119    /// will reflect the starting point of the narrowed span.
120    ///
121    /// # Examples
122    ///
123    /// ```
124    /// use rune::ast::Span;
125    ///
126    /// assert_eq!(Span::new(10, 12).narrow(4), Span::new(10, 10));
127    /// assert_eq!(Span::new(5, 15).narrow(2), Span::new(7, 13));
128    /// ```
129    pub fn narrow(self, amount: impl Into<ByteIndex>) -> Self {
130        let amount = amount.into();
131        let end = ByteIndex::max(self.start, self.end.saturating_sub(amount));
132        let start = ByteIndex::min(self.start.saturating_add(amount), end);
133        Self { start, end }
134    }
135
136    /// Get the span as a range of usize.
137    ///
138    /// # Panics
139    ///
140    /// Panics if the span contains ranges which cannot be faithfully
141    /// represented in an [usize].
142    pub fn range(self) -> ops::Range<usize> {
143        ops::Range {
144            start: usize::try_from(self.start.0).expect("start index out of bounds"),
145            end: usize::try_from(self.end.0).expect("end index out of bounds"),
146        }
147    }
148
149    /// Trim the start of the span by the given amount.
150    pub(crate) fn trim_start(self, amount: impl Into<ByteIndex>) -> Self {
151        let amount = amount.into();
152
153        Self {
154            start: ByteIndex::min(self.start.saturating_add(amount), self.end),
155            end: self.end,
156        }
157    }
158
159    /// Trim the end of the span by the given amount.
160    pub(crate) fn trim_end(self, amount: impl Into<ByteIndex>) -> Self {
161        let amount = amount.into();
162
163        Self {
164            start: self.start,
165            end: ByteIndex::max(self.end.saturating_sub(amount), self.start),
166        }
167    }
168}
169
170#[cfg(feature = "serde")]
171impl Serialize for Span {
172    #[inline]
173    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
174    where
175        S: serde::Serializer,
176    {
177        (self.start, self.end).serialize(serializer)
178    }
179}
180
181#[cfg(feature = "serde")]
182impl<'de> Deserialize<'de> for Span {
183    #[inline]
184    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
185    where
186        D: serde::Deserializer<'de>,
187    {
188        let (start, end) = <(ByteIndex, ByteIndex)>::deserialize(deserializer)?;
189        Ok(Self { start, end })
190    }
191}
192
193impl fmt::Display for Span {
194    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
195        write!(fmt, "{}:{}", self.start, self.end)
196    }
197}
198
199impl fmt::Debug for Span {
200    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
201        write!(f, "{}:{}", self.start, self.end)
202    }
203}
204
205/// A single index in a [Span], like the start or ending index.
206#[derive(Default, TryClone, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
207#[repr(transparent)]
208#[cfg_attr(feature = "serde", derive(Serialize, Deserialize), serde(transparent))]
209#[cfg_attr(feature = "musli", derive(Encode, Decode), musli(transparent))]
210#[try_clone(copy)]
211pub struct ByteIndex(#[doc(hidden)] pub u32);
212
213impl ByteIndex {
214    /// Convert a byte index into a usize.
215    ///
216    /// # Panics
217    ///
218    /// Panics if the byte index contains values which cannot be faithfully
219    /// represented in an [usize].
220    pub fn into_usize(self) -> usize {
221        usize::try_from(self.0).expect("byte index out of range")
222    }
223
224    fn min(a: Self, b: Self) -> Self {
225        Self(u32::min(a.0, b.0))
226    }
227
228    fn max(a: Self, b: Self) -> Self {
229        Self(u32::max(a.0, b.0))
230    }
231
232    pub(crate) fn saturating_sub(self, other: Self) -> Self {
233        Self(self.0.saturating_sub(other.0))
234    }
235
236    fn saturating_add(self, other: Self) -> Self {
237        Self(self.0.saturating_add(other.0))
238    }
239}
240
241impl From<u32> for ByteIndex {
242    fn from(value: u32) -> Self {
243        Self(value)
244    }
245}
246
247impl TryFrom<usize> for ByteIndex {
248    type Error = <usize as TryFrom<u32>>::Error;
249
250    fn try_from(value: usize) -> Result<Self, Self::Error> {
251        Ok(Self(u32::try_from(value)?))
252    }
253}
254
255impl TryFrom<i32> for ByteIndex {
256    type Error = <i32 as TryFrom<u32>>::Error;
257
258    fn try_from(value: i32) -> Result<Self, Self::Error> {
259        Ok(Self(u32::try_from(value)?))
260    }
261}
262
263impl fmt::Display for ByteIndex {
264    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
265        write!(f, "{}", self.0)
266    }
267}
268
269impl fmt::Debug for ByteIndex {
270    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
271        write!(f, "{}", self.0)
272    }
273}
274
275impl cmp::PartialEq<usize> for ByteIndex {
276    fn eq(&self, other: &usize) -> bool {
277        match u32::try_from(*other) {
278            Ok(other) => self.0 == other,
279            Err(..) => false,
280        }
281    }
282}
283
284impl cmp::PartialEq<u32> for ByteIndex {
285    fn eq(&self, other: &u32) -> bool {
286        self.0 == *other
287    }
288}