assembly_fdb/ro/
slice.rs

1#![allow(clippy::upper_case_acronyms)]
2//! # Handling of slice references into the in-memory DB file
3
4use assembly_fdb_core::file::{FDBBucketHeader, FDBColumnHeader, FDBFieldData, FDBTableHeader};
5use std::convert::TryInto;
6
7/// Invariant: length must always be a multiple of 8 bytes
8#[derive(Copy, Clone)]
9pub struct FDBTableHeaderSlice<'a>(pub(super) &'a [u8]);
10
11fn read_table_header(buf: &[u8; 8]) -> FDBTableHeader {
12    let (a, b) = buf.split_at(4);
13    FDBTableHeader {
14        table_def_header_addr: u32::from_le_bytes(a.try_into().unwrap()),
15        table_data_header_addr: u32::from_le_bytes(b.try_into().unwrap()),
16    }
17}
18
19impl<'a> Iterator for FDBTableHeaderSlice<'a> {
20    type Item = FDBTableHeader;
21
22    fn next(&mut self) -> Option<Self::Item> {
23        if self.0.len() >= 8 {
24            let (next, rest) = self.0.split_at(8);
25            self.0 = rest;
26            let header = read_table_header(next.try_into().unwrap());
27            Some(header)
28        } else {
29            None
30        }
31    }
32}
33
34impl<'a> DoubleEndedIterator for FDBTableHeaderSlice<'a> {
35    fn next_back(&mut self) -> Option<Self::Item> {
36        let len = self.0.len();
37        if len >= 8 {
38            let (rest, next) = self.0.split_at(len - 8);
39            self.0 = rest;
40            let header = read_table_header(next.try_into().unwrap());
41            Some(header)
42        } else {
43            None
44        }
45    }
46}
47
48/// Invariant: length must always be a multiple of 8 bytes
49#[derive(Copy, Clone)]
50pub struct FDBColumnHeaderSlice<'a>(pub(super) &'a [u8]);
51
52fn read_column_header(buf: &[u8; 8]) -> FDBColumnHeader {
53    let (a, b) = buf.split_at(4);
54    FDBColumnHeader {
55        column_data_type: u32::from_le_bytes(a.try_into().unwrap()),
56        column_name_addr: u32::from_le_bytes(b.try_into().unwrap()),
57    }
58}
59
60impl<'a> FDBColumnHeaderSlice<'a> {
61    /// Get the len of this slice
62    pub const fn len(&self) -> usize {
63        self.0.len() / std::mem::size_of::<FDBColumnHeader>()
64    }
65
66    /// Check whether the slice is empty
67    pub const fn is_empty(&self) -> bool {
68        self.0.is_empty()
69    }
70}
71
72impl<'a> Iterator for FDBColumnHeaderSlice<'a> {
73    type Item = FDBColumnHeader;
74
75    fn next(&mut self) -> Option<Self::Item> {
76        if self.0.len() >= 8 {
77            let (next, rest) = self.0.split_at(8);
78            self.0 = rest;
79            let header = read_column_header(next.try_into().unwrap());
80            Some(header)
81        } else {
82            None
83        }
84    }
85}
86
87impl<'a> DoubleEndedIterator for FDBColumnHeaderSlice<'a> {
88    fn next_back(&mut self) -> Option<Self::Item> {
89        let len = self.0.len();
90        if len >= 8 {
91            let (rest, next) = self.0.split_at(len - 8);
92            self.0 = rest;
93            let header = read_column_header(next.try_into().unwrap());
94            Some(header)
95        } else {
96            None
97        }
98    }
99}
100
101/// Invariant: length must always be a multiple of 4 bytes
102#[derive(Copy, Clone)]
103pub struct FDBBucketHeaderSlice<'a>(pub(super) &'a [u8]);
104
105fn read_bucket_header(buf: &[u8; 4]) -> FDBBucketHeader {
106    FDBBucketHeader {
107        row_header_list_head_addr: u32::from_le_bytes(*buf),
108    }
109}
110
111impl<'a> Iterator for FDBBucketHeaderSlice<'a> {
112    type Item = FDBBucketHeader;
113
114    fn next(&mut self) -> Option<Self::Item> {
115        if self.0.len() >= 4 {
116            let (next, rest) = self.0.split_at(4);
117            self.0 = rest;
118            let header = read_bucket_header(next.try_into().unwrap());
119            Some(header)
120        } else {
121            None
122        }
123    }
124
125    fn nth(&mut self, n: usize) -> Option<Self::Item> {
126        let base = n * std::mem::size_of::<Self::Item>();
127        let next = base + std::mem::size_of::<Self::Item>();
128        if self.0.len() >= next {
129            let (_skipped, start) = self.0.split_at(base);
130            let (next, rest) = start.split_at(std::mem::size_of::<Self::Item>());
131            self.0 = rest;
132            Some(read_bucket_header(next.try_into().unwrap()))
133        } else {
134            self.0 = self.0.split_at(self.0.len()).1;
135            None
136        }
137    }
138}
139
140impl<'a> DoubleEndedIterator for FDBBucketHeaderSlice<'a> {
141    fn next_back(&mut self) -> Option<Self::Item> {
142        let len = self.0.len();
143        if len >= 4 {
144            let (rest, next) = self.0.split_at(len - 4);
145            self.0 = rest;
146            let header = read_bucket_header(next.try_into().unwrap());
147            Some(header)
148        } else {
149            None
150        }
151    }
152}
153
154/// Invariant: length must always be a multiple of 4 bytes
155#[derive(Copy, Clone)]
156pub struct FDBFieldDataSlice<'a>(pub(super) &'a [u8]);
157
158fn read_field_data(buf: &[u8; 8]) -> FDBFieldData {
159    let (a, b) = buf.split_at(4);
160    FDBFieldData {
161        data_type: u32::from_le_bytes(a.try_into().unwrap()),
162        value: b.try_into().unwrap(),
163    }
164}
165
166impl<'a> Iterator for FDBFieldDataSlice<'a> {
167    type Item = FDBFieldData;
168
169    fn next(&mut self) -> Option<Self::Item> {
170        if self.0.len() >= 8 {
171            let (next, rest) = self.0.split_at(8);
172            self.0 = rest;
173            let header = read_field_data(next.try_into().unwrap());
174            Some(header)
175        } else {
176            None
177        }
178    }
179}
180
181impl<'a> DoubleEndedIterator for FDBFieldDataSlice<'a> {
182    fn next_back(&mut self) -> Option<Self::Item> {
183        let len = self.0.len();
184        if len >= 8 {
185            let (rest, next) = self.0.split_at(len - 8);
186            self.0 = rest;
187            let header = read_field_data(next.try_into().unwrap());
188            Some(header)
189        } else {
190            None
191        }
192    }
193}