use crate::{
metadata::tables::{
field::FieldRaw,
types::{RowWritable, TableInfoRef},
},
utils::{write_le_at, write_le_at_dyn},
Error, Result,
};
impl RowWritable for FieldRaw {
fn row_write(
&self,
data: &mut [u8],
offset: &mut usize,
_rid: u32,
sizes: &TableInfoRef,
) -> Result<()> {
let flags_u16 = u16::try_from(self.flags)
.map_err(|_| Error::LayoutFailed("Field flags value exceeds u16 range".to_string()))?;
write_le_at(data, offset, flags_u16)?;
write_le_at_dyn(data, offset, self.name, sizes.is_large_str())?;
write_le_at_dyn(data, offset, self.signature, sizes.is_large_blob())?;
Ok(())
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::{
metadata::tables::types::{RowReadable, TableInfo, TableRow},
metadata::token::Token,
};
use std::sync::Arc;
#[test]
fn test_row_size() {
let table_info = Arc::new(TableInfo::new_test(&[], false, false, false));
let size = <FieldRaw as TableRow>::row_size(&table_info);
assert_eq!(size, 6);
let table_info_large = Arc::new(TableInfo::new_test(&[], true, true, false));
let size_large = <FieldRaw as TableRow>::row_size(&table_info_large);
assert_eq!(size_large, 10);
}
#[test]
fn test_round_trip_serialization() {
let original_row = FieldRaw {
rid: 1,
token: Token::new(0x04000001),
offset: 0,
flags: 0x0006, name: 0x1234,
signature: 0x5678,
};
let table_info = Arc::new(TableInfo::new_test(&[], false, false, false));
let row_size = <FieldRaw as TableRow>::row_size(&table_info) as usize;
let mut buffer = vec![0u8; row_size];
let mut offset = 0;
original_row
.row_write(&mut buffer, &mut offset, 1, &table_info)
.expect("Serialization should succeed");
let mut read_offset = 0;
let deserialized_row = FieldRaw::row_read(&buffer, &mut read_offset, 1, &table_info)
.expect("Deserialization should succeed");
assert_eq!(deserialized_row.rid, original_row.rid);
assert_eq!(deserialized_row.flags, original_row.flags);
assert_eq!(deserialized_row.name, original_row.name);
assert_eq!(deserialized_row.signature, original_row.signature);
}
#[test]
fn test_known_binary_format() {
let data = vec![
0x06, 0x00, 0x34, 0x12, 0x78, 0x56, ];
let table_info = Arc::new(TableInfo::new_test(&[], false, false, false));
let mut read_offset = 0;
let reference_row = FieldRaw::row_read(&data, &mut read_offset, 1, &table_info)
.expect("Reading reference data should succeed");
let mut buffer = vec![0u8; data.len()];
let mut write_offset = 0;
reference_row
.row_write(&mut buffer, &mut write_offset, 1, &table_info)
.expect("Serialization should succeed");
assert_eq!(
buffer, data,
"Serialized data should match original binary format"
);
}
#[test]
fn test_field_attributes() {
let test_cases = vec![
(0x0001, "CompilerControlled"),
(0x0002, "Private"),
(0x0006, "Public"),
(0x0010, "Static"),
(0x0020, "Literal"),
(0x0040, "InitOnly"),
(0x1000, "HasDefault"),
(0x2000, "HasFieldMarshal"),
(0x0016, "Public|Static"), ];
let table_info = Arc::new(TableInfo::new_test(&[], false, false, false));
for (flags, description) in test_cases {
let field_row = FieldRaw {
rid: 1,
token: Token::new(0x04000001),
offset: 0,
flags,
name: 0x100,
signature: 0x200,
};
let row_size = <FieldRaw as TableRow>::row_size(&table_info) as usize;
let mut buffer = vec![0u8; row_size];
let mut offset = 0;
field_row
.row_write(&mut buffer, &mut offset, 1, &table_info)
.unwrap_or_else(|_| panic!("Serialization should succeed for {description}"));
let mut read_offset = 0;
let deserialized_row = FieldRaw::row_read(&buffer, &mut read_offset, 1, &table_info)
.unwrap_or_else(|_| panic!("Deserialization should succeed for {description}"));
assert_eq!(
deserialized_row.flags, field_row.flags,
"Flags should match for {description}"
);
}
}
#[test]
fn test_large_heap_serialization() {
let original_row = FieldRaw {
rid: 1,
token: Token::new(0x04000001),
offset: 0,
flags: 0x0026, name: 0x123456,
signature: 0x789ABC,
};
let table_info = Arc::new(TableInfo::new_test(&[], true, true, false));
let row_size = <FieldRaw as TableRow>::row_size(&table_info) as usize;
let mut buffer = vec![0u8; row_size];
let mut offset = 0;
original_row
.row_write(&mut buffer, &mut offset, 1, &table_info)
.expect("Large heap serialization should succeed");
let mut read_offset = 0;
let deserialized_row = FieldRaw::row_read(&buffer, &mut read_offset, 1, &table_info)
.expect("Large heap deserialization should succeed");
assert_eq!(deserialized_row.flags, original_row.flags);
assert_eq!(deserialized_row.name, original_row.name);
assert_eq!(deserialized_row.signature, original_row.signature);
}
#[test]
fn test_edge_cases() {
let zero_row = FieldRaw {
rid: 1,
token: Token::new(0x04000001),
offset: 0,
flags: 0,
name: 0,
signature: 0,
};
let table_info = Arc::new(TableInfo::new_test(&[], false, false, false));
let row_size = <FieldRaw as TableRow>::row_size(&table_info) as usize;
let mut buffer = vec![0u8; row_size];
let mut offset = 0;
zero_row
.row_write(&mut buffer, &mut offset, 1, &table_info)
.expect("Zero value serialization should succeed");
let mut read_offset = 0;
let deserialized_row = FieldRaw::row_read(&buffer, &mut read_offset, 1, &table_info)
.expect("Zero value deserialization should succeed");
assert_eq!(deserialized_row.flags, zero_row.flags);
assert_eq!(deserialized_row.name, zero_row.name);
assert_eq!(deserialized_row.signature, zero_row.signature);
}
#[test]
fn test_flags_range_validation() {
let large_flags_row = FieldRaw {
rid: 1,
token: Token::new(0x04000001),
offset: 0,
flags: 0x12345678, name: 0x100,
signature: 0x200,
};
let table_info = Arc::new(TableInfo::new_test(&[], false, false, false));
let row_size = <FieldRaw as TableRow>::row_size(&table_info) as usize;
let mut buffer = vec![0u8; row_size];
let mut offset = 0;
let result = large_flags_row.row_write(&mut buffer, &mut offset, 1, &table_info);
assert!(result.is_err());
assert!(result
.unwrap_err()
.to_string()
.contains("Field flags value exceeds u16 range"));
}
}