atomic_matrix/internals/looper.rs
1//! # Looper
2//!
3//! #### Iterator implementation for the matrix
4//!
5//! Looper is a iterator library that implements the Iterator trait from
6//! Rust into AtomicMatrix. It integrates the trait logic into the chaining
7//! system already present into the matrix to enable sequential traversal.
8//!
9//! Following the logic of [`MatrixHandler`] This method provides access to
10//! typed data visualization directly into [`LoopWindow`] through the method
11//! `.view_data_as::<T>()`, which returns a life time specified reference T.
12//! As well as providing the ability to read data as raw bytes.
13//!
14//! # Thread Sharing
15//!
16//! [`LoopWindow`] is [`Send`] and [`Sync`] - once obtained, it can be freely
17//! shared across threads, as it only holds references. Note however that race
18//! conditions on concurrent read/write into the underlying block are still
19//! possible and must be handled by the caller.
20//!
21//! [`Looper`] itself is not thread-safe (it holds mutable iteration state).
22//! To iterate from multiple threads, create one iterator per thread or collect
23//! data into a [`vec`] first.
24use std::sync::atomic::Ordering;
25
26use crate::handlers::*;
27use crate::matrix::core::*;
28
29/// The Iterator object implementation for the matrix.
30///
31/// It encapsules a reference to the [`MatrixHandler`] API and implements the
32/// std Iterator trait native from rust, with a few logic adaptations to run
33/// inside the matrix life-cycle.
34pub struct Looper<'a> {
35 handler_ref: &'a MatrixHandler,
36 current_offset: u32,
37 end_offset: u32,
38}
39
40/// The view object that is returned as Iterate during operations.
41///
42/// It provides operation abstractions on the [`RelativePtr`] and the
43/// [`MatrixHandler`] objects related to the context of iterating over the
44/// matrix.
45pub struct LoopWindow<'a> {
46 rel_ptr: RelativePtr<u8>,
47 handler: &'a MatrixHandler,
48}
49
50/// Default Iterator implementation on [`Looper`], with the addition
51/// of using the matrix chain as next instead of normal indexes.
52impl<'a> Iterator for Looper<'a> {
53 type Item = LoopWindow<'a>;
54
55 /// Queries the next block in the matrix based on the current item offset
56 /// related to base_ptr() + the size of the block. If the size is 0 or the
57 /// offset surpasses the boundaries of the matrix, the iteration stop.
58 /// Else, returns an [`LoopWindow`] of the current record.
59 ///
60 /// # Returns
61 /// Either the [`LoopWindow`] of the current record, or None.
62 fn next(&mut self) -> Option<Self::Item> {
63 if self.current_offset >= self.end_offset {
64 return None;
65 }
66
67 let rel_ptr = self.handler_ref.matrix().query(self.current_offset);
68 let header = unsafe { rel_ptr.resolve_header(self.handler_ref.base_ptr()) };
69
70 let size = header.size.load(Ordering::Acquire);
71 if size == 0 {
72 return None;
73 }
74
75 self.current_offset = self
76 .current_offset
77 .checked_add(size)
78 .expect("offset overflow");
79
80 Some(LoopWindow::new(rel_ptr, self.handler_ref))
81 }
82}
83
84impl<'a> Looper<'a> {
85 /// Creates a new [`Looper`] instance over the current handler.
86 ///
87 /// # Returns:
88 /// An instance of Self.
89 pub fn new(handler_ref: &'a MatrixHandler) -> Self {
90 let len = (16 + (std::mem::size_of::<AtomicMatrix>() as u32) + 15) & !15;
91 let end = handler_ref.matrix().sector_boundaries[0].load(Ordering::Acquire);
92
93 Self {
94 handler_ref,
95 current_offset: len,
96 end_offset: end,
97 }
98 }
99}
100
101// SAFETY: LoopWindow contains only one RelativePtr<u8> (an offset u32,
102// essentially imutable as design) e an imutable reference &MatrixHandler.
103// The resolution to real pointer always goes through the handler, who
104// manages its own thread safety. No mutable state is contained in the
105// Struct.
106unsafe impl<'a> Send for LoopWindow<'a> {}
107unsafe impl<'a> Sync for LoopWindow<'a> {}
108
109impl<'a> LoopWindow<'a> {
110 /// Creates a new [`LoopWindow`] instance of a record.
111 ///
112 /// # Params:
113 /// @rel_ptr: The [`RelativePtr`] of the current record. \
114 /// @handler: A reference to the handler owned by the caller.
115 ///
116 /// # Returns:
117 /// An instance of Self.
118 pub fn new(rel_ptr: RelativePtr<u8>, handler: &'a MatrixHandler) -> Self {
119 Self { rel_ptr, handler }
120 }
121
122 /// Returns a reference to the current record data typed as T.
123 pub fn view_data_as<T>(&self) -> &'a T {
124 let block = Block::<T>::from_offset(self.rel_ptr.offset());
125 let res = unsafe { self.handler.read(&block) };
126
127 res
128 }
129
130 /// Returns a reference to the current record data as a raw pointer.
131 pub fn view_data_raw(&self) -> &'a [u8] {
132 unsafe {
133 let data_ptr = self.rel_ptr.resolve(self.handler.base_ptr());
134 let header = self.view_header();
135 let size = header.size.load(Ordering::Acquire) - 32 - 16;
136 std::slice::from_raw_parts(data_ptr, size as usize)
137 }
138 }
139
140 /// Returns a reference to the header of this record
141 pub fn view_header(&self) -> &'a BlockHeader {
142 unsafe { self.rel_ptr.resolve_header(self.handler.base_ptr()) }
143 }
144
145 /// Returns the offset of the current record
146 pub fn view_offset(&self) -> u32 {
147 self.rel_ptr.offset()
148 }
149}
150
151pub mod macros {}