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