xsd_schema/document/
page.rs1use std::cell::Cell;
2
3use bumpalo::Bump;
4
5use super::error::BufferDocumentError;
6use super::node::{page_of, slot_of, Node, PAGE_SIZE};
7
8pub struct NodePages<'a> {
16 arena: &'a Bump,
17 pages: Vec<&'a [Cell<Node>]>,
18 len: u32,
19}
20
21impl<'a> NodePages<'a> {
22 pub fn new(arena: &'a Bump) -> Self {
24 let first_page = Self::make_page(arena);
25 Self {
26 arena,
27 pages: vec![first_page],
28 len: 0,
29 }
30 }
31
32 pub fn alloc(&mut self) -> Result<u32, BufferDocumentError> {
40 let idx = self.len;
41 if idx == u32::MAX {
43 return Err(BufferDocumentError::Overflow);
44 }
45 self.len = idx + 1;
46 if idx > 0 && slot_of(idx) == 0 {
49 self.allocate_page();
50 }
51 Ok(idx)
52 }
53
54 #[inline]
56 pub fn get(&self, node_ref: u32) -> Node {
57 let page = page_of(node_ref) as usize;
58 let slot = slot_of(node_ref) as usize;
59 self.pages[page][slot].get()
60 }
61
62 #[inline]
64 pub fn set(&self, node_ref: u32, node: Node) {
65 let page = page_of(node_ref) as usize;
66 let slot = slot_of(node_ref) as usize;
67 self.pages[page][slot].set(node);
68 }
69
70 #[inline]
72 pub fn update<F: FnOnce(&mut Node)>(&self, node_ref: u32, f: F) {
73 let page = page_of(node_ref) as usize;
74 let slot = slot_of(node_ref) as usize;
75 let mut node = self.pages[page][slot].get();
76 f(&mut node);
77 self.pages[page][slot].set(node);
78 }
79
80 #[inline]
82 pub fn len(&self) -> u32 {
83 self.len
84 }
85
86 #[inline]
88 pub fn is_empty(&self) -> bool {
89 self.len == 0
90 }
91
92 fn allocate_page(&mut self) {
94 let page = Self::make_page(self.arena);
95 self.pages.push(page);
96 }
97
98 fn make_page(arena: &Bump) -> &[Cell<Node>] {
100 arena.alloc_slice_fill_with(PAGE_SIZE as usize, |_| Cell::new(Node::default()))
101 }
102}
103
104#[cfg(test)]
105mod tests {
106 use super::super::node::{NodeType, NULL, PAGE_SIZE};
107 use super::*;
108
109 #[test]
110 fn first_alloc_returns_zero() {
111 let arena = Bump::new();
112 let mut pages = NodePages::new(&arena);
113 assert_eq!(pages.alloc().unwrap(), 0);
114 }
115
116 #[test]
117 fn sequential_alloc() {
118 let arena = Bump::new();
119 let mut pages = NodePages::new(&arena);
120 for expected in 0..10 {
121 assert_eq!(pages.alloc().unwrap(), expected);
122 }
123 }
124
125 #[test]
126 fn set_get_round_trip() {
127 let arena = Bump::new();
128 let mut pages = NodePages::new(&arena);
129 let idx = pages.alloc().unwrap();
130
131 let mut node = Node::default();
132 node.set_node_type(NodeType::Element);
133 node.value = 42;
134 node.parent = NULL;
135 node.next_sibling = NULL;
136
137 pages.set(idx, node);
138 let read = pages.get(idx);
139 assert_eq!(read.node_type(), NodeType::Element);
140 assert_eq!(read.value, 42);
141 assert_eq!(read.parent, NULL);
142 assert_eq!(read.next_sibling, NULL);
143 }
144
145 #[test]
146 fn update_modifies_in_place() {
147 let arena = Bump::new();
148 let mut pages = NodePages::new(&arena);
149 let idx = pages.alloc().unwrap();
150
151 let mut node = Node::default();
152 node.set_node_type(NodeType::Text);
153 node.value = 10;
154 pages.set(idx, node);
155
156 pages.update(idx, |n| {
157 n.value = 99;
158 n.set_flag(Node::HAS_CHILDREN);
159 });
160
161 let read = pages.get(idx);
162 assert_eq!(read.value, 99);
163 assert!(read.has_flag(Node::HAS_CHILDREN));
164 assert_eq!(read.node_type(), NodeType::Text); }
166
167 #[test]
168 fn cross_page_allocation() {
169 let arena = Bump::new();
170 let mut pages = NodePages::new(&arena);
171
172 let count = PAGE_SIZE + 1;
174 for i in 0..count {
175 let idx = pages.alloc().unwrap();
176 assert_eq!(idx, i);
177 pages.set(
179 idx,
180 Node {
181 value: i,
182 ..Node::default()
183 },
184 );
185 }
186
187 assert_eq!(pages.len(), count);
188
189 let last_first = PAGE_SIZE - 1;
191 assert_eq!(pages.get(last_first).value, last_first);
192
193 assert_eq!(pages.get(PAGE_SIZE).value, PAGE_SIZE);
195 }
196
197 #[test]
198 fn len_tracks_allocations() {
199 let arena = Bump::new();
200 let mut pages = NodePages::new(&arena);
201 assert_eq!(pages.len(), 0);
202 assert!(pages.is_empty());
203
204 pages.alloc().unwrap();
205 assert_eq!(pages.len(), 1);
206 assert!(!pages.is_empty());
207
208 for _ in 0..9 {
209 pages.alloc().unwrap();
210 }
211 assert_eq!(pages.len(), 10);
212 }
213
214 #[test]
215 fn default_node_is_nul() {
216 let arena = Bump::new();
217 let mut pages = NodePages::new(&arena);
218 let idx = pages.alloc().unwrap();
219 let node = pages.get(idx);
220 assert_eq!(node.node_type(), NodeType::Nul);
221 assert_eq!(node.value, 0);
222 assert_eq!(node.parent, 0);
223 assert_eq!(node.next_sibling, 0);
224 }
225
226 #[test]
227 fn set_with_shared_ref() {
228 let arena = Bump::new();
230 let mut pages = NodePages::new(&arena);
231 let idx = pages.alloc().unwrap();
232
233 let pages_ref: &NodePages = &pages;
235 let mut node = Node::default();
236 node.set_node_type(NodeType::Comment);
237 node.value = 7;
238 pages_ref.set(idx, node);
239
240 assert_eq!(pages.get(idx).node_type(), NodeType::Comment);
241 assert_eq!(pages.get(idx).value, 7);
242 }
243
244 #[test]
245 fn alloc_overflow_returns_error() {
246 let arena = Bump::new();
247 let mut pages = NodePages::new(&arena);
248 pages.len = u32::MAX;
250 assert!(matches!(pages.alloc(), Err(BufferDocumentError::Overflow)));
251 }
252}