css_parse/
cursor_write_sink.rs

1use crate::{Cursor, CursorSink, SourceCursor, SourceCursorSink, Token};
2use core::fmt::{Result, Write};
3
4/// This is a [CursorSink] that wraps a Writer (`impl fmt::Write`) and on each [CursorSink::append()] call, will write
5/// the contents of the cursor [Cursor] given into the given Writer - using the given `&'a str` as the original source.
6/// This is useful as way to turn Cursors into Strings or [u8]s (or files or whatever else implements [Write]).
7pub struct CursorWriteSink<'a, T: Write> {
8	source_text: &'a str,
9	writer: T,
10	last_token: Option<Token>,
11	err: Result,
12}
13
14impl<'a, T: Write> CursorWriteSink<'a, T> {
15	pub fn new(source_text: &'a str, writer: T) -> Self {
16		Self { source_text, writer, last_token: None, err: Ok(()) }
17	}
18
19	fn write(&mut self, c: Cursor, source: &'a str) -> Result {
20		self.err?;
21		if let Some(last) = self.last_token {
22			if last.needs_separator_for(c.token()) {
23				self.writer.write_char(' ')?;
24			}
25		}
26		self.last_token = Some(c.token());
27		c.write_str(source, &mut self.writer)?;
28		Ok(())
29	}
30}
31
32impl<'a, T: Write> CursorSink for CursorWriteSink<'a, T> {
33	fn append(&mut self, c: Cursor) {
34		self.err = self.write(c, self.source_text);
35	}
36}
37
38impl<'a, T: Write> SourceCursorSink<'a> for CursorWriteSink<'a, T> {
39	fn append(&mut self, c: SourceCursor<'a>) {
40		self.err = self.write(c.cursor(), c.source());
41	}
42}
43
44#[cfg(test)]
45mod test {
46	use super::*;
47	use crate::{ComponentValues, ToCursors, parse};
48	use bumpalo::Bump;
49
50	#[test]
51	fn test() {
52		let source_text = "foo{bar:baz();}";
53		let bump = Bump::default();
54		let mut str = String::new();
55		let mut stream = CursorWriteSink::new(source_text, &mut str);
56		parse!(in bump &source_text as ComponentValues).output.unwrap().to_cursors(&mut stream);
57		assert_eq!(str, "foo{bar:baz();}");
58	}
59}