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_spec<'arena>(&'arena self, column_spec: ColumnSpec) -> ColumnSpec<'arena> {
48 if column_spec.is_empty() {
50 &[]
51 } else {
52 self.inner.alloc_slice(column_spec)
53 }
54 }
55
56 pub fn alloc_array_spec<'arena>(
57 &'arena self,
58 array_spec: ArraySpec<'arena>,
59 ) -> &'arena ArraySpec<'arena> {
60 self.inner.alloc(array_spec)
61 }
62
63 pub fn alloc_row_label_info<'arena>(
64 &'arena self,
65 info: RowLabelInfo<'arena>,
66 ) -> &'arena RowLabelInfo<'arena> {
67 self.inner.alloc(info)
68 }
69
70 pub fn alloc_ahref<'arena, 'attrs>(
71 &'arena self,
72 ahref: AHref<'attrs>,
73 ) -> &'arena AHref<'attrs> {
74 self.inner.alloc(ahref)
75 }
76
77 pub fn alloc_multiscript_pairs<'arena, 'pairs>(
78 &'arena self,
79 pairs: &[MultiscriptPair<'pairs>],
80 ) -> &'arena &'arena [MultiscriptPair<'pairs>] {
81 let fat = self.inner.alloc_slice(pairs);
82 self.inner.alloc(&*fat)
83 }
84}
85
86impl Default for Arena {
87 fn default() -> Self {
88 Self::new()
89 }
90}
91
92#[derive(Debug)]
93#[repr(transparent)]
94pub struct Buffer(String);
95
96impl Buffer {
97 pub fn new(size_hint: usize) -> Self {
98 Buffer(String::with_capacity(size_hint))
99 }
100
101 pub fn get_builder(&mut self) -> StringBuilder<'_> {
102 StringBuilder::new(self)
103 }
104}
105
106#[derive(Debug)]
112pub struct StringBuilder<'buffer> {
113 buffer: &'buffer mut Buffer,
114}
115
116impl<'buffer> StringBuilder<'buffer> {
117 pub fn new(buffer: &'buffer mut Buffer) -> Self {
118 buffer.0.clear();
120 StringBuilder { buffer }
121 }
122
123 #[inline]
124 pub fn push_str(&mut self, src: &str) {
125 self.buffer.0.push_str(src)
126 }
127
128 pub fn push_char(&mut self, c: char) {
129 self.buffer.0.push(c)
130 }
131
132 #[inline]
133 pub fn push_superchar(&mut self, sc: SuperChar) {
134 self.buffer.0.extend(sc.chars());
135 }
136
137 pub fn finish(self, arena: &Arena) -> &str {
138 arena.alloc_str(&self.buffer.0)
139 }
140
141 pub fn is_empty(&self) -> bool {
142 self.buffer.0.is_empty()
143 }
144}
145
146impl std::fmt::Write for StringBuilder<'_> {
147 #[inline]
148 fn write_str(&mut self, s: &str) -> std::fmt::Result {
149 self.push_str(s);
150 Ok(())
151 }
152
153 #[inline]
154 fn write_char(&mut self, c: char) -> std::fmt::Result {
155 self.push_char(c);
156 Ok(())
157 }
158}
159
160#[cfg(test)]
161mod tests {
162 use crate::attribute::RowAttrs;
163
164 use super::*;
165
166 #[test]
167 fn test_arena() {
168 let arena = Arena::new();
169 let node = Node::EMPTY_ROW;
170 let reference = arena.push(node);
171 assert!(matches!(
172 reference,
173 Node::Row {
174 nodes: [],
175 attrs: RowAttrs::DEFAULT,
176 },
177 ));
178 }
179
180 #[test]
181 fn test_buffer_extend() {
182 let arena = Arena::new();
183 let mut buffer = Buffer::new(0);
184 let mut builder = buffer.get_builder();
185 builder.push_char('H');
186 builder.push_char('i');
187 let str_ref = builder.finish(&arena);
188 assert_eq!(str_ref, "Hi");
189 }
190
191 #[test]
192 fn test_buffer_manual_reference() {
193 let arena = Arena::new();
194 let mut buffer = Buffer::new(0);
195 let mut builder = buffer.get_builder();
196 assert_eq!(builder.buffer.0.len(), 0);
197 builder.push_char('H');
198 builder.push_char('i');
199 builder.push_char('↩'); assert_eq!(builder.buffer.0.len(), 5);
201 let str_ref = builder.finish(&arena);
202 assert_eq!(str_ref.len(), 5);
203 assert_eq!(str_ref, "Hi↩");
204 }
205
206 struct CycleParticipant<'a> {
207 val: i32,
208 next: Option<&'a mut CycleParticipant<'a>>,
209 }
210
211 #[test]
212 fn test_arena_with_cycle() {
213 let arena = DroplessArena::default();
214
215 let a = arena.alloc(CycleParticipant { val: 1, next: None });
216 let b = arena.alloc(CycleParticipant { val: 2, next: None });
217 a.next = Some(b);
218 let c = arena.alloc(CycleParticipant { val: 3, next: None });
219 a.next.as_mut().unwrap().next = Some(c);
220
221 assert_eq!(a.val, 1);
231 assert_eq!(a.next.as_ref().unwrap().val, 2);
232 assert_eq!(a.next.as_ref().unwrap().next.as_ref().unwrap().val, 3);
233 }
234}