math_core_renderer_internal/
arena.rs1use alloc::string::String;
2use core::fmt::Debug;
3
4use stable_arena::DroplessArena;
5
6use crate::{
7 ast::{AHref, MultiscriptPair, Node},
8 length::LengthSet,
9 super_char::SuperChar,
10 table::{ArraySpec, ColumnSpec, RowLabelInfo},
11};
12
13pub struct Arena {
14 inner: DroplessArena,
15}
16
17impl Arena {
18 pub fn new() -> Self {
19 Arena {
20 inner: DroplessArena::default(),
21 }
22 }
23
24 pub fn push<'arena>(&'arena self, node: Node<'arena>) -> &'arena mut Node<'arena> {
25 self.inner.alloc(node)
26 }
27
28 pub fn push_slice<'arena>(
29 &'arena self,
30 nodes: &[&'arena Node<'arena>],
31 ) -> &'arena [&'arena Node<'arena>] {
32 if nodes.is_empty() {
34 &[]
35 } else {
36 self.inner.alloc_slice(nodes)
37 }
38 }
39
40 pub fn alloc_str(&self, src: &str) -> &str {
41 if src.is_empty() {
43 ""
44 } else {
45 self.inner.alloc_str(src)
46 }
47 }
48
49 pub fn alloc_column_spec<'arena>(&'arena self, column_spec: ColumnSpec) -> ColumnSpec<'arena> {
50 if column_spec.is_empty() {
52 &[]
53 } else {
54 self.inner.alloc_slice(column_spec)
55 }
56 }
57
58 pub fn alloc_array_spec<'arena>(
59 &'arena self,
60 array_spec: ArraySpec<'arena>,
61 ) -> &'arena ArraySpec<'arena> {
62 self.inner.alloc(array_spec)
63 }
64
65 pub fn alloc_row_label_info<'arena>(
66 &'arena self,
67 info: RowLabelInfo<'arena>,
68 ) -> &'arena RowLabelInfo<'arena> {
69 self.inner.alloc(info)
70 }
71
72 pub fn alloc_ahref<'arena, 'attrs>(
73 &'arena self,
74 ahref: AHref<'attrs>,
75 ) -> &'arena AHref<'attrs> {
76 self.inner.alloc(ahref)
77 }
78
79 pub fn alloc_multiscript_pairs<'arena, 'pairs>(
80 &'arena self,
81 pairs: &[MultiscriptPair<'pairs>],
82 ) -> &'arena &'arena [MultiscriptPair<'pairs>] {
83 let fat = self.inner.alloc_slice(pairs);
84 self.inner.alloc(&*fat)
85 }
86
87 pub fn alloc_length_set(&self, length_set: LengthSet) -> &LengthSet {
88 self.inner.alloc(length_set)
89 }
90}
91
92impl Default for Arena {
93 fn default() -> Self {
94 Self::new()
95 }
96}
97
98#[derive(Debug)]
99#[repr(transparent)]
100pub struct Buffer(String);
101
102impl Buffer {
103 pub fn new(size_hint: usize) -> Self {
104 Buffer(String::with_capacity(size_hint))
105 }
106
107 pub fn get_builder(&mut self) -> StringBuilder<'_> {
108 StringBuilder::new(self)
109 }
110}
111
112#[derive(Debug)]
118pub struct StringBuilder<'buffer> {
119 buffer: &'buffer mut Buffer,
120}
121
122impl<'buffer> StringBuilder<'buffer> {
123 pub fn new(buffer: &'buffer mut Buffer) -> Self {
124 buffer.0.clear();
126 StringBuilder { buffer }
127 }
128
129 #[inline]
130 pub fn push_str(&mut self, src: &str) {
131 self.buffer.0.push_str(src)
132 }
133
134 pub fn push_char(&mut self, c: char) {
135 self.buffer.0.push(c)
136 }
137
138 #[inline]
139 pub fn push_superchar(&mut self, sc: SuperChar) {
140 self.buffer.0.extend(sc.chars());
141 }
142
143 pub fn finish(self, arena: &Arena) -> &str {
144 arena.alloc_str(&self.buffer.0)
145 }
146
147 pub fn is_empty(&self) -> bool {
148 self.buffer.0.is_empty()
149 }
150}
151
152impl core::fmt::Write for StringBuilder<'_> {
153 #[inline]
154 fn write_str(&mut self, s: &str) -> core::fmt::Result {
155 self.push_str(s);
156 Ok(())
157 }
158
159 #[inline]
160 fn write_char(&mut self, c: char) -> core::fmt::Result {
161 self.push_char(c);
162 Ok(())
163 }
164}
165
166#[cfg(test)]
167mod tests {
168 use crate::attribute::RowAttrs;
169
170 use super::*;
171
172 #[test]
173 fn test_arena() {
174 let arena = Arena::new();
175 let node = Node::EMPTY_ROW;
176 let reference = arena.push(node);
177 std::assert_matches!(
178 reference,
179 Node::Row {
180 nodes: [],
181 attrs: RowAttrs::DEFAULT,
182 },
183 );
184 }
185
186 #[test]
187 fn test_buffer_extend() {
188 let arena = Arena::new();
189 let mut buffer = Buffer::new(0);
190 let mut builder = buffer.get_builder();
191 builder.push_char('H');
192 builder.push_char('i');
193 let str_ref = builder.finish(&arena);
194 assert_eq!(str_ref, "Hi");
195 }
196
197 #[test]
198 fn test_buffer_manual_reference() {
199 let arena = Arena::new();
200 let mut buffer = Buffer::new(0);
201 let mut builder = buffer.get_builder();
202 assert_eq!(builder.buffer.0.len(), 0);
203 builder.push_char('H');
204 builder.push_char('i');
205 builder.push_char('↩'); assert_eq!(builder.buffer.0.len(), 5);
207 let str_ref = builder.finish(&arena);
208 assert_eq!(str_ref.len(), 5);
209 assert_eq!(str_ref, "Hi↩");
210 }
211
212 struct CycleParticipant<'a> {
213 val: i32,
214 next: Option<&'a mut CycleParticipant<'a>>,
215 }
216
217 #[test]
218 fn test_arena_with_cycle() {
219 let arena = DroplessArena::default();
220
221 let a = arena.alloc(CycleParticipant { val: 1, next: None });
222 let b = arena.alloc(CycleParticipant { val: 2, next: None });
223 a.next = Some(b);
224 let c = arena.alloc(CycleParticipant { val: 3, next: None });
225 a.next.as_mut().unwrap().next = Some(c);
226
227 assert_eq!(a.val, 1);
237 assert_eq!(a.next.as_ref().unwrap().val, 2);
238 assert_eq!(a.next.as_ref().unwrap().next.as_ref().unwrap().val, 3);
239 }
240}