math_core_renderer_internal/
arena.rs1use std::fmt::Debug;
2
3use stable_arena::DroplessArena;
4
5use crate::{
6 ast::{AHref, 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
81impl Default for Arena {
82 fn default() -> Self {
83 Self::new()
84 }
85}
86
87#[derive(Debug)]
88#[repr(transparent)]
89pub struct Buffer(String);
90
91impl Buffer {
92 pub fn new(size_hint: usize) -> Self {
93 Buffer(String::with_capacity(size_hint))
94 }
95
96 pub fn get_builder(&mut self) -> StringBuilder<'_> {
97 StringBuilder::new(self)
98 }
99}
100
101#[derive(Debug)]
107pub struct StringBuilder<'buffer> {
108 buffer: &'buffer mut Buffer,
109}
110
111impl<'buffer> StringBuilder<'buffer> {
112 pub fn new(buffer: &'buffer mut Buffer) -> Self {
113 buffer.0.clear();
115 StringBuilder { buffer }
116 }
117
118 #[inline]
119 pub fn push_str(&mut self, src: &str) {
120 self.buffer.0.push_str(src)
121 }
122
123 pub fn push_char(&mut self, c: char) {
124 self.buffer.0.push(c)
125 }
126
127 #[inline]
128 pub fn push_superchar(&mut self, sc: SuperChar) {
129 self.buffer.0.extend(sc.chars());
130 }
131
132 pub fn finish(self, arena: &Arena) -> &str {
133 arena.alloc_str(&self.buffer.0)
134 }
135
136 pub fn is_empty(&self) -> bool {
137 self.buffer.0.is_empty()
138 }
139}
140
141impl std::fmt::Write for StringBuilder<'_> {
142 #[inline]
143 fn write_str(&mut self, s: &str) -> std::fmt::Result {
144 self.push_str(s);
145 Ok(())
146 }
147
148 #[inline]
149 fn write_char(&mut self, c: char) -> std::fmt::Result {
150 self.push_char(c);
151 Ok(())
152 }
153}
154
155#[cfg(test)]
156mod tests {
157 use super::*;
158
159 #[test]
160 fn test_arena() {
161 let arena = Arena::new();
162 let node = Node::HardcodedMathML("Hello, world!");
163 let reference = arena.push(node);
164 assert!(matches!(reference, Node::HardcodedMathML("Hello, world!")));
165 }
166
167 #[test]
168 fn test_buffer_extend() {
169 let arena = Arena::new();
170 let mut buffer = Buffer::new(0);
171 let mut builder = buffer.get_builder();
172 builder.push_char('H');
173 builder.push_char('i');
174 let str_ref = builder.finish(&arena);
175 assert_eq!(str_ref, "Hi");
176 }
177
178 #[test]
179 fn test_buffer_manual_reference() {
180 let arena = Arena::new();
181 let mut buffer = Buffer::new(0);
182 let mut builder = buffer.get_builder();
183 assert_eq!(builder.buffer.0.len(), 0);
184 builder.push_char('H');
185 builder.push_char('i');
186 builder.push_char('↩'); assert_eq!(builder.buffer.0.len(), 5);
188 let str_ref = builder.finish(&arena);
189 assert_eq!(str_ref.len(), 5);
190 assert_eq!(str_ref, "Hi↩");
191 }
192
193 struct CycleParticipant<'a> {
194 val: i32,
195 next: Option<&'a mut CycleParticipant<'a>>,
196 }
197
198 #[test]
199 fn test_arena_with_cycle() {
200 let arena = DroplessArena::default();
201
202 let a = arena.alloc(CycleParticipant { val: 1, next: None });
203 let b = arena.alloc(CycleParticipant { val: 2, next: None });
204 a.next = Some(b);
205 let c = arena.alloc(CycleParticipant { val: 3, next: None });
206 a.next.as_mut().unwrap().next = Some(c);
207
208 assert_eq!(a.val, 1);
218 assert_eq!(a.next.as_ref().unwrap().val, 2);
219 assert_eq!(a.next.as_ref().unwrap().next.as_ref().unwrap().val, 3);
220 }
221}