css_parse/
cursor_interleave_sink.rs

1use crate::{Cursor, CursorSink, Kind};
2
3/// This is a [CursorSink] that wraps a Sink (`impl CursorSink`) and a slice of [Cursor]s to interleave. On each
4/// [CursorSink::append()] call, will append to the delegate sink, while also interleaving any of the Cursors from the
5/// slice of [Cursor]s, in the right places.
6///
7/// This is useful as way to interleave ancilliary cursors, for example trivia.
8pub struct CursorInterleaveSink<'a, S> {
9	sink: &'a mut S,
10	interleave: &'a [(bumpalo::collections::Vec<'a, Cursor>, Cursor)],
11	current_index: usize,
12	#[cfg(debug_assertions)]
13	seen_eof: bool,
14}
15
16impl<'a, S: CursorSink> CursorInterleaveSink<'a, S> {
17	pub fn new(sink: &'a mut S, interleave: &'a [(bumpalo::collections::Vec<'a, Cursor>, Cursor)]) -> Self {
18		Self {
19			sink,
20			interleave,
21			current_index: 0,
22			#[cfg(debug_assertions)]
23			seen_eof: false,
24		}
25	}
26}
27
28impl<'a, S: CursorSink> CursorSink for CursorInterleaveSink<'a, S> {
29	fn append(&mut self, c: Cursor) {
30		#[cfg(debug_assertions)]
31		{
32			debug_assert!(!self.seen_eof, "Received cursor after EOF: {:?}", c);
33			if c == Kind::Eof {
34				self.seen_eof = true;
35			}
36		}
37
38		// Check if this content cursor has associated trivia
39		while self.current_index < self.interleave.len() {
40			let (trivia, associated_cursor) = &self.interleave[self.current_index];
41			if *associated_cursor == c {
42				for cursor in trivia {
43					self.sink.append(*cursor);
44				}
45				self.current_index += 1;
46				break;
47			}
48			if associated_cursor.span().start() > c.span().start() {
49				break;
50			}
51			self.current_index += 1;
52		}
53
54		// If this is EOF, flush any remaining trivia before emitting EOF
55		if c == Kind::Eof {
56			while self.current_index < self.interleave.len() {
57				let (trivia, _) = &self.interleave[self.current_index];
58				for cursor in trivia {
59					self.sink.append(*cursor);
60				}
61				self.current_index += 1;
62			}
63		}
64
65		self.sink.append(c);
66	}
67}