use crate::{
metadata::tables::{
interfaceimpl::InterfaceImplRaw,
types::{CodedIndexType, RowWritable, TableId, TableInfoRef},
},
utils::write_le_at_dyn,
Result,
};
impl RowWritable for InterfaceImplRaw {
fn row_write(
&self,
data: &mut [u8],
offset: &mut usize,
_rid: u32,
sizes: &TableInfoRef,
) -> Result<()> {
write_le_at_dyn(data, offset, self.class, sizes.is_large(TableId::TypeDef))?;
let encoded_interface = sizes.encode_coded_index(
self.interface.tag,
self.interface.row,
CodedIndexType::TypeDefOrRef,
)?;
write_le_at_dyn(
data,
offset,
encoded_interface,
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 = <InterfaceImplRaw as TableRow>::row_size(&table_info);
assert_eq!(size, 4);
let table_info_large = Arc::new(TableInfo::new_test(
&[
(TableId::TypeDef, 70000),
(TableId::TypeRef, 70000),
(TableId::TypeSpec, 70000),
],
false,
false,
false,
));
let size_large = <InterfaceImplRaw as TableRow>::row_size(&table_info_large);
assert_eq!(size_large, 8);
}
#[test]
fn test_round_trip_serialization() {
let original_row = InterfaceImplRaw {
rid: 1,
token: Token::new(0x09000001),
offset: 0,
class: 0x0101,
interface: CodedIndex::new(TableId::TypeSpec, 0x80, 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 = <InterfaceImplRaw 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 =
InterfaceImplRaw::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.class, original_row.class);
assert_eq!(deserialized_row.interface, original_row.interface);
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, ];
let table_info = Arc::new(TableInfo::new_test(
&[(TableId::InterfaceImpl, 1)],
false,
false,
false,
));
let mut read_offset = 0;
let reference_row = InterfaceImplRaw::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, 0x01, 0x01, 0x02, 0x02, 0x02, 0x02, ];
let table_info = Arc::new(TableInfo::new_test(
&[(TableId::TypeDef, u16::MAX as u32 + 2)],
true,
true,
true,
));
let mut read_offset = 0;
let reference_row = InterfaceImplRaw::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_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 interface_impl_row = InterfaceImplRaw {
rid: 1,
token: Token::new(0x09000001),
offset: 0,
class: 1,
interface: CodedIndex::new(table_id, 1, CodedIndexType::TypeDefOrRef),
};
let row_size = <InterfaceImplRaw as TableRow>::row_size(&table_info) as usize;
let mut buffer = vec![0u8; row_size];
let mut offset = 0;
interface_impl_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 =
InterfaceImplRaw::row_read(&buffer, &mut read_offset, 1, &table_info)
.unwrap_or_else(|_| panic!("Deserialization should succeed for {description}"));
assert_eq!(
deserialized_row.interface.tag, interface_impl_row.interface.tag,
"Interface type tag should match for {description}"
);
}
}
#[test]
fn test_large_table_serialization() {
let original_row = InterfaceImplRaw {
rid: 1,
token: Token::new(0x09000001),
offset: 0,
class: 0x12345,
interface: CodedIndex::new(TableId::TypeRef, 0x8000, CodedIndexType::TypeDefOrRef),
};
let table_info = Arc::new(TableInfo::new_test(
&[
(TableId::TypeDef, 70000),
(TableId::TypeRef, 70000),
(TableId::TypeSpec, 70000),
],
false,
false,
false,
));
let row_size = <InterfaceImplRaw 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 table serialization should succeed");
let mut read_offset = 0;
let deserialized_row =
InterfaceImplRaw::row_read(&buffer, &mut read_offset, 1, &table_info)
.expect("Large table deserialization should succeed");
assert_eq!(deserialized_row.class, original_row.class);
assert_eq!(deserialized_row.interface, original_row.interface);
}
#[test]
fn test_edge_cases() {
let minimal_interface_impl = InterfaceImplRaw {
rid: 1,
token: Token::new(0x09000001),
offset: 0,
class: 1, interface: 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 = <InterfaceImplRaw as TableRow>::row_size(&table_info) as usize;
let mut buffer = vec![0u8; row_size];
let mut offset = 0;
minimal_interface_impl
.row_write(&mut buffer, &mut offset, 1, &table_info)
.expect("Minimal interface impl serialization should succeed");
let mut read_offset = 0;
let deserialized_row =
InterfaceImplRaw::row_read(&buffer, &mut read_offset, 1, &table_info)
.expect("Minimal interface impl deserialization should succeed");
assert_eq!(deserialized_row.class, minimal_interface_impl.class);
assert_eq!(deserialized_row.interface, minimal_interface_impl.interface);
}
#[test]
fn test_different_table_combinations() {
let interface_impl_row = InterfaceImplRaw {
rid: 1,
token: Token::new(0x09000001),
offset: 0,
class: 0x8000,
interface: CodedIndex::new(TableId::TypeDef, 0x4000, CodedIndexType::TypeDefOrRef),
};
let test_cases = vec![
(1000, 1000, 4), (70000, 1000, 8), (1000, 70000, 6), (70000, 70000, 8), ];
for (typedef_size, other_size, expected_size) in test_cases {
let table_info = Arc::new(TableInfo::new_test(
&[
(TableId::TypeDef, typedef_size),
(TableId::TypeRef, other_size),
(TableId::TypeSpec, other_size),
],
false, false, false, ));
let size = <InterfaceImplRaw as TableRow>::row_size(&table_info) as usize;
assert_eq!(
size, expected_size,
"Row size should be {expected_size} for typedef_size={typedef_size}, other_size={other_size}"
);
let mut buffer = vec![0u8; size];
let mut offset = 0;
interface_impl_row
.row_write(&mut buffer, &mut offset, 1, &table_info)
.expect("Serialization should succeed");
let mut read_offset = 0;
let deserialized_row =
InterfaceImplRaw::row_read(&buffer, &mut read_offset, 1, &table_info)
.expect("Deserialization should succeed");
assert_eq!(deserialized_row.class, interface_impl_row.class);
assert_eq!(
deserialized_row.interface.tag,
interface_impl_row.interface.tag
);
}
}
}