assembly_data/fdb/file/
mod.rs

1#![allow(clippy::upper_case_acronyms)]
2//! The structures, as they are serialized
3//!
4//! This module contains the low-level structs that make up the FDB file. These
5//! structures are annotated with `#[repr(C)]` and can be used to read directly
6//! from a memory-mapped file on a little-endian machine.
7//!
8//! Not all values of these structs are valid for FDB files, but all well-formed
9//! FDB-files can be represented by these values. Most importantly, the
10//! [`FDBColumnHeader::column_data_type`] only has a limited amount of defined values but
11//! covers the whole 32 bits.
12use 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)]
22/// The basic format of an array reference
23pub struct ArrayHeader {
24    /// The number of entries in the array
25    pub count: u32,
26    /// The offset of the start of the array
27    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/// The header of the database file.
37///
38/// This struct exists only once at index 0 of the file.
39#[derive(Copy, Clone, Debug, Pod, Zeroable, PartialEq, Eq)]
40#[repr(C)]
41pub struct FDBHeader {
42    /// The [`FDBTableHeader`] array.
43    pub tables: ArrayHeader,
44}
45
46impl FDBHeader {
47    #[inline]
48    /// Returns the length in bytes of the TableHeader array.
49    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)]
56/// The header of a table.
57///
58/// This struct is used in the global TableHeader list and contains
59/// the offsets of the two structures that define the definition and
60/// content of the tables.
61pub struct FDBTableHeader {
62    /// The offset of this table definition header.
63    pub table_def_header_addr: u32,
64    /// The offset of the table data header.
65    pub table_data_header_addr: u32,
66}
67
68#[derive(Copy, Clone, Debug, Pod, Zeroable, PartialEq, Eq)]
69#[repr(C)]
70/// The header of a table definition
71///
72/// This struct exists once per table and contains links to information
73/// on the name of the table and the names and data types of the columns.
74pub struct FDBTableDefHeader {
75    /// The number of columns in this table.
76    pub column_count: u32,
77    /// The offset of the (null-terminated) name of this table
78    pub table_name_addr: u32,
79    /// The offset of the array of [`FDBColumnHeader`]s
80    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    /// Returns the expected byte length of the referenced [`FDBColumnHeader`] array.
106    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)]
113/// The header of a column (field-of-row) definition
114///
115/// This struct contains information on the name and data type of a column.
116/// It is always an element of the array pointed to by the [`FDBTableDefHeader`].
117pub struct FDBColumnHeader {
118    /// The numeric identifier of the data type.
119    pub column_data_type: u32,
120    /// The offset of the (null-terminated) name.
121    pub column_name_addr: u32,
122}
123
124#[derive(Copy, Clone, Debug, Pod, Zeroable, PartialEq, Eq)]
125#[repr(C)]
126/// The header of a table data block
127///
128/// It contains a reference to the array of buckets that hold the row data.
129pub struct FDBTableDataHeader {
130    /// The buckets.
131    pub buckets: ArrayHeader,
132}
133
134impl FDBTableDataHeader {
135    #[inline]
136    /// Returns the expected byte length of the [`FDBBucketHeader`] array.
137    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)]
144/// The header of a single bucket.
145///
146/// A bucket is a linked list of references to rows that all have the same
147/// primary key hash.
148pub struct FDBBucketHeader {
149    /// Offset of the first element of the linked list or 0xffffffff.
150    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)]
163/// One entry of the linked list of references to rows.
164///
165/// This struct always contains a reference to a row and may
166/// point to another entry in the linked list.
167pub struct FDBRowHeaderListEntry {
168    /// The offset of the row header.
169    pub row_header_addr: u32,
170    /// The offset of the next list entry or `0`.
171    pub row_header_list_next_addr: u32,
172}
173
174#[derive(Copy, Clone, Debug, Pod, Zeroable, PartialEq, Eq)]
175#[repr(C)]
176/// The header for a single row
177pub struct FDBRowHeader {
178    /// The fields in this row
179    pub fields: ArrayHeader,
180}
181
182impl FDBRowHeader {
183    #[inline]
184    /// Returns the expected byte length of the [`FDBFieldData`] array.
185    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)]
192/// The type and value of a row field.
193pub struct FDBFieldData {
194    /// The data type.
195    pub data_type: u32,
196    /// The bytes that specify the value.
197    pub value: [u8; 4],
198}
199
200#[derive(Debug, Copy, Clone, PartialEq)]
201/// The `common::Context` for used to make `file::FDBFieldValue`
202pub struct FileContext;
203
204impl Context for FileContext {
205    type String = IndirectValue;
206    type I64 = IndirectValue;
207    type XML = IndirectValue;
208}
209
210/// An indirect value in the file
211#[derive(Debug, Copy, Clone, PartialEq, Eq)]
212pub struct IndirectValue {
213    /// The base of the value
214    pub addr: u32,
215}
216
217/// A database field value repr
218pub 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}