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
120#[cfg(test)]
121mod tests {
122 use super::*;
123
124 #[test]
125 fn arena_test() {
126 let arena = Arena::new();
127 let node = Node::HardcodedMathML("Hello, world!");
128 let reference = arena.push(node);
129 assert!(matches!(reference, Node::HardcodedMathML("Hello, world!")));
130 }
131
132 #[test]
133 fn buffer_extend() {
134 let arena = Arena::new();
135 let mut buffer = Buffer::new(0);
136 let mut builder = buffer.get_builder();
137 builder.push_char('H');
138 builder.push_char('i');
139 let str_ref = builder.finish(&arena);
140 assert_eq!(str_ref, "Hi");
141 }
142
143 #[test]
144 fn buffer_manual_reference() {
145 let arena = Arena::new();
146 let mut buffer = Buffer::new(0);
147 let mut builder = buffer.get_builder();
148 assert_eq!(builder.buffer.0.len(), 0);
149 builder.push_char('H');
150 builder.push_char('i');
151 builder.push_char('↩'); assert_eq!(builder.buffer.0.len(), 5);
153 let str_ref = builder.finish(&arena);
154 assert_eq!(str_ref.len(), 5);
155 assert_eq!(str_ref, "Hi↩");
156 }
157
158 struct CycleParticipant<'a> {
159 val: i32,
160 next: Option<&'a mut CycleParticipant<'a>>,
161 }
162
163 #[test]
164 fn basic_arena() {
165 let arena = DroplessArena::default();
166
167 let a = arena.alloc(CycleParticipant { val: 1, next: None });
168 let b = arena.alloc(CycleParticipant { val: 2, next: None });
169 a.next = Some(b);
170 let c = arena.alloc(CycleParticipant { val: 3, next: None });
171 a.next.as_mut().unwrap().next = Some(c);
172
173 assert_eq!(a.val, 1);
183 assert_eq!(a.next.as_ref().unwrap().val, 2);
184 assert_eq!(a.next.as_ref().unwrap().next.as_ref().unwrap().val, 3);
185 }
186}