1#![allow(clippy::upper_case_acronyms)]
2use std::convert::{TryFrom, TryInto};
13
14use bytemuck_derive::{Pod, Zeroable};
15
16use super::common::{Context, UnknownValueType, Value, ValueType};
17
18pub mod lists;
19
20#[derive(Copy, Clone, Debug, Pod, Zeroable, PartialEq, Eq)]
21#[repr(C)]
22pub struct ArrayHeader {
24 pub count: u32,
26 pub base_offset: u32,
28}
29
30impl From<(u32, u32)> for ArrayHeader {
31 fn from((count, base_offset): (u32, u32)) -> Self {
32 Self { count, base_offset }
33 }
34}
35
36#[derive(Copy, Clone, Debug, Pod, Zeroable, PartialEq, Eq)]
40#[repr(C)]
41pub struct FDBHeader {
42 pub tables: ArrayHeader,
44}
45
46impl FDBHeader {
47 #[inline]
48 pub const fn table_headers_byte_count(&self) -> usize {
50 self.tables.count as usize * std::mem::size_of::<FDBTableHeader>()
51 }
52}
53
54#[derive(Copy, Clone, Debug, Pod, Zeroable, PartialEq, Eq)]
55#[repr(C)]
56pub struct FDBTableHeader {
62 pub table_def_header_addr: u32,
64 pub table_data_header_addr: u32,
66}
67
68#[derive(Copy, Clone, Debug, Pod, Zeroable, PartialEq, Eq)]
69#[repr(C)]
70pub struct FDBTableDefHeader {
75 pub column_count: u32,
77 pub table_name_addr: u32,
79 pub column_header_list_addr: u32,
81}
82
83impl From<(u32, u32, u32)> for FDBTableDefHeader {
84 fn from((column_count, table_name_addr, column_header_list_addr): (u32, u32, u32)) -> Self {
85 Self {
86 column_count,
87 table_name_addr,
88 column_header_list_addr,
89 }
90 }
91}
92
93impl From<[u32; 3]> for FDBTableDefHeader {
94 fn from([column_count, table_name_addr, column_header_list_addr]: [u32; 3]) -> Self {
95 Self {
96 column_count,
97 table_name_addr,
98 column_header_list_addr,
99 }
100 }
101}
102
103impl FDBTableDefHeader {
104 #[inline]
105 pub const fn column_header_list_byte_count(&self) -> usize {
107 self.column_count as usize * std::mem::size_of::<FDBColumnHeader>()
108 }
109}
110
111#[derive(Copy, Clone, Debug, Pod, Zeroable, PartialEq, Eq)]
112#[repr(C)]
113pub struct FDBColumnHeader {
118 pub column_data_type: u32,
120 pub column_name_addr: u32,
122}
123
124#[derive(Copy, Clone, Debug, Pod, Zeroable, PartialEq, Eq)]
125#[repr(C)]
126pub struct FDBTableDataHeader {
130 pub buckets: ArrayHeader,
132}
133
134impl FDBTableDataHeader {
135 #[inline]
136 pub const fn bucket_header_list_byte_count(&self) -> usize {
138 self.buckets.count as usize * std::mem::size_of::<FDBBucketHeader>()
139 }
140}
141
142#[derive(Copy, Clone, Debug, Pod, Zeroable, PartialEq, Eq)]
143#[repr(C)]
144pub struct FDBBucketHeader {
149 pub row_header_list_head_addr: u32,
151}
152
153impl From<u32> for FDBBucketHeader {
154 fn from(row_header_list_head_addr: u32) -> Self {
155 Self {
156 row_header_list_head_addr,
157 }
158 }
159}
160
161#[derive(Copy, Clone, Debug, Pod, Zeroable, PartialEq, Eq)]
162#[repr(C)]
163pub struct FDBRowHeaderListEntry {
168 pub row_header_addr: u32,
170 pub row_header_list_next_addr: u32,
172}
173
174#[derive(Copy, Clone, Debug, Pod, Zeroable, PartialEq, Eq)]
175#[repr(C)]
176pub struct FDBRowHeader {
178 pub fields: ArrayHeader,
180}
181
182impl FDBRowHeader {
183 #[inline]
184 pub const fn field_data_list_byte_count(&self) -> usize {
186 self.fields.count as usize * std::mem::size_of::<FDBFieldData>()
187 }
188}
189
190#[derive(Copy, Clone, Debug, Pod, Zeroable, PartialEq, Eq)]
191#[repr(C)]
192pub struct FDBFieldData {
194 pub data_type: u32,
196 pub value: [u8; 4],
198}
199
200#[derive(Debug, Copy, Clone, PartialEq)]
201pub struct FileContext;
203
204impl Context for FileContext {
205 type String = IndirectValue;
206 type I64 = IndirectValue;
207 type XML = IndirectValue;
208}
209
210#[derive(Debug, Copy, Clone, PartialEq, Eq)]
212pub struct IndirectValue {
213 pub addr: u32,
215}
216
217pub type FDBFieldValue = Value<FileContext>;
219
220impl TryFrom<FDBFieldData> for FDBFieldValue {
221 type Error = UnknownValueType;
222
223 fn try_from(value: FDBFieldData) -> Result<Self, Self::Error> {
224 let value_type: ValueType = value.data_type.try_into()?;
225 Ok(match value_type {
226 ValueType::Nothing => FDBFieldValue::Nothing,
227 ValueType::Integer => FDBFieldValue::Integer(i32::from_le_bytes(value.value)),
228 ValueType::Float => FDBFieldValue::Float(f32::from_le_bytes(value.value)),
229 ValueType::Text => FDBFieldValue::Text(IndirectValue {
230 addr: u32::from_le_bytes(value.value),
231 }),
232 ValueType::Boolean => FDBFieldValue::Boolean(value.value != [0; 4]),
233 ValueType::BigInt => FDBFieldValue::BigInt(IndirectValue {
234 addr: u32::from_le_bytes(value.value),
235 }),
236 ValueType::VarChar => FDBFieldValue::VarChar(IndirectValue {
237 addr: u32::from_le_bytes(value.value),
238 }),
239 })
240 }
241}
242
243#[cfg(test)]
244mod tests {
245 use super::*;
246 use std::mem;
247
248 #[test]
249 fn test_align() {
250 assert_eq!(mem::align_of::<FDBHeader>(), 4);
251 assert_eq!(mem::align_of::<FDBTableHeader>(), 4);
252 assert_eq!(mem::align_of::<FDBTableDefHeader>(), 4);
253 assert_eq!(mem::align_of::<FDBColumnHeader>(), 4);
254 assert_eq!(mem::align_of::<FDBTableDataHeader>(), 4);
255 assert_eq!(mem::align_of::<FDBBucketHeader>(), 4);
256 assert_eq!(mem::align_of::<FDBRowHeaderListEntry>(), 4);
257 assert_eq!(mem::align_of::<FDBRowHeader>(), 4);
258 assert_eq!(mem::align_of::<FDBFieldData>(), 4);
259 }
260
261 #[test]
262 fn test_size_of() {
263 assert_eq!(mem::size_of::<FDBHeader>(), 8);
264 assert_eq!(mem::size_of::<FDBTableHeader>(), 8);
265 assert_eq!(mem::size_of::<FDBTableDefHeader>(), 12);
266 assert_eq!(mem::size_of::<FDBColumnHeader>(), 8);
267 assert_eq!(mem::size_of::<FDBTableDataHeader>(), 8);
268 assert_eq!(mem::size_of::<FDBBucketHeader>(), 4);
269 assert_eq!(mem::size_of::<FDBRowHeaderListEntry>(), 8);
270 assert_eq!(mem::size_of::<FDBRowHeader>(), 8);
271 assert_eq!(mem::size_of::<FDBFieldData>(), 8);
272 }
273}