1use std::fmt::Debug;
2use std::ops::Range;
3
4pub type Pos = usize;
6
7#[derive(Default, Clone, Copy, PartialEq, Eq, Hash)]
13#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
14pub struct Span {
15 pub lo: Pos,
17 pub hi: Pos,
19}
20
21impl From<Range<Pos>> for Span {
22 #[inline]
23 fn from(range: Range<Pos>) -> Self {
24 Self {
25 lo: range.start,
26 hi: range.end,
27 }
28 }
29}
30
31impl From<(Pos, Pos)> for Span {
32 #[inline]
33 fn from((lo, hi): (Pos, Pos)) -> Self {
34 Self { lo, hi }
35 }
36}
37
38impl Span {
39 #[inline]
41 pub fn new(lo: Pos, hi: Pos) -> Self {
42 Self { lo, hi }
43 }
44
45 pub fn get<'s>(&self, input: &'s str) -> &'s str {
47 if self.hi <= self.lo {
48 return "";
49 }
50 let hi = self.hi.min(input.len());
51 &input[self.lo..hi]
52 }
53}
54
55impl Debug for Span {
56 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
57 if self.hi <= self.lo {
58 write!(f, "{}", self.lo)
59 } else {
60 write!(f, "{}..{}", self.lo, self.hi)
61 }
62 }
63}
64
65pub trait ToSpan {
73 fn lo(&self) -> Pos;
74 fn hi(&self) -> Pos;
75 fn span(&self) -> Span {
76 Span::new(self.lo(), self.hi())
77 }
78}
79pub use teleparse_macros::ToSpan;
80
81impl ToSpan for Span {
82 fn lo(&self) -> Pos {
83 self.lo
84 }
85 fn hi(&self) -> Pos {
86 self.hi
87 }
88 fn span(&self) -> Span {
89 *self
90 }
91}
92
93impl<T: ToSpan> ToSpan for &T {
94 fn lo(&self) -> Pos {
95 T::lo(self)
96 }
97 fn hi(&self) -> Pos {
98 T::hi(self)
99 }
100 fn span(&self) -> Span {
101 T::span(self)
102 }
103}
104
105macro_rules! derive_to_span_tuple {
106 ($last:tt, $($n:ident),*) => {
107 impl<$($n: ToSpan),*> ToSpan for ($($n,)*) {
108 #[inline]
109 fn lo(&self) -> Pos {
110 self.0.lo()
111 }
112 #[inline]
113 fn hi(&self) -> Pos {
114 self.$last.hi()
115 }
116 }
117 };
118}
119
120derive_to_span_tuple!(1, A, B);
121derive_to_span_tuple!(2, A, B, C);
122derive_to_span_tuple!(3, A, B, C, D);
123derive_to_span_tuple!(4, A, B, C, D, E);
124
125#[cfg(test)]
126mod tests {
127 use super::*;
128 #[test]
129 fn ref_to_span() {
130 let span = Span::new(1, 2);
131 let span_ref = &span;
132
133 assert_eq!(span_ref.span(), Span::new(1, 2));
134 }
135}