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}