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