1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
#![allow(clippy::upper_case_acronyms)]
//! # Handling of slice references into the in-memory DB file

use assembly_fdb_core::file::{FDBBucketHeader, FDBColumnHeader, FDBFieldData, FDBTableHeader};
use std::convert::TryInto;

/// Invariant: length must always be a multiple of 8 bytes
#[derive(Copy, Clone)]
pub struct FDBTableHeaderSlice<'a>(pub(super) &'a [u8]);

fn read_table_header(buf: &[u8; 8]) -> FDBTableHeader {
    let (a, b) = buf.split_at(4);
    FDBTableHeader {
        table_def_header_addr: u32::from_le_bytes(a.try_into().unwrap()),
        table_data_header_addr: u32::from_le_bytes(b.try_into().unwrap()),
    }
}

impl<'a> Iterator for FDBTableHeaderSlice<'a> {
    type Item = FDBTableHeader;

    fn next(&mut self) -> Option<Self::Item> {
        if self.0.len() >= 8 {
            let (next, rest) = self.0.split_at(8);
            self.0 = rest;
            let header = read_table_header(next.try_into().unwrap());
            Some(header)
        } else {
            None
        }
    }
}

impl<'a> DoubleEndedIterator for FDBTableHeaderSlice<'a> {
    fn next_back(&mut self) -> Option<Self::Item> {
        let len = self.0.len();
        if len >= 8 {
            let (rest, next) = self.0.split_at(len - 8);
            self.0 = rest;
            let header = read_table_header(next.try_into().unwrap());
            Some(header)
        } else {
            None
        }
    }
}

/// Invariant: length must always be a multiple of 8 bytes
#[derive(Copy, Clone)]
pub struct FDBColumnHeaderSlice<'a>(pub(super) &'a [u8]);

fn read_column_header(buf: &[u8; 8]) -> FDBColumnHeader {
    let (a, b) = buf.split_at(4);
    FDBColumnHeader {
        column_data_type: u32::from_le_bytes(a.try_into().unwrap()),
        column_name_addr: u32::from_le_bytes(b.try_into().unwrap()),
    }
}

impl<'a> FDBColumnHeaderSlice<'a> {
    /// Get the len of this slice
    pub const fn len(&self) -> usize {
        self.0.len() / std::mem::size_of::<FDBColumnHeader>()
    }

    /// Check whether the slice is empty
    pub const fn is_empty(&self) -> bool {
        self.0.is_empty()
    }
}

impl<'a> Iterator for FDBColumnHeaderSlice<'a> {
    type Item = FDBColumnHeader;

    fn next(&mut self) -> Option<Self::Item> {
        if self.0.len() >= 8 {
            let (next, rest) = self.0.split_at(8);
            self.0 = rest;
            let header = read_column_header(next.try_into().unwrap());
            Some(header)
        } else {
            None
        }
    }
}

impl<'a> DoubleEndedIterator for FDBColumnHeaderSlice<'a> {
    fn next_back(&mut self) -> Option<Self::Item> {
        let len = self.0.len();
        if len >= 8 {
            let (rest, next) = self.0.split_at(len - 8);
            self.0 = rest;
            let header = read_column_header(next.try_into().unwrap());
            Some(header)
        } else {
            None
        }
    }
}

/// Invariant: length must always be a multiple of 4 bytes
#[derive(Copy, Clone)]
pub struct FDBBucketHeaderSlice<'a>(pub(super) &'a [u8]);

fn read_bucket_header(buf: &[u8; 4]) -> FDBBucketHeader {
    FDBBucketHeader {
        row_header_list_head_addr: u32::from_le_bytes(*buf),
    }
}

impl<'a> Iterator for FDBBucketHeaderSlice<'a> {
    type Item = FDBBucketHeader;

    fn next(&mut self) -> Option<Self::Item> {
        if self.0.len() >= 4 {
            let (next, rest) = self.0.split_at(4);
            self.0 = rest;
            let header = read_bucket_header(next.try_into().unwrap());
            Some(header)
        } else {
            None
        }
    }

    fn nth(&mut self, n: usize) -> Option<Self::Item> {
        let base = n * std::mem::size_of::<Self::Item>();
        let next = base + std::mem::size_of::<Self::Item>();
        if self.0.len() >= next {
            let (_skipped, start) = self.0.split_at(base);
            let (next, rest) = start.split_at(std::mem::size_of::<Self::Item>());
            self.0 = rest;
            Some(read_bucket_header(next.try_into().unwrap()))
        } else {
            self.0 = self.0.split_at(self.0.len()).1;
            None
        }
    }
}

impl<'a> DoubleEndedIterator for FDBBucketHeaderSlice<'a> {
    fn next_back(&mut self) -> Option<Self::Item> {
        let len = self.0.len();
        if len >= 4 {
            let (rest, next) = self.0.split_at(len - 4);
            self.0 = rest;
            let header = read_bucket_header(next.try_into().unwrap());
            Some(header)
        } else {
            None
        }
    }
}

/// Invariant: length must always be a multiple of 4 bytes
#[derive(Copy, Clone)]
pub struct FDBFieldDataSlice<'a>(pub(super) &'a [u8]);

fn read_field_data(buf: &[u8; 8]) -> FDBFieldData {
    let (a, b) = buf.split_at(4);
    FDBFieldData {
        data_type: u32::from_le_bytes(a.try_into().unwrap()),
        value: b.try_into().unwrap(),
    }
}

impl<'a> Iterator for FDBFieldDataSlice<'a> {
    type Item = FDBFieldData;

    fn next(&mut self) -> Option<Self::Item> {
        if self.0.len() >= 8 {
            let (next, rest) = self.0.split_at(8);
            self.0 = rest;
            let header = read_field_data(next.try_into().unwrap());
            Some(header)
        } else {
            None
        }
    }
}

impl<'a> DoubleEndedIterator for FDBFieldDataSlice<'a> {
    fn next_back(&mut self) -> Option<Self::Item> {
        let len = self.0.len();
        if len >= 8 {
            let (rest, next) = self.0.split_at(len - 8);
            self.0 = rest;
            let header = read_field_data(next.try_into().unwrap());
            Some(header)
        } else {
            None
        }
    }
}