Skip to main content

css_parse/
arena_box.rs

1use crate::{Arena, Cursor, CursorSink, Parse, Parser, Peek, SemanticEq, ToCursors};
2use allocator_api2::alloc::{Allocator, Layout};
3use css_lexer::{KindSet, Span, ToSpan};
4use std::{
5	fmt,
6	hash::{Hash, Hasher},
7	marker::PhantomData,
8	ops::{Deref, DerefMut},
9	ptr::NonNull,
10};
11
12/// An arena-allocated box that retains a reference to its allocator, enabling [`Clone`] support.
13///
14/// Unlike [`bumpalo::boxed::Box`], which only stores a mutable reference to the allocated value (and thus cannot
15/// implement [`Clone`] without the allocator), `Box` stores both the allocator reference and the value pointer.
16/// This allows it to allocate a new copy during [`Clone::clone`].
17///
18/// This type is intended for recursive AST nodes (e.g. `color-mix()` containing nested `<color>` values) where
19/// indirection is required to break the cycle, but the allocation should still live in the parsing arena.
20#[repr(C)]
21pub struct Box<'a, T, A: Allocator = &'a Arena> {
22	ptr: NonNull<T>,
23	alloc: A,
24	marker: PhantomData<&'a mut T>,
25}
26
27impl<'a, T, A: Allocator> Box<'a, T, A> {
28	/// Allocate `value` in the given `alloc`.
29	#[inline]
30	pub fn new_in(alloc: A, value: T) -> Self {
31		let ptr = alloc.allocate(Layout::new::<T>()).expect("arena exhausted").cast::<T>();
32		unsafe { ptr.as_ptr().write(value) };
33		Self { ptr, alloc, marker: PhantomData }
34	}
35}
36
37impl<'a, T, A: Allocator> Deref for Box<'a, T, A> {
38	type Target = T;
39
40	#[inline]
41	fn deref(&self) -> &T {
42		unsafe { self.ptr.as_ref() }
43	}
44}
45
46impl<'a, T, A: Allocator> DerefMut for Box<'a, T, A> {
47	#[inline]
48	fn deref_mut(&mut self) -> &mut T {
49		unsafe { self.ptr.as_mut() }
50	}
51}
52
53impl<'a, T, A: Allocator> Drop for Box<'a, T, A> {
54	fn drop(&mut self) {
55		unsafe { self.ptr.as_ptr().drop_in_place() };
56	}
57}
58
59impl<'a, T: Clone, A: Allocator + Clone> Clone for Box<'a, T, A> {
60	fn clone(&self) -> Self {
61		Box::new_in(self.alloc.clone(), (**self).clone())
62	}
63}
64
65impl<'a, T: fmt::Debug, A: Allocator> fmt::Debug for Box<'a, T, A> {
66	fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
67		fmt::Debug::fmt(&**self, f)
68	}
69}
70
71impl<'a, T: fmt::Display, A: Allocator> fmt::Display for Box<'a, T, A> {
72	fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
73		fmt::Display::fmt(&**self, f)
74	}
75}
76
77impl<'a, T: PartialEq, A: Allocator> PartialEq for Box<'a, T, A> {
78	fn eq(&self, other: &Self) -> bool {
79		(**self).eq(&**other)
80	}
81}
82
83impl<'a, T: Eq, A: Allocator> Eq for Box<'a, T, A> {}
84
85impl<'a, T: PartialOrd, A: Allocator> PartialOrd for Box<'a, T, A> {
86	fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
87		(**self).partial_cmp(&**other)
88	}
89}
90
91impl<'a, T: Ord, A: Allocator> Ord for Box<'a, T, A> {
92	fn cmp(&self, other: &Self) -> std::cmp::Ordering {
93		(**self).cmp(&**other)
94	}
95}
96
97impl<'a, T: Hash, A: Allocator> Hash for Box<'a, T, A> {
98	fn hash<H: Hasher>(&self, state: &mut H) {
99		(**self).hash(state);
100	}
101}
102
103impl<'a, T: ToCursors, A: Allocator> ToCursors for Box<'a, T, A> {
104	fn to_cursors(&self, s: &mut impl CursorSink) {
105		(**self).to_cursors(s);
106	}
107}
108
109impl<'a, T: SemanticEq, A: Allocator> SemanticEq for Box<'a, T, A> {
110	fn semantic_eq(&self, other: &Self) -> bool {
111		(**self).semantic_eq(other)
112	}
113}
114
115impl<'a, T: ToSpan, A: Allocator> ToSpan for Box<'a, T, A> {
116	fn to_span(&self) -> Span {
117		(**self).to_span()
118	}
119}
120
121impl<'a, M: crate::NodeMetadata, T: crate::NodeWithMetadata<M>, A: Allocator> crate::NodeWithMetadata<M>
122	for Box<'a, T, A>
123{
124	fn self_metadata(&self) -> M {
125		(**self).self_metadata()
126	}
127
128	fn metadata(&self) -> M {
129		(**self).metadata()
130	}
131}
132
133impl<'a, T: Peek<'a>, A: Allocator> Peek<'a> for Box<'a, T, A> {
134	const PEEK_KINDSET: KindSet = T::PEEK_KINDSET;
135
136	#[inline(always)]
137	fn peek<I>(p: &Parser<'a, I>, c: Cursor) -> bool
138	where
139		I: Iterator<Item = Cursor> + Clone,
140	{
141		T::peek(p, c)
142	}
143}
144
145impl<'a, T: Parse<'a>> Parse<'a> for Box<'a, T> {
146	fn parse<I>(p: &mut Parser<'a, I>) -> crate::Result<Self>
147	where
148		I: Iterator<Item = Cursor> + Clone,
149	{
150		let value = T::parse(p)?;
151		Ok(Box::new_in(p.alloc(), value))
152	}
153}
154
155#[cfg(feature = "serde")]
156impl<'a, T: serde::Serialize, A: Allocator> serde::Serialize for Box<'a, T, A> {
157	fn serialize<S: serde::Serializer>(&self, serializer: S) -> std::result::Result<S::Ok, S::Error> {
158		(**self).serialize(serializer)
159	}
160}