Skip to main content

source_tools/
source_cursor.rs

1use crate::{Cursor, SourceToken, Span, ToSpan};
2
3/// A cursor paired with its source text.
4#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
5pub struct SourceCursor<'a, T> {
6	cursor: Cursor<T>,
7	source: &'a str,
8}
9
10impl<'a, T> SourceCursor<'a, T> {
11	/// Creates a source cursor without checking source length.
12	#[inline(always)]
13	pub const fn new(cursor: Cursor<T>, source: &'a str) -> Self {
14		Self { cursor, source }
15	}
16
17	/// Returns cursor by reference.
18	#[inline(always)]
19	pub const fn cursor_ref(&self) -> &Cursor<T> {
20		&self.cursor
21	}
22
23	/// Returns source text.
24	#[inline(always)]
25	pub const fn source(&self) -> &'a str {
26		self.source
27	}
28}
29
30impl<'a, T: Copy> SourceCursor<'a, T> {
31	/// Returns cursor.
32	#[inline(always)]
33	pub const fn cursor(&self) -> Cursor<T> {
34		self.cursor
35	}
36
37	/// Returns token.
38	#[inline(always)]
39	pub const fn token(&self) -> T {
40		self.cursor.token()
41	}
42}
43
44impl<'a, T: SourceToken> SourceCursor<'a, T> {
45	/// Creates a source cursor and checks source length in debug builds.
46	#[inline(always)]
47	pub fn from(cursor: Cursor<T>, source: &'a str) -> Self {
48		debug_assert_eq!(cursor.len() as usize, source.len(), "source length must match cursor length");
49		Self::new(cursor, source)
50	}
51
52	/// Returns token value with leading and trailing syntax removed.
53	pub fn value(&self) -> &'a str {
54		let leading = self.token().leading_len() as usize;
55		let trailing = self.token().trailing_len() as usize;
56		&self.source[leading..self.source.len() - trailing]
57	}
58}
59
60impl<T: SourceToken> ToSpan for SourceCursor<'_, T> {
61	fn to_span(&self) -> Span {
62		self.cursor.to_span()
63	}
64}
65
66#[cfg(test)]
67mod tests {
68	use super::*;
69	use crate::SourceOffset;
70
71	#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
72	struct Token(u32);
73
74	impl SourceToken for Token {
75		type Kind = ();
76		const EMPTY: Self = Token(0);
77
78		fn kind(self) -> Self::Kind {}
79
80		fn len(self) -> u32 {
81			self.0
82		}
83
84		fn kind_name(self) -> &'static str {
85			"test"
86		}
87	}
88
89	#[test]
90	fn binds_cursor_to_source() {
91		let cursor = Cursor::new(SourceOffset(2), Token(3));
92		let sourced = SourceCursor::from(cursor, "abc");
93		assert_eq!(sourced.cursor(), cursor);
94		assert_eq!(sourced.source(), "abc");
95		assert_eq!(sourced.to_span(), Span::new(SourceOffset(2), SourceOffset(5)));
96	}
97}