Skip to main content

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 [`IterView`] 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/// [`IterView`] 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/// [`MatrixIter`] 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 [`MatrixIter`], 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 [`IterView`] of the current record.
59    ///
60    /// # Returns
61    /// Either the [`IterView`] 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 [`MatrixIter`] 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: IterView 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 IterView 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 {}