1use crate::{AssociatedWhitespaceRules, CommentStyle, Kind, KindSet, QuoteStyle, SourceOffset, Span, ToSpan, Token};
2
3#[derive(Debug, Default, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
5pub struct Cursor(SourceOffset, Token);
6
7impl Cursor {
8 pub const DUMMY_SITE_NUMBER_ZERO: Self = Self(SourceOffset::DUMMY, Token::NUMBER_ZERO);
9 pub const EMPTY: Self = Self(SourceOffset::ZERO, Token::EMPTY);
10
11 #[inline(always)]
12 pub const fn new(offset: SourceOffset, token: Token) -> Self {
13 Self(offset, token)
14 }
15
16 #[inline(always)]
17 pub const fn dummy(token: Token) -> Self {
18 Self(SourceOffset::DUMMY, token)
19 }
20
21 #[inline(always)]
22 pub const fn token(&self) -> Token {
23 self.1
24 }
25
26 #[inline(always)]
27 pub const fn offset(&self) -> SourceOffset {
28 self.0
29 }
30
31 #[inline(always)]
32 pub fn end_offset(&self) -> SourceOffset {
33 if self.offset() == SourceOffset::DUMMY {
34 return self.offset();
35 }
36 SourceOffset(self.offset().0 + self.len())
37 }
38
39 #[inline(always)]
40 pub const fn is_empty(&self) -> bool {
41 self.token().is_empty()
42 }
43
44 #[inline(always)]
45 pub const fn len(&self) -> u32 {
46 self.token().len()
47 }
48
49 #[inline(always)]
50 pub fn span(&self) -> Span {
51 Span::new(self.offset(), self.end_offset())
52 }
53
54 #[inline(always)]
55 pub fn str_slice<'a>(&self, str: &'a str) -> &'a str {
56 debug_assert!(
57 str.len() >= (self.end_offset().0 as usize),
58 "attempted to index out of bounds ({} < {})",
59 str.len(),
60 self.end_offset().0
61 );
62 &str[(self.offset().0 as usize)..(self.end_offset().0 as usize)]
63 }
64
65 pub fn with_quotes(&self, quote_style: QuoteStyle) -> Self {
66 if *self == quote_style || *self != Kind::String {
67 return *self;
68 }
69 Self::new(self.offset(), self.token().with_quotes(quote_style))
70 }
71
72 pub fn with_associated_whitespace(&self, rules: AssociatedWhitespaceRules) -> Self {
73 debug_assert!(self.1 == KindSet::DELIM_LIKE);
74 if self.1.associated_whitespace().to_bits() == rules.to_bits() {
75 return *self;
76 }
77 Self::new(self.offset(), self.token().with_associated_whitespace(rules))
78 }
79
80 pub fn with_sign_required(&self) -> Self {
85 debug_assert!(self.1 == Kind::Number);
86 Self::new(self.offset(), self.token().with_sign_required())
87 }
88
89 #[inline]
90 pub fn atom_bits(&self) -> u32 {
91 self.1.atom_bits()
92 }
93}
94
95impl From<Cursor> for Token {
96 fn from(cursor: Cursor) -> Self {
97 cursor.token()
98 }
99}
100
101impl PartialEq<Token> for Cursor {
102 fn eq(&self, other: &Token) -> bool {
103 self.1 == *other
104 }
105}
106
107impl ToSpan for Cursor {
108 fn to_span(&self) -> Span {
109 self.span()
110 }
111}
112
113impl From<Cursor> for Span {
114 fn from(cursor: Cursor) -> Self {
115 cursor.span()
116 }
117}
118
119impl PartialEq<Span> for Cursor {
120 fn eq(&self, other: &Span) -> bool {
121 self.span() == *other
122 }
123}
124
125impl From<Cursor> for Kind {
126 fn from(cursor: Cursor) -> Self {
127 cursor.token().kind()
128 }
129}
130
131impl PartialEq<Kind> for Cursor {
132 fn eq(&self, other: &Kind) -> bool {
133 self.1 == *other
134 }
135}
136
137impl PartialEq<CommentStyle> for Cursor {
138 fn eq(&self, other: &CommentStyle) -> bool {
139 self.1 == *other
140 }
141}
142
143impl From<Cursor> for KindSet {
144 fn from(cursor: Cursor) -> Self {
145 cursor.token().into()
146 }
147}
148
149impl PartialEq<KindSet> for Cursor {
150 fn eq(&self, other: &KindSet) -> bool {
151 self.1 == *other
152 }
153}
154
155impl From<Cursor> for QuoteStyle {
156 fn from(cursor: Cursor) -> Self {
157 cursor.token().into()
158 }
159}
160
161impl PartialEq<QuoteStyle> for Cursor {
162 fn eq(&self, other: &QuoteStyle) -> bool {
163 self.1 == *other
164 }
165}
166
167impl PartialEq<AssociatedWhitespaceRules> for Cursor {
168 fn eq(&self, other: &AssociatedWhitespaceRules) -> bool {
169 self.1 == *other
170 }
171}
172
173impl PartialEq<char> for Cursor {
174 fn eq(&self, other: &char) -> bool {
175 self.1 == *other
176 }
177}
178
179impl PartialEq<CommentStyle> for &Cursor {
180 fn eq(&self, other: &CommentStyle) -> bool {
181 self.1 == *other
182 }
183}
184
185impl PartialEq<Kind> for &Cursor {
186 fn eq(&self, other: &Kind) -> bool {
187 self.1 == *other
188 }
189}
190
191impl PartialEq<KindSet> for &Cursor {
192 fn eq(&self, other: &KindSet) -> bool {
193 self.1 == *other
194 }
195}
196
197impl PartialEq<QuoteStyle> for &Cursor {
198 fn eq(&self, other: &QuoteStyle) -> bool {
199 self.1 == *other
200 }
201}
202
203impl PartialEq<char> for &Cursor {
204 fn eq(&self, other: &char) -> bool {
205 self.1 == *other
206 }
207}
208
209#[cfg(feature = "miette")]
210impl From<Cursor> for miette::SourceSpan {
211 fn from(val: Cursor) -> Self {
212 let span = val.span();
213 span.into()
214 }
215}
216
217#[cfg(feature = "serde")]
218impl serde::ser::Serialize for Cursor {
219 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
220 where
221 S: serde::ser::Serializer,
222 {
223 use serde::ser::SerializeStruct;
224 if self.token() == Token::EMPTY {
225 return serializer.serialize_none();
226 }
227 let mut state = serializer.serialize_struct("Cursor", 3)?;
228 state.serialize_field("kind", self.token().kind().as_str())?;
229 state.serialize_field("offset", &self.offset())?;
230 state.serialize_field("len", &self.token().len())?;
231 state.end()
232 }
233}
234
235#[test]
236fn size_test() {
237 assert_eq!(::std::mem::size_of::<Cursor>(), 12);
238}