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) head_data_offset: Option<NonZeroU64>,
72 pub(super) current_data_offset: Option<NonZeroU64>,
73}
74
75impl<M: MemoryMap> FieldDataIterator<'_, M> {
76 pub(super) fn restart(&mut self) {
77 self.current_data_offset = self.head_data_offset;
78 }
79}
80
81impl<'a, M: MemoryMap> Iterator for FieldDataIterator<'a, M> {
82 type Item = Result<ValueGuard<'a, DataObject<&'a [u8]>>>;
83
84 fn next(&mut self) -> Option<Self::Item> {
85 let data_offset = self.current_data_offset?;
86
87 match self.journal.data_ref(data_offset) {
88 Ok(data_guard) => {
89 self.current_data_offset = data_guard.header.next_field_offset;
91 Some(Ok(data_guard))
92 }
93 Err(e) => {
94 self.current_data_offset = None;
95 Some(Err(e))
96 }
97 }
98 }
99}
100
101pub struct FieldDataOffsetIterator<'a, M: MemoryMap> {
104 pub(super) journal: &'a JournalFile<M>,
105 pub(super) current_data_offset: Option<NonZeroU64>,
106}
107
108impl<'a, M: MemoryMap> Iterator for FieldDataOffsetIterator<'a, M> {
109 type Item = Result<(NonZeroU64, ValueGuard<'a, DataObject<&'a [u8]>>)>;
110
111 fn next(&mut self) -> Option<Self::Item> {
112 let data_offset = self.current_data_offset?;
113
114 match self.journal.data_ref(data_offset) {
115 Ok(data_guard) => {
116 self.current_data_offset = data_guard.header.next_field_offset;
117 Some(Ok((data_offset, data_guard)))
118 }
119 Err(e) => {
120 self.current_data_offset = None;
121 Some(Err(e))
122 }
123 }
124 }
125}
126
127pub struct EntryDataIterator<'a, M: MemoryMap> {
129 pub(super) journal: &'a JournalFile<M>,
130 pub(super) entry_offset: Option<NonZeroU64>,
131 pub(super) current_index: usize,
132 pub(super) total_items: usize,
133}
134
135impl<'a, M: MemoryMap> Iterator for EntryDataIterator<'a, M> {
136 type Item = Result<ValueGuard<'a, DataObject<&'a [u8]>>>;
137
138 fn next(&mut self) -> Option<Self::Item> {
139 let entry_offset = self.entry_offset?;
140
141 if self.current_index >= self.total_items {
143 return None;
144 }
145
146 match self.journal.entry_ref(entry_offset) {
148 Ok(entry_guard) => {
149 let idx = self.current_index;
150 self.current_index += 1;
151
152 let data_offset = match &entry_guard.items {
153 EntryItemsType::Regular(items) => {
154 if idx >= items.len() {
155 return None;
156 }
157 items[idx].object_offset
158 }
159 EntryItemsType::Compact(items) => {
160 if idx >= items.len() {
161 return None;
162 }
163 items[idx].object_offset as u64
164 }
165 };
166
167 let data_offset = match NonZeroU64::new(data_offset) {
168 Some(offset) => offset,
169 None => {
170 self.current_index = self.total_items;
171 return Some(Err(JournalError::InvalidOffset));
172 }
173 };
174
175 drop(entry_guard);
177
178 match self.journal.data_ref(data_offset) {
180 Ok(data_guard) => Some(Ok(data_guard)),
181 Err(e) => {
182 self.current_index = self.total_items;
184 Some(Err(e))
185 }
186 }
187 }
188 Err(e) => {
189 self.current_index = self.total_items;
191 Some(Err(e))
192 }
193 }
194 }
195}