journal_core/file/
file_iterators.rs1use super::file::JournalFile;
2use super::mmap::MemoryMap;
3use super::object::*;
4use crate::error::{JournalError, Result};
5use crate::file::value_guard::ValueGuard;
6use std::num::NonZeroU64;
7
8pub struct FieldIterator<'a, M: MemoryMap> {
10 pub(super) journal: &'a JournalFile<M>,
11 pub(super) field_hash_table: Option<FieldHashTable<&'a [u8]>>,
12 pub(super) current_bucket_index: usize,
13 pub(super) next_field_offset: Option<NonZeroU64>,
14}
15
16impl<M: MemoryMap> FieldIterator<'_, M> {
17 pub(super) fn advance_to_next_nonempty_bucket(&mut self) {
19 let Some(hash_table) = &self.field_hash_table else {
21 return;
22 };
23
24 let items = &hash_table.items;
25
26 while self.current_bucket_index < items.len() {
28 let bucket = items[self.current_bucket_index];
29 if bucket.head_hash_offset.is_some() {
30 self.next_field_offset = bucket.head_hash_offset;
31 return;
32 }
33 self.current_bucket_index += 1;
34 }
35
36 self.next_field_offset = None;
38 }
39}
40
41impl<'a, M: MemoryMap> Iterator for FieldIterator<'a, M> {
42 type Item = Result<ValueGuard<'a, FieldObject<&'a [u8]>>>;
43
44 fn next(&mut self) -> Option<Self::Item> {
45 let offset = self.next_field_offset?;
46
47 match self.journal.field_ref(offset) {
48 Ok(field_guard) => {
49 self.next_field_offset = field_guard.header.next_hash_offset;
51
52 if self.next_field_offset.is_none() {
54 self.current_bucket_index += 1;
55 self.advance_to_next_nonempty_bucket();
56 }
57
58 Some(Ok(field_guard))
59 }
60 Err(e) => {
61 self.next_field_offset = None;
62 Some(Err(e))
63 }
64 }
65 }
66}
67
68pub struct FieldDataIterator<'a, M: MemoryMap> {
70 pub(super) journal: &'a JournalFile<M>,
71 pub(super) current_data_offset: Option<NonZeroU64>,
72}
73
74impl<'a, M: MemoryMap> Iterator for FieldDataIterator<'a, M> {
75 type Item = Result<ValueGuard<'a, DataObject<&'a [u8]>>>;
76
77 fn next(&mut self) -> Option<Self::Item> {
78 let data_offset = self.current_data_offset?;
79
80 match self.journal.data_ref(data_offset) {
81 Ok(data_guard) => {
82 self.current_data_offset = data_guard.header.next_field_offset;
84 Some(Ok(data_guard))
85 }
86 Err(e) => {
87 self.current_data_offset = None;
88 Some(Err(e))
89 }
90 }
91 }
92}
93
94pub struct FieldDataOffsetIterator<'a, M: MemoryMap> {
97 pub(super) journal: &'a JournalFile<M>,
98 pub(super) current_data_offset: Option<NonZeroU64>,
99}
100
101impl<'a, M: MemoryMap> Iterator for FieldDataOffsetIterator<'a, M> {
102 type Item = Result<(NonZeroU64, ValueGuard<'a, DataObject<&'a [u8]>>)>;
103
104 fn next(&mut self) -> Option<Self::Item> {
105 let data_offset = self.current_data_offset?;
106
107 match self.journal.data_ref(data_offset) {
108 Ok(data_guard) => {
109 self.current_data_offset = data_guard.header.next_field_offset;
110 Some(Ok((data_offset, data_guard)))
111 }
112 Err(e) => {
113 self.current_data_offset = None;
114 Some(Err(e))
115 }
116 }
117 }
118}
119
120pub struct EntryDataIterator<'a, M: MemoryMap> {
122 pub(super) journal: &'a JournalFile<M>,
123 pub(super) entry_offset: Option<NonZeroU64>,
124 pub(super) current_index: usize,
125 pub(super) total_items: usize,
126}
127
128impl<'a, M: MemoryMap> Iterator for EntryDataIterator<'a, M> {
129 type Item = Result<ValueGuard<'a, DataObject<&'a [u8]>>>;
130
131 fn next(&mut self) -> Option<Self::Item> {
132 let entry_offset = self.entry_offset?;
133
134 if self.current_index >= self.total_items {
136 return None;
137 }
138
139 match self.journal.entry_ref(entry_offset) {
141 Ok(entry_guard) => {
142 let idx = self.current_index;
143 self.current_index += 1;
144
145 let data_offset = match &entry_guard.items {
146 EntryItemsType::Regular(items) => {
147 if idx >= items.len() {
148 return None;
149 }
150 items[idx].object_offset
151 }
152 EntryItemsType::Compact(items) => {
153 if idx >= items.len() {
154 return None;
155 }
156 items[idx].object_offset as u64
157 }
158 };
159
160 let data_offset = match NonZeroU64::new(data_offset) {
161 Some(offset) => offset,
162 None => {
163 self.current_index = self.total_items;
164 return Some(Err(JournalError::InvalidOffset));
165 }
166 };
167
168 drop(entry_guard);
170
171 match self.journal.data_ref(data_offset) {
173 Ok(data_guard) => Some(Ok(data_guard)),
174 Err(e) => {
175 self.current_index = self.total_items;
177 Some(Err(e))
178 }
179 }
180 }
181 Err(e) => {
182 self.current_index = self.total_items;
184 Some(Err(e))
185 }
186 }
187 }
188}