use crate::{
metadata::tables::{
methodimpl::MethodImplRaw,
types::{CodedIndexType, RowWritable, TableId, TableInfoRef},
},
utils::write_le_at_dyn,
Result,
};
impl RowWritable for MethodImplRaw {
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 method_body_value = sizes.encode_coded_index(
self.method_body.tag,
self.method_body.row,
CodedIndexType::MethodDefOrRef,
)?;
write_le_at_dyn(
data,
offset,
method_body_value,
sizes.coded_index_bits(CodedIndexType::MethodDefOrRef) > 16,
)?;
let method_declaration_value = sizes.encode_coded_index(
self.method_declaration.tag,
self.method_declaration.row,
CodedIndexType::MethodDefOrRef,
)?;
write_le_at_dyn(
data,
offset,
method_declaration_value,
sizes.coded_index_bits(CodedIndexType::MethodDefOrRef) > 16,
)?;
Ok(())
}
}
#[cfg(test)]
mod tests {
use std::sync::Arc;
use crate::metadata::tables::{
methodimpl::MethodImplRaw,
types::{
CodedIndex, CodedIndexType, RowReadable, RowWritable, TableId, TableInfo, TableRow,
},
};
use crate::metadata::token::Token;
#[test]
fn test_methodimpl_row_size() {
let sizes = Arc::new(TableInfo::new_test(
&[
(TableId::TypeDef, 100),
(TableId::MethodDef, 50),
(TableId::MemberRef, 30),
],
false,
false,
false,
));
let expected_size = 2 + 2 + 2; assert_eq!(<MethodImplRaw as TableRow>::row_size(&sizes), expected_size);
let sizes_large = Arc::new(TableInfo::new_test(
&[
(TableId::TypeDef, 0x10000),
(TableId::MethodDef, 0x10000),
(TableId::MemberRef, 30),
],
false,
false,
false,
));
let expected_size_large = 4 + 4 + 4; assert_eq!(
<MethodImplRaw as TableRow>::row_size(&sizes_large),
expected_size_large
);
}
#[test]
fn test_methodimpl_row_write_small() {
let sizes = Arc::new(TableInfo::new_test(
&[
(TableId::TypeDef, 100),
(TableId::MethodDef, 50),
(TableId::MemberRef, 30),
],
false,
false,
false,
));
let method_impl = MethodImplRaw {
rid: 1,
token: Token::new(0x19000001),
offset: 0,
class: 0x0101,
method_body: CodedIndex::new(TableId::MethodDef, 1, CodedIndexType::MethodDefOrRef), method_declaration: CodedIndex::new(
TableId::MethodDef,
1,
CodedIndexType::MethodDefOrRef,
), };
let mut buffer = vec![0u8; <MethodImplRaw as TableRow>::row_size(&sizes) as usize];
let mut offset = 0;
method_impl
.row_write(&mut buffer, &mut offset, 1, &sizes)
.unwrap();
let expected = vec![
0x01, 0x01, 0x02, 0x00, 0x02, 0x00, ];
assert_eq!(buffer, expected);
assert_eq!(offset, expected.len());
}
#[test]
fn test_methodimpl_row_write_large() {
let sizes = Arc::new(TableInfo::new_test(
&[
(TableId::TypeDef, 0x10000),
(TableId::MethodDef, 0x10000),
(TableId::MemberRef, 30),
],
false,
false,
false,
));
let method_impl = MethodImplRaw {
rid: 1,
token: Token::new(0x19000001),
offset: 0,
class: 0x01010101,
method_body: CodedIndex::new(TableId::MethodDef, 1, CodedIndexType::MethodDefOrRef), method_declaration: CodedIndex::new(
TableId::MemberRef,
10,
CodedIndexType::MethodDefOrRef,
), };
let mut buffer = vec![0u8; <MethodImplRaw as TableRow>::row_size(&sizes) as usize];
let mut offset = 0;
method_impl
.row_write(&mut buffer, &mut offset, 1, &sizes)
.unwrap();
let expected = vec![
0x01, 0x01, 0x01, 0x01, 0x02, 0x00, 0x00,
0x00, 0x15, 0x00, 0x00,
0x00, ];
assert_eq!(buffer, expected);
assert_eq!(offset, expected.len());
}
#[test]
fn test_methodimpl_round_trip() {
let sizes = Arc::new(TableInfo::new_test(
&[
(TableId::TypeDef, 100),
(TableId::MethodDef, 50),
(TableId::MemberRef, 30),
],
false,
false,
false,
));
let original = MethodImplRaw {
rid: 42,
token: Token::new(0x1900002A),
offset: 0,
class: 55,
method_body: CodedIndex::new(TableId::MethodDef, 25, CodedIndexType::MethodDefOrRef),
method_declaration: CodedIndex::new(
TableId::MemberRef,
15,
CodedIndexType::MethodDefOrRef,
),
};
let mut buffer = vec![0u8; <MethodImplRaw as TableRow>::row_size(&sizes) as usize];
let mut offset = 0;
original
.row_write(&mut buffer, &mut offset, 42, &sizes)
.unwrap();
let mut read_offset = 0;
let read_back = MethodImplRaw::row_read(&buffer, &mut read_offset, 42, &sizes).unwrap();
assert_eq!(original.rid, read_back.rid);
assert_eq!(original.token, read_back.token);
assert_eq!(original.class, read_back.class);
assert_eq!(original.method_body, read_back.method_body);
assert_eq!(original.method_declaration, read_back.method_declaration);
}
#[test]
fn test_methodimpl_different_coded_indexes() {
let sizes = Arc::new(TableInfo::new_test(
&[
(TableId::TypeDef, 100),
(TableId::MethodDef, 50),
(TableId::MemberRef, 30),
],
false,
false,
false,
));
let test_cases = vec![
(TableId::MethodDef, 1, TableId::MethodDef, 2),
(TableId::MethodDef, 5, TableId::MemberRef, 3),
(TableId::MemberRef, 10, TableId::MethodDef, 8),
(TableId::MemberRef, 15, TableId::MemberRef, 12),
];
for (body_tag, body_row, decl_tag, decl_row) in test_cases {
let method_impl = MethodImplRaw {
rid: 1,
token: Token::new(0x19000001),
offset: 0,
class: 10,
method_body: CodedIndex::new(body_tag, body_row, CodedIndexType::MethodDefOrRef),
method_declaration: CodedIndex::new(
decl_tag,
decl_row,
CodedIndexType::MethodDefOrRef,
),
};
let mut buffer = vec![0u8; <MethodImplRaw as TableRow>::row_size(&sizes) as usize];
let mut offset = 0;
method_impl
.row_write(&mut buffer, &mut offset, 1, &sizes)
.unwrap();
let mut read_offset = 0;
let read_back = MethodImplRaw::row_read(&buffer, &mut read_offset, 1, &sizes).unwrap();
assert_eq!(method_impl.class, read_back.class);
assert_eq!(method_impl.method_body, read_back.method_body);
assert_eq!(method_impl.method_declaration, read_back.method_declaration);
}
}
#[test]
fn test_methodimpl_edge_cases() {
let sizes = Arc::new(TableInfo::new_test(
&[
(TableId::TypeDef, 100),
(TableId::MethodDef, 50),
(TableId::MemberRef, 30),
],
false,
false,
false,
));
let zero_impl = MethodImplRaw {
rid: 1,
token: Token::new(0x19000001),
offset: 0,
class: 0,
method_body: CodedIndex::new(TableId::MethodDef, 0, CodedIndexType::MethodDefOrRef),
method_declaration: CodedIndex::new(
TableId::MethodDef,
0,
CodedIndexType::MethodDefOrRef,
),
};
let mut buffer = vec![0u8; <MethodImplRaw as TableRow>::row_size(&sizes) as usize];
let mut offset = 0;
zero_impl
.row_write(&mut buffer, &mut offset, 1, &sizes)
.unwrap();
let expected = vec![
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ];
assert_eq!(buffer, expected);
let max_impl = MethodImplRaw {
rid: 1,
token: Token::new(0x19000001),
offset: 0,
class: 0xFFFF,
method_body: CodedIndex::new(
TableId::MemberRef,
0x7FFF,
CodedIndexType::MethodDefOrRef,
), method_declaration: CodedIndex::new(
TableId::MethodDef,
0x7FFF,
CodedIndexType::MethodDefOrRef,
),
};
let mut buffer = vec![0u8; <MethodImplRaw as TableRow>::row_size(&sizes) as usize];
let mut offset = 0;
max_impl
.row_write(&mut buffer, &mut offset, 1, &sizes)
.unwrap();
assert_eq!(buffer.len(), 6); }
#[test]
fn test_methodimpl_known_binary_format() {
let sizes = Arc::new(TableInfo::new_test(
&[
(TableId::MethodImpl, 1),
(TableId::TypeDef, 10),
(TableId::MethodDef, 10),
(TableId::MemberRef, 10),
],
false,
false,
false,
));
let method_impl = MethodImplRaw {
rid: 1,
token: Token::new(0x19000001),
offset: 0,
class: 0x0101,
method_body: CodedIndex::new(TableId::MethodDef, 1, CodedIndexType::MethodDefOrRef), method_declaration: CodedIndex::new(
TableId::MethodDef,
1,
CodedIndexType::MethodDefOrRef,
), };
let mut buffer = vec![0u8; <MethodImplRaw as TableRow>::row_size(&sizes) as usize];
let mut offset = 0;
method_impl
.row_write(&mut buffer, &mut offset, 1, &sizes)
.unwrap();
let expected = vec![
0x01, 0x01, 0x02, 0x00, 0x02, 0x00, ];
assert_eq!(buffer, expected);
}
}