Skip to main content

css_parse/
arena_impls.rs

1use crate::{Cursor, CursorSink, Parse, Parser, Peek, SemanticEq, ToCursors};
2use allocator_api2::alloc::Allocator;
3use css_lexer::KindSet;
4use csskit_arena::Box;
5
6impl<'a, T: ToCursors, A: Allocator> ToCursors for Box<'a, T, A> {
7	fn to_cursors(&self, s: &mut impl CursorSink) {
8		(**self).to_cursors(s);
9	}
10}
11
12impl<'a, T: SemanticEq, A: Allocator> SemanticEq for Box<'a, T, A> {
13	fn semantic_eq(&self, other: &Self, source_text: &str) -> bool {
14		(**self).semantic_eq(other, source_text)
15	}
16}
17
18impl<'a, M: crate::NodeMetadata, T: crate::NodeWithMetadata<M>, A: Allocator> crate::NodeWithMetadata<M>
19	for Box<'a, T, A>
20{
21	fn self_metadata(&self) -> M {
22		(**self).self_metadata()
23	}
24
25	fn metadata(&self) -> M {
26		(**self).metadata()
27	}
28}
29
30impl<'a, T: Peek<'a>, A: Allocator> Peek<'a> for Box<'a, T, A> {
31	const PEEK_KINDSET: KindSet = T::PEEK_KINDSET;
32
33	#[inline(always)]
34	fn peek<I>(p: &Parser<'a, I>, c: Cursor) -> bool
35	where
36		I: Iterator<Item = Cursor> + Clone,
37	{
38		T::peek(p, c)
39	}
40}
41
42impl<'a, T: Parse<'a>> Parse<'a> for Box<'a, T> {
43	fn parse<I>(p: &mut Parser<'a, I>) -> crate::Result<Self>
44	where
45		I: Iterator<Item = Cursor> + Clone,
46	{
47		let value = T::parse(p)?;
48		Ok(Box::new_in(p.alloc(), value))
49	}
50}
51
52#[cfg(test)]
53mod test {
54	use crate::{Arena, ComponentValues, EmptyAtomSet, Parser};
55	use css_lexer::Lexer;
56	use std::panic::{AssertUnwindSafe, catch_unwind};
57
58	#[test]
59	fn parsing_beyond_default_arena_capacity_does_not_panic() {
60		let source = "a ".repeat(16_384);
61		let result = catch_unwind(AssertUnwindSafe(|| {
62			let arena = Arena::new();
63			let lexer = Lexer::new(&EmptyAtomSet::ATOMS, &source);
64			let mut parser = Parser::new(&arena, &source, lexer);
65			let _ = parser.parse_entirely::<ComponentValues>();
66		}));
67
68		assert!(result.is_ok(), "arena exhaustion must not abort parsing");
69	}
70}