math_core_renderer_internal/
arena.rs1use std::fmt::Debug;
2
3use stable_arena::DroplessArena;
4
5use crate::{
6 ast::Node,
7 table::{ArraySpec, ColumnSpec},
8};
9
10pub struct Arena {
11 inner: DroplessArena,
12}
13
14impl Arena {
15 pub fn new() -> Self {
16 Arena {
17 inner: DroplessArena::default(),
18 }
19 }
20
21 pub fn push<'arena>(&'arena self, node: Node<'arena>) -> &'arena mut Node<'arena> {
22 self.inner.alloc(node)
23 }
24
25 pub fn push_slice<'arena>(
26 &'arena self,
27 nodes: &[&'arena Node<'arena>],
28 ) -> &'arena [&'arena Node<'arena>] {
29 if nodes.is_empty() {
31 &[]
32 } else {
33 self.inner.alloc_slice(nodes)
34 }
35 }
36
37 pub fn alloc_str(&self, src: &str) -> &str {
38 if src.is_empty() {
40 ""
41 } else {
42 self.inner.alloc_str(src)
43 }
44 }
45
46 pub fn alloc_column_specs<'arena>(
47 &'arena self,
48 column_specs: &[ColumnSpec],
49 ) -> &'arena [ColumnSpec] {
50 if column_specs.is_empty() {
52 &[]
53 } else {
54 self.inner.alloc_slice(column_specs)
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
66impl Default for Arena {
67 fn default() -> Self {
68 Self::new()
69 }
70}
71
72#[derive(Debug)]
73#[repr(transparent)]
74pub struct Buffer(String);
75
76impl Buffer {
77 pub fn new(size_hint: usize) -> Self {
78 Buffer(String::with_capacity(size_hint))
79 }
80
81 pub fn get_builder(&mut self) -> StringBuilder<'_> {
82 StringBuilder::new(self)
83 }
84}
85
86pub struct StringBuilder<'buffer> {
92 buffer: &'buffer mut Buffer,
93}
94
95impl<'buffer> StringBuilder<'buffer> {
96 pub fn new(buffer: &'buffer mut Buffer) -> Self {
97 buffer.0.clear();
99 StringBuilder { buffer }
100 }
101
102 #[inline]
103 pub fn push_str(&mut self, src: &str) {
104 self.buffer.0.push_str(src)
105 }
106
107 pub fn push_char(&mut self, c: char) {
108 self.buffer.0.push(c)
109 }
110
111 pub fn finish(self, arena: &Arena) -> &str {
112 arena.alloc_str(&self.buffer.0)
113 }
114
115 pub fn is_empty(&self) -> bool {
116 self.buffer.0.is_empty()
117 }
118}
119
120impl std::fmt::Write for StringBuilder<'_> {
121 #[inline]
122 fn write_str(&mut self, s: &str) -> std::fmt::Result {
123 self.push_str(s);
124 Ok(())
125 }
126
127 #[inline]
128 fn write_char(&mut self, c: char) -> std::fmt::Result {
129 self.push_char(c);
130 Ok(())
131 }
132}
133
134#[cfg(test)]
135mod tests {
136 use super::*;
137
138 #[test]
139 fn test_arena() {
140 let arena = Arena::new();
141 let node = Node::HardcodedMathML("Hello, world!");
142 let reference = arena.push(node);
143 assert!(matches!(reference, Node::HardcodedMathML("Hello, world!")));
144 }
145
146 #[test]
147 fn test_buffer_extend() {
148 let arena = Arena::new();
149 let mut buffer = Buffer::new(0);
150 let mut builder = buffer.get_builder();
151 builder.push_char('H');
152 builder.push_char('i');
153 let str_ref = builder.finish(&arena);
154 assert_eq!(str_ref, "Hi");
155 }
156
157 #[test]
158 fn test_buffer_manual_reference() {
159 let arena = Arena::new();
160 let mut buffer = Buffer::new(0);
161 let mut builder = buffer.get_builder();
162 assert_eq!(builder.buffer.0.len(), 0);
163 builder.push_char('H');
164 builder.push_char('i');
165 builder.push_char('↩'); assert_eq!(builder.buffer.0.len(), 5);
167 let str_ref = builder.finish(&arena);
168 assert_eq!(str_ref.len(), 5);
169 assert_eq!(str_ref, "Hi↩");
170 }
171
172 struct CycleParticipant<'a> {
173 val: i32,
174 next: Option<&'a mut CycleParticipant<'a>>,
175 }
176
177 #[test]
178 fn test_arena_with_cycle() {
179 let arena = DroplessArena::default();
180
181 let a = arena.alloc(CycleParticipant { val: 1, next: None });
182 let b = arena.alloc(CycleParticipant { val: 2, next: None });
183 a.next = Some(b);
184 let c = arena.alloc(CycleParticipant { val: 3, next: None });
185 a.next.as_mut().unwrap().next = Some(c);
186
187 assert_eq!(a.val, 1);
197 assert_eq!(a.next.as_ref().unwrap().val, 2);
198 assert_eq!(a.next.as_ref().unwrap().next.as_ref().unwrap().val, 3);
199 }
200}