use crate::{
metadata::tables::{
event::EventRaw,
types::{CodedIndexType, RowWritable, TableInfoRef},
},
utils::{write_le_at, write_le_at_dyn},
Error, Result,
};
impl RowWritable for EventRaw {
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("Event 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())?;
let encoded_index = sizes.encode_coded_index(
self.event_type.tag,
self.event_type.row,
CodedIndexType::TypeDefOrRef,
)?;
write_le_at_dyn(
data,
offset,
encoded_index,
sizes.coded_index_bits(CodedIndexType::TypeDefOrRef) > 16,
)?;
Ok(())
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::{
metadata::tables::{
types::{RowReadable, TableInfo, TableRow},
CodedIndex, TableId,
},
metadata::token::Token,
};
use std::sync::Arc;
#[test]
fn test_row_size() {
let table_info = Arc::new(TableInfo::new_test(
&[
(TableId::TypeDef, 100),
(TableId::TypeRef, 100),
(TableId::TypeSpec, 100),
],
false,
false,
false,
));
let size = <EventRaw as TableRow>::row_size(&table_info);
assert_eq!(size, 6);
let table_info_large = Arc::new(TableInfo::new_test(
&[
(TableId::TypeDef, 70000),
(TableId::TypeRef, 70000),
(TableId::TypeSpec, 70000),
],
true,
false,
false,
));
let size_large = <EventRaw as TableRow>::row_size(&table_info_large);
assert_eq!(size_large, 10);
}
#[test]
fn test_round_trip_serialization() {
let original_row = EventRaw {
rid: 1,
token: Token::new(0x14000001),
offset: 0,
flags: 0x0101,
name: 0x0202,
event_type: CodedIndex::new(TableId::TypeDef, 192, CodedIndexType::TypeDefOrRef),
};
let table_info = Arc::new(TableInfo::new_test(
&[
(TableId::TypeDef, 1000),
(TableId::TypeRef, 1000),
(TableId::TypeSpec, 1000),
],
false,
false,
false,
));
let row_size = <EventRaw 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 = EventRaw::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.event_type, original_row.event_type);
assert_eq!(offset, row_size, "Offset should match expected row size");
}
#[test]
fn test_known_binary_format_small() {
let data = vec![
0x01, 0x01, 0x02, 0x02, 0x00, 0x03, ];
let table_info = Arc::new(TableInfo::new_test(
&[
(TableId::TypeDef, 1),
(TableId::TypeRef, 1),
(TableId::TypeSpec, 1),
],
false,
false,
false,
));
let mut read_offset = 0;
let reference_row = EventRaw::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_known_binary_format_large() {
let data = vec![
0x01, 0x01, 0x02, 0x02, 0x02, 0x02, 0x00, 0x03, 0x03, 0x03, ];
let table_info = Arc::new(TableInfo::new_test(
&[
(TableId::TypeDef, u16::MAX as u32 + 3),
(TableId::TypeRef, 1),
(TableId::TypeSpec, 1),
],
true,
false,
false,
));
let mut read_offset = 0;
let reference_row = EventRaw::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_event_attributes() {
let test_cases = vec![
(0x0000, "None"),
(0x0200, "SpecialName"),
(0x0400, "RTSpecialName"),
(0x0600, "SpecialName|RTSpecialName"),
];
let table_info = Arc::new(TableInfo::new_test(
&[
(TableId::TypeDef, 100),
(TableId::TypeRef, 100),
(TableId::TypeSpec, 100),
],
false,
false,
false,
));
for (flags, description) in test_cases {
let event_row = EventRaw {
rid: 1,
token: Token::new(0x14000001),
offset: 0,
flags,
name: 0x100,
event_type: CodedIndex::new(TableId::TypeDef, 1, CodedIndexType::TypeDefOrRef),
};
let row_size = <EventRaw as TableRow>::row_size(&table_info) as usize;
let mut buffer = vec![0u8; row_size];
let mut offset = 0;
event_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 = EventRaw::row_read(&buffer, &mut read_offset, 1, &table_info)
.unwrap_or_else(|_| panic!("Deserialization should succeed for {description}"));
assert_eq!(
deserialized_row.flags, event_row.flags,
"Flags should match for {description}"
);
}
}
#[test]
fn test_coded_index_types() {
let test_cases = vec![
(TableId::TypeDef, "TypeDef"),
(TableId::TypeRef, "TypeRef"),
(TableId::TypeSpec, "TypeSpec"),
];
let table_info = Arc::new(TableInfo::new_test(
&[
(TableId::TypeDef, 100),
(TableId::TypeRef, 100),
(TableId::TypeSpec, 100),
],
false,
false,
false,
));
for (table_id, description) in test_cases {
let event_row = EventRaw {
rid: 1,
token: Token::new(0x14000001),
offset: 0,
flags: 0x0200, name: 0x100,
event_type: CodedIndex::new(table_id, 1, CodedIndexType::TypeDefOrRef),
};
let row_size = <EventRaw as TableRow>::row_size(&table_info) as usize;
let mut buffer = vec![0u8; row_size];
let mut offset = 0;
event_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 = EventRaw::row_read(&buffer, &mut read_offset, 1, &table_info)
.unwrap_or_else(|_| panic!("Deserialization should succeed for {description}"));
assert_eq!(
deserialized_row.event_type.tag, event_row.event_type.tag,
"Event type tag should match for {description}"
);
}
}
#[test]
fn test_large_heap_serialization() {
let original_row = EventRaw {
rid: 1,
token: Token::new(0x14000001),
offset: 0,
flags: 0x0600, name: 0x123456,
event_type: CodedIndex::new(TableId::TypeRef, 0x8000, CodedIndexType::TypeDefOrRef),
};
let table_info = Arc::new(TableInfo::new_test(
&[
(TableId::TypeDef, 70000),
(TableId::TypeRef, 70000),
(TableId::TypeSpec, 70000),
],
true,
false,
false,
));
let row_size = <EventRaw 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 = EventRaw::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.event_type, original_row.event_type);
}
#[test]
fn test_edge_cases() {
let minimal_event = EventRaw {
rid: 1,
token: Token::new(0x14000001),
offset: 0,
flags: 0, name: 0, event_type: CodedIndex::new(TableId::TypeDef, 1, CodedIndexType::TypeDefOrRef), };
let table_info = Arc::new(TableInfo::new_test(
&[
(TableId::TypeDef, 100),
(TableId::TypeRef, 100),
(TableId::TypeSpec, 100),
],
false,
false,
false,
));
let row_size = <EventRaw as TableRow>::row_size(&table_info) as usize;
let mut buffer = vec![0u8; row_size];
let mut offset = 0;
minimal_event
.row_write(&mut buffer, &mut offset, 1, &table_info)
.expect("Minimal event serialization should succeed");
let mut read_offset = 0;
let deserialized_row = EventRaw::row_read(&buffer, &mut read_offset, 1, &table_info)
.expect("Minimal event deserialization should succeed");
assert_eq!(deserialized_row.flags, minimal_event.flags);
assert_eq!(deserialized_row.name, minimal_event.name);
assert_eq!(deserialized_row.event_type, minimal_event.event_type);
}
#[test]
fn test_flags_range_validation() {
let large_flags_row = EventRaw {
rid: 1,
token: Token::new(0x14000001),
offset: 0,
flags: 0x12345678, name: 0x100,
event_type: CodedIndex::new(TableId::TypeDef, 1, CodedIndexType::TypeDefOrRef),
};
let table_info = Arc::new(TableInfo::new_test(
&[
(TableId::TypeDef, 100),
(TableId::TypeRef, 100),
(TableId::TypeSpec, 100),
],
false,
false,
false,
));
let row_size = <EventRaw 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("Event flags value exceeds u16 range"));
}
}