1use alloc::vec::Vec;
7
8use crate::opcode::Opcode;
9use crate::{constants, memory, memory::header};
10
11#[derive(Debug, Clone, Copy, PartialEq, Eq)]
13pub enum RingError {
14 Full,
17}
18
19#[inline]
24pub(crate) fn push(slots: &mut [u8], header: &mut [u8], mask: usize, op: &Opcode) -> Result<(), RingError> {
25 let write = cursor(header, memory::OFF_WRITE_CURSOR, mask);
26 let next = (write + 1) & mask;
27 if next == cursor(header, memory::OFF_READ_CURSOR, mask) {
28 return Err(RingError::Full);
29 }
30 let bytes = op.to_bytes();
31 let off = write * Opcode::SIZE;
32 slots[off..off + Opcode::SIZE].copy_from_slice(&bytes);
33 header::set_u32(header, memory::OFF_WRITE_CURSOR, next as u32);
34 Ok(())
35}
36
37#[inline]
39pub(crate) fn cursor(header: &[u8], off: usize, mask: usize) -> usize {
40 header::get_u32(header, off) as usize & mask
41}
42
43pub(crate) fn push_create_node(
45 slots: &mut [u8],
46 header: &mut [u8],
47 mask: usize,
48 node_id: u32,
49 component_type: u16,
50) -> Result<(), RingError> {
51 push(
52 slots,
53 header,
54 mask,
55 &Opcode::new(
56 constants::category::TREE,
57 constants::tree::CREATE_NODE,
58 0,
59 node_id,
60 component_type as u32,
61 0,
62 ),
63 )
64}
65
66pub(crate) fn push_delete_node(
67 slots: &mut [u8],
68 header: &mut [u8],
69 mask: usize,
70 node_id: u32,
71) -> Result<(), RingError> {
72 push(
73 slots,
74 header,
75 mask,
76 &Opcode::new(constants::category::TREE, constants::tree::DELETE_NODE, 0, node_id, 0, 0),
77 )
78}
79
80pub(crate) fn push_insert_child(
81 slots: &mut [u8],
82 header: &mut [u8],
83 mask: usize,
84 parent: u32,
85 child: u32,
86 index: u32,
87) -> Result<(), RingError> {
88 push(
89 slots,
90 header,
91 mask,
92 &Opcode::new(
93 constants::category::TREE,
94 constants::tree::INSERT_CHILD,
95 0,
96 parent,
97 child,
98 index,
99 ),
100 )
101}
102
103pub(crate) fn push_remove_child(
104 slots: &mut [u8],
105 header: &mut [u8],
106 mask: usize,
107 parent: u32,
108 child: u32,
109) -> Result<(), RingError> {
110 push(
111 slots,
112 header,
113 mask,
114 &Opcode::new(
115 constants::category::TREE,
116 constants::tree::REMOVE_CHILD,
117 0,
118 parent,
119 child,
120 0,
121 ),
122 )
123}
124
125pub(crate) fn push_move_child(
126 slots: &mut [u8],
127 header: &mut [u8],
128 mask: usize,
129 parent: u32,
130 child: u32,
131 new_index: u32,
132) -> Result<(), RingError> {
133 push(
134 slots,
135 header,
136 mask,
137 &Opcode::new(
138 constants::category::TREE,
139 constants::tree::MOVE_CHILD,
140 0,
141 parent,
142 child,
143 new_index,
144 ),
145 )
146}
147
148pub(crate) fn push_set_property(
149 slots: &mut [u8],
150 header: &mut [u8],
151 mask: usize,
152 node_id: u32,
153 property_id: u16,
154 value_type: u8,
155 value: u32,
156) -> Result<(), RingError> {
157 push(
158 slots,
159 header,
160 mask,
161 &Opcode::new(
162 constants::category::PARAMETER,
163 constants::parameter::SET_PROPERTY,
164 0,
165 node_id,
166 ((value_type as u32) << 16) | property_id as u32,
167 value,
168 ),
169 )
170}
171
172pub(crate) fn push_set_text(
173 slots: &mut [u8],
174 header: &mut [u8],
175 mask: usize,
176 node_id: u32,
177 arena_ref: u32,
178) -> Result<(), RingError> {
179 push(
180 slots,
181 header,
182 mask,
183 &Opcode::new(
184 constants::category::PARAMETER,
185 constants::parameter::SET_TEXT,
186 0,
187 node_id,
188 arena_ref,
189 0,
190 ),
191 )
192}
193
194pub(crate) fn push_reset(
195 slots: &mut [u8],
196 header: &mut [u8],
197 mask: usize,
198) -> Result<(), RingError> {
199 push(
200 slots,
201 header,
202 mask,
203 &Opcode::new(constants::category::META, constants::meta::RESET, 0, 0, 0, 0),
204 )
205}
206
207#[inline]
216pub(crate) fn push_event(
217 event_slots: &mut [u8],
218 header: &mut [u8],
219 mask: usize,
220 op: &Opcode,
221) -> Result<(), RingError> {
222 let write = cursor(header, memory::OFF_EVENT_WRITE_CURSOR, mask);
223 let next = (write + 1) & mask;
224 if next == cursor(header, memory::OFF_EVENT_READ_CURSOR, mask) {
225 return Err(RingError::Full);
226 }
227 let bytes = op.to_bytes();
228 let off = write * Opcode::SIZE;
229 event_slots[off..off + Opcode::SIZE].copy_from_slice(&bytes);
230 header::set_u32(header, memory::OFF_EVENT_WRITE_CURSOR, next as u32);
231 Ok(())
232}
233
234#[inline]
244pub(crate) fn read_events(
245 event_slots: &[u8],
246 header: &mut [u8],
247 mask: usize,
248 max: usize,
249) -> Vec<Opcode> {
250 let read = cursor(header, memory::OFF_EVENT_READ_CURSOR, mask);
251 let write = cursor(header, memory::OFF_EVENT_WRITE_CURSOR, mask);
252 let count = write.wrapping_sub(read) & mask;
253 let n = count.min(max);
254 if n == 0 {
255 return Vec::new();
256 }
257 let mut out = Vec::with_capacity(n);
258 for i in 0..n {
259 let slot = (read + i) & mask;
260 let off = slot * Opcode::SIZE;
261 let bytes: [u8; Opcode::SIZE] =
262 event_slots[off..off + Opcode::SIZE].try_into().unwrap();
263 out.push(Opcode::from_bytes(&bytes));
264 }
265 header::set_u32(header, memory::OFF_EVENT_READ_CURSOR, ((read + n) & mask) as u32);
266 out
267}
268
269#[cfg(test)]
270mod tests {
271 use super::*;
272 use crate::memory::header;
273 use alloc::vec;
274
275 fn tiny_mem(slot_count: usize) -> Vec<u8> {
278 let layout = crate::memory::MemoryLayout {
279 slot_count,
280 arena_bytes: 64,
281 event_arena_bytes: 64,
282 };
283 let mut mem = vec![0u8; layout.total_bytes()];
284 crate::init_memory(&mut mem, &layout);
285 mem
286 }
287
288 #[test]
289 fn push_reports_full_at_exact_capacity() {
290 let slot_count = 4usize;
291 let mut mem = tiny_mem(slot_count);
292 let mask = slot_count - 1;
293
294 let (head, rest) = mem.split_at_mut(crate::memory::HEADER_SIZE);
296 let (slots, _rest) = rest.split_at_mut(slot_count * Opcode::SIZE);
297
298 for i in 0..3 {
299 push(slots, head, mask, &Opcode::new(crate::category::TREE, 1, 0, i, 0, 0)).unwrap();
300 }
301 assert_eq!(
302 push(slots, head, mask, &Opcode::new(crate::category::TREE, 1, 0, 9, 0, 0)),
303 Err(RingError::Full)
304 );
305 assert_eq!(header::get_u32(head, crate::memory::OFF_WRITE_CURSOR), 3);
307 }
308
309 #[test]
310 fn cursor_masks_out_of_range_header_values() {
311 let mut mem = tiny_mem(8);
312 let (head, _) = mem.split_at_mut(crate::memory::HEADER_SIZE);
313 header::set_u32(head, crate::memory::OFF_WRITE_CURSOR, 17);
314 assert_eq!(cursor(head, crate::memory::OFF_WRITE_CURSOR, 7), 1);
316 }
317
318 #[test]
319 fn push_event_and_read_events_round_trip() {
320 let slot_count = 4usize;
321 let mut mem = tiny_mem(slot_count);
322 let mask = slot_count - 1;
323
324 let (head, rest) = mem.split_at_mut(crate::memory::HEADER_SIZE);
325 let (_slots, rest) = rest.split_at_mut(slot_count * Opcode::SIZE);
326 let (event_slots, _arena) = rest.split_at_mut(slot_count * Opcode::SIZE);
327
328 let op = Opcode::new(crate::category::EVENT, crate::event::POINTER_UP, 0, 5, 0, 0);
329 push_event(event_slots, head, mask, &op).unwrap();
330
331 let drained = read_events(event_slots, head, mask, usize::MAX);
332 assert_eq!(drained, vec![op]);
333 assert!(read_events(event_slots, head, mask, usize::MAX).is_empty());
335 assert_eq!(
336 header::get_u32(head, crate::memory::OFF_EVENT_READ_CURSOR),
337 header::get_u32(head, crate::memory::OFF_EVENT_WRITE_CURSOR)
338 );
339 }
340
341 #[test]
342 fn push_event_reports_full_and_recovers() {
343 let slot_count = 2usize;
344 let mut mem = tiny_mem(slot_count);
345 let mask = slot_count - 1;
346
347 let (head, rest) = mem.split_at_mut(crate::memory::HEADER_SIZE);
348 let (_slots, rest) = rest.split_at_mut(slot_count * Opcode::SIZE);
349 let (event_slots, _arena) = rest.split_at_mut(slot_count * Opcode::SIZE);
350
351 let op = Opcode::new(crate::category::EVENT, crate::event::POINTER_UP, 0, 5, 0, 0);
352 assert!(push_event(event_slots, head, mask, &op).is_ok());
353 assert_eq!(
354 push_event(event_slots, head, mask, &op),
355 Err(RingError::Full)
356 );
357
358 let drained = read_events(event_slots, head, mask, usize::MAX);
360 assert_eq!(drained.len(), 1);
361 assert!(push_event(event_slots, head, mask, &op).is_ok());
362 }
363
364 #[test]
365 fn read_events_drains_a_wrapped_producer() {
366 let slot_count = 4usize;
367 let mut mem = tiny_mem(slot_count);
368 let mask = slot_count - 1;
369
370 let (head, rest) = mem.split_at_mut(crate::memory::HEADER_SIZE);
371 let (_slots, rest) = rest.split_at_mut(slot_count * Opcode::SIZE);
372 let (event_slots, _arena) = rest.split_at_mut(slot_count * Opcode::SIZE);
373
374 let op = Opcode::new(crate::category::EVENT, crate::event::POINTER_UP, 0, 5, 0, 0);
375 for _ in 0..3 {
377 push_event(event_slots, head, mask, &op).unwrap();
378 }
379 assert_eq!(read_events(event_slots, head, mask, 1).len(), 1);
381 push_event(event_slots, head, mask, &op).unwrap();
385 assert_eq!(
386 header::get_u32(head, crate::memory::OFF_EVENT_READ_CURSOR),
387 1
388 );
389 assert_eq!(
390 header::get_u32(head, crate::memory::OFF_EVENT_WRITE_CURSOR),
391 0
392 );
393
394 let drained = read_events(event_slots, head, mask, usize::MAX);
397 assert_eq!(drained, vec![op; 3]);
398 assert_eq!(
399 header::get_u32(head, crate::memory::OFF_EVENT_READ_CURSOR),
400 0
401 );
402 assert!(push_event(event_slots, head, mask, &op).is_ok());
404 assert_eq!(
405 read_events(event_slots, head, mask, usize::MAX).len(),
406 1
407 );
408 }
409}