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