mirror of
https://github.com/Squareville/Assembly.git
synced 2026-01-06 08:59:35 -06:00
246 lines
7.4 KiB
Rust
246 lines
7.4 KiB
Rust
#![allow(clippy::upper_case_acronyms)]
|
|
use std::convert::TryFrom;
|
|
|
|
use crate::file::{
|
|
FDBBucketHeader, FDBColumnHeader, FDBFieldValue, FDBHeader, FDBRowHeader,
|
|
FDBRowHeaderListEntry, FDBTableDataHeader, FDBTableDefHeader, FDBTableHeader, IndirectValue,
|
|
};
|
|
use crate::{common::ValueType, file::ArrayHeader};
|
|
use assembly_core::buffer::{MinimallyAligned, Repr, LEU32};
|
|
|
|
/// An FDB header usable for unaligned reads
|
|
#[repr(C, align(1))]
|
|
pub struct FDBHeaderC {
|
|
pub(super) table_count: LEU32,
|
|
pub(super) table_header_list_addr: LEU32,
|
|
}
|
|
|
|
/// An FDB table header usable for unaligned reads
|
|
#[repr(C, align(1))]
|
|
pub struct FDBTableHeaderC {
|
|
pub(super) table_def_header_addr: LEU32,
|
|
pub(super) table_data_header_addr: LEU32,
|
|
}
|
|
|
|
/// An FDB table definition header usable for unaligned reads
|
|
#[repr(C, align(1))]
|
|
pub struct FDBTableDefHeaderC {
|
|
pub(super) column_count: LEU32,
|
|
pub(super) table_name_addr: LEU32,
|
|
pub(super) column_header_list_addr: LEU32,
|
|
}
|
|
|
|
/// An FDB column header usable for unaligned reads
|
|
#[repr(C, align(1))]
|
|
pub struct FDBColumnHeaderC {
|
|
pub(super) column_data_type: LEU32,
|
|
pub(super) column_name_addr: LEU32,
|
|
}
|
|
|
|
/// An FDB table data header usable for unaligned reads
|
|
#[repr(C, align(1))]
|
|
pub struct FDBTableDataHeaderC {
|
|
pub(super) bucket_count: LEU32,
|
|
pub(super) bucket_header_list_addr: LEU32,
|
|
}
|
|
|
|
/// An FDB bucket header usable for unaligned reads
|
|
#[repr(C, align(1))]
|
|
pub struct FDBBucketHeaderC {
|
|
pub(super) row_header_list_head_addr: LEU32,
|
|
}
|
|
|
|
/// An FDB row header list entry usable for unaligned reads
|
|
#[repr(C, align(1))]
|
|
#[derive(Debug)]
|
|
pub struct FDBRowHeaderListEntryC {
|
|
pub(super) row_header_addr: LEU32,
|
|
pub(super) row_header_list_next_addr: LEU32,
|
|
}
|
|
|
|
/// An FDB row header usable for unaligned reads
|
|
#[repr(C, align(1))]
|
|
pub struct FDBRowHeaderC {
|
|
pub(super) field_count: LEU32,
|
|
pub(super) field_data_list_addr: LEU32,
|
|
}
|
|
|
|
/// An FDB field value usable for unaligned reads
|
|
#[repr(C, align(1))]
|
|
pub struct FDBFieldValueC(pub(super) [u8; 4]);
|
|
|
|
/// An FDB field data usable for unaligned reads
|
|
#[repr(C, align(1))]
|
|
pub struct FDBFieldDataC {
|
|
pub(super) data_type: LEU32,
|
|
pub(super) value: FDBFieldValueC,
|
|
}
|
|
|
|
unsafe impl MinimallyAligned for FDBHeaderC {}
|
|
|
|
impl Repr for FDBHeaderC {
|
|
type Value = FDBHeader;
|
|
fn extract(&self) -> Self::Value {
|
|
FDBHeader {
|
|
tables: ArrayHeader {
|
|
count: self.table_count.extract(),
|
|
base_offset: self.table_header_list_addr.extract(),
|
|
},
|
|
}
|
|
}
|
|
}
|
|
|
|
unsafe impl MinimallyAligned for FDBTableHeaderC {}
|
|
|
|
impl Repr for FDBTableHeaderC {
|
|
type Value = FDBTableHeader;
|
|
fn extract(&self) -> Self::Value {
|
|
FDBTableHeader {
|
|
table_def_header_addr: self.table_def_header_addr.extract(),
|
|
table_data_header_addr: self.table_data_header_addr.extract(),
|
|
}
|
|
}
|
|
}
|
|
|
|
unsafe impl MinimallyAligned for FDBTableDefHeaderC {}
|
|
|
|
impl Repr for FDBTableDefHeaderC {
|
|
type Value = FDBTableDefHeader;
|
|
fn extract(&self) -> Self::Value {
|
|
FDBTableDefHeader {
|
|
column_count: self.column_count.extract(),
|
|
table_name_addr: self.table_name_addr.extract(),
|
|
column_header_list_addr: self.column_header_list_addr.extract(),
|
|
}
|
|
}
|
|
}
|
|
|
|
unsafe impl MinimallyAligned for FDBTableDataHeaderC {}
|
|
|
|
impl Repr for FDBTableDataHeaderC {
|
|
type Value = FDBTableDataHeader;
|
|
fn extract(&self) -> Self::Value {
|
|
FDBTableDataHeader {
|
|
buckets: ArrayHeader {
|
|
count: self.bucket_count.extract(),
|
|
base_offset: self.bucket_header_list_addr.extract(),
|
|
},
|
|
}
|
|
}
|
|
}
|
|
|
|
unsafe impl MinimallyAligned for FDBColumnHeaderC {}
|
|
|
|
impl Repr for FDBColumnHeaderC {
|
|
type Value = FDBColumnHeader;
|
|
fn extract(&self) -> Self::Value {
|
|
FDBColumnHeader {
|
|
column_data_type: self.column_data_type.extract(),
|
|
column_name_addr: self.column_name_addr.extract(),
|
|
}
|
|
}
|
|
}
|
|
|
|
unsafe impl MinimallyAligned for FDBBucketHeaderC {}
|
|
|
|
impl Repr for FDBBucketHeaderC {
|
|
type Value = FDBBucketHeader;
|
|
fn extract(&self) -> Self::Value {
|
|
FDBBucketHeader {
|
|
row_header_list_head_addr: self.row_header_list_head_addr.extract(),
|
|
}
|
|
}
|
|
}
|
|
|
|
unsafe impl MinimallyAligned for FDBRowHeaderListEntryC {}
|
|
|
|
impl Repr for FDBRowHeaderListEntryC {
|
|
type Value = FDBRowHeaderListEntry;
|
|
fn extract(&self) -> Self::Value {
|
|
FDBRowHeaderListEntry {
|
|
row_header_addr: self.row_header_addr.extract(),
|
|
row_header_list_next_addr: self.row_header_list_next_addr.extract(),
|
|
}
|
|
}
|
|
}
|
|
|
|
unsafe impl MinimallyAligned for FDBRowHeaderC {}
|
|
|
|
impl Repr for FDBRowHeaderC {
|
|
type Value = FDBRowHeader;
|
|
fn extract(&self) -> Self::Value {
|
|
FDBRowHeader {
|
|
fields: ArrayHeader {
|
|
count: self.field_count.extract(),
|
|
base_offset: self.field_data_list_addr.extract(),
|
|
},
|
|
}
|
|
}
|
|
}
|
|
|
|
unsafe impl MinimallyAligned for FDBFieldDataC {}
|
|
|
|
impl Repr for FDBFieldDataC {
|
|
type Value = FDBFieldValue;
|
|
fn extract(&self) -> Self::Value {
|
|
// FIXME: Remove unwrap
|
|
let data_type = ValueType::try_from(self.data_type.extract()).unwrap();
|
|
match data_type {
|
|
ValueType::Nothing => FDBFieldValue::Nothing,
|
|
ValueType::Integer => FDBFieldValue::Integer(i32::from_le_bytes(self.value.0)),
|
|
ValueType::Float => FDBFieldValue::Float(f32::from_le_bytes(self.value.0)),
|
|
ValueType::Text => FDBFieldValue::Text(IndirectValue {
|
|
addr: u32::from_le_bytes(self.value.0),
|
|
}),
|
|
ValueType::Boolean => FDBFieldValue::Boolean(self.value.0 != [0, 0, 0, 0]),
|
|
ValueType::BigInt => FDBFieldValue::BigInt(IndirectValue {
|
|
addr: u32::from_le_bytes(self.value.0),
|
|
}),
|
|
ValueType::VarChar => FDBFieldValue::VarChar(IndirectValue {
|
|
addr: u32::from_le_bytes(self.value.0),
|
|
}),
|
|
}
|
|
}
|
|
}
|
|
|
|
#[cfg(test)]
|
|
mod tests {
|
|
use super::*;
|
|
|
|
#[test]
|
|
fn check_align_of() {
|
|
assert_eq!(1, std::mem::align_of::<FDBHeaderC>());
|
|
assert_eq!(1, std::mem::align_of::<FDBTableHeaderC>());
|
|
assert_eq!(1, std::mem::align_of::<FDBTableDefHeaderC>());
|
|
assert_eq!(1, std::mem::align_of::<FDBTableDataHeaderC>());
|
|
assert_eq!(1, std::mem::align_of::<FDBColumnHeaderC>());
|
|
assert_eq!(1, std::mem::align_of::<FDBBucketHeaderC>());
|
|
assert_eq!(1, std::mem::align_of::<FDBRowHeaderListEntryC>());
|
|
assert_eq!(1, std::mem::align_of::<FDBRowHeaderC>());
|
|
assert_eq!(1, std::mem::align_of::<FDBFieldDataC>());
|
|
assert_eq!(1, std::mem::align_of::<FDBFieldValueC>());
|
|
}
|
|
|
|
#[test]
|
|
fn check_unaligned_read() {
|
|
let test: &[u32] = &[0x00000000, 0x00000800, 0x00000000];
|
|
let buffer: &[u8] = unsafe { std::slice::from_raw_parts(test.as_ptr() as *const u8, 12) };
|
|
|
|
// Is this actually unaligned?
|
|
let base = unsafe { buffer.as_ptr().offset(1) };
|
|
assert_eq!(1, base as usize % 4);
|
|
|
|
// Can we successfully get the value?
|
|
let header = unsafe { &*(base as *const FDBHeaderC) };
|
|
assert_eq!(
|
|
header.extract(),
|
|
FDBHeader {
|
|
tables: ArrayHeader {
|
|
count: 0,
|
|
base_offset: 8,
|
|
}
|
|
}
|
|
);
|
|
}
|
|
}
|