use crate::{
metadata::tables::{
methodsemantics::MethodSemanticsRaw,
types::{CodedIndexType, RowWritable, TableId, TableInfoRef},
},
utils::{write_le_at, write_le_at_dyn},
Result,
};
impl RowWritable for MethodSemanticsRaw {
fn row_write(
&self,
data: &mut [u8],
offset: &mut usize,
_rid: u32,
sizes: &TableInfoRef,
) -> Result<()> {
write_le_at(
data,
offset,
u16::try_from(self.semantics).map_err(|_| {
malformed_error!("MethodSemantics semantics out of range: {}", self.semantics)
})?,
)?;
write_le_at_dyn(
data,
offset,
self.method,
sizes.is_large(TableId::MethodDef),
)?;
let association_value = sizes.encode_coded_index(
self.association.tag,
self.association.row,
CodedIndexType::HasSemantics,
)?;
write_le_at_dyn(
data,
offset,
association_value,
sizes.coded_index_bits(CodedIndexType::HasSemantics) > 16,
)?;
Ok(())
}
}
#[cfg(test)]
mod tests {
use std::sync::Arc;
use crate::metadata::tables::{
methodsemantics::MethodSemanticsRaw,
types::{
CodedIndex, CodedIndexType, RowReadable, RowWritable, TableId, TableInfo, TableRow,
},
};
use crate::metadata::token::Token;
#[test]
fn test_methodsemantics_row_size() {
let sizes = Arc::new(TableInfo::new_test(
&[
(TableId::MethodDef, 100),
(TableId::Event, 50),
(TableId::Property, 30),
],
false,
false,
false,
));
let expected_size = 2 + 2 + 2; assert_eq!(
<MethodSemanticsRaw as TableRow>::row_size(&sizes),
expected_size
);
let sizes_large = Arc::new(TableInfo::new_test(
&[
(TableId::MethodDef, 0x10000),
(TableId::Event, 50),
(TableId::Property, 30),
],
false,
false,
false,
));
let expected_size_large = 2 + 4 + 2; assert_eq!(
<MethodSemanticsRaw as TableRow>::row_size(&sizes_large),
expected_size_large
);
}
#[test]
fn test_methodsemantics_row_write_small() {
let sizes = Arc::new(TableInfo::new_test(
&[
(TableId::MethodDef, 100),
(TableId::Event, 50),
(TableId::Property, 30),
],
false,
false,
false,
));
let method_semantics = MethodSemanticsRaw {
rid: 1,
token: Token::new(0x18000001),
offset: 0,
semantics: 0x0002, method: 42,
association: CodedIndex::new(TableId::Property, 15, CodedIndexType::HasSemantics), };
let mut buffer = vec![0u8; <MethodSemanticsRaw as TableRow>::row_size(&sizes) as usize];
let mut offset = 0;
method_semantics
.row_write(&mut buffer, &mut offset, 1, &sizes)
.unwrap();
let expected = vec![
0x02, 0x00, 0x2A, 0x00, 0x1F, 0x00, ];
assert_eq!(buffer, expected);
assert_eq!(offset, expected.len());
}
#[test]
fn test_methodsemantics_row_write_large() {
let sizes = Arc::new(TableInfo::new_test(
&[
(TableId::MethodDef, 0x10000),
(TableId::Event, 50),
(TableId::Property, 30),
],
false,
false,
false,
));
let method_semantics = MethodSemanticsRaw {
rid: 1,
token: Token::new(0x18000001),
offset: 0,
semantics: 0x0008, method: 0x8000,
association: CodedIndex::new(TableId::Event, 25, CodedIndexType::HasSemantics), };
let mut buffer = vec![0u8; <MethodSemanticsRaw as TableRow>::row_size(&sizes) as usize];
let mut offset = 0;
method_semantics
.row_write(&mut buffer, &mut offset, 1, &sizes)
.unwrap();
let expected = vec![
0x08, 0x00, 0x00, 0x80, 0x00, 0x00, 0x32, 0x00, ];
assert_eq!(buffer, expected);
assert_eq!(offset, expected.len());
}
#[test]
fn test_methodsemantics_round_trip() {
let sizes = Arc::new(TableInfo::new_test(
&[
(TableId::MethodDef, 100),
(TableId::Event, 50),
(TableId::Property, 30),
],
false,
false,
false,
));
let original = MethodSemanticsRaw {
rid: 42,
token: Token::new(0x1800002A),
offset: 0,
semantics: 0x0001, method: 55,
association: CodedIndex::new(TableId::Property, 10, CodedIndexType::HasSemantics),
};
let mut buffer = vec![0u8; <MethodSemanticsRaw 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 =
MethodSemanticsRaw::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.semantics, read_back.semantics);
assert_eq!(original.method, read_back.method);
assert_eq!(original.association, read_back.association);
}
#[test]
fn test_methodsemantics_different_semantic_types() {
let sizes = Arc::new(TableInfo::new_test(
&[
(TableId::MethodDef, 100),
(TableId::Event, 50),
(TableId::Property, 30),
],
false,
false,
false,
));
let test_cases = vec![
(0x0001u32, "SETTER"),
(0x0002u32, "GETTER"),
(0x0004u32, "OTHER"),
(0x0008u32, "ADD_ON"),
(0x0010u32, "REMOVE_ON"),
(0x0020u32, "FIRE"),
];
for (semantic_value, _name) in test_cases {
let method_semantics = MethodSemanticsRaw {
rid: 1,
token: Token::new(0x18000001),
offset: 0,
semantics: semantic_value,
method: 10,
association: CodedIndex::new(TableId::Property, 5, CodedIndexType::HasSemantics),
};
let mut buffer = vec![0u8; <MethodSemanticsRaw as TableRow>::row_size(&sizes) as usize];
let mut offset = 0;
method_semantics
.row_write(&mut buffer, &mut offset, 1, &sizes)
.unwrap();
let written_semantics = u16::from_le_bytes([buffer[0], buffer[1]]);
assert_eq!(u32::from(written_semantics), semantic_value);
}
}
#[test]
fn test_methodsemantics_edge_cases() {
let sizes = Arc::new(TableInfo::new_test(
&[
(TableId::MethodDef, 100),
(TableId::Event, 50),
(TableId::Property, 30),
],
false,
false,
false,
));
let zero_semantics = MethodSemanticsRaw {
rid: 1,
token: Token::new(0x18000001),
offset: 0,
semantics: 0,
method: 0,
association: CodedIndex::new(TableId::Event, 0, CodedIndexType::HasSemantics),
};
let mut buffer = vec![0u8; <MethodSemanticsRaw as TableRow>::row_size(&sizes) as usize];
let mut offset = 0;
zero_semantics
.row_write(&mut buffer, &mut offset, 1, &sizes)
.unwrap();
let expected = vec![
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ];
assert_eq!(buffer, expected);
let max_semantics = MethodSemanticsRaw {
rid: 1,
token: Token::new(0x18000001),
offset: 0,
semantics: 0xFFFF,
method: 0xFFFF,
association: CodedIndex::new(TableId::Property, 0x7FFF, CodedIndexType::HasSemantics), };
let mut buffer = vec![0u8; <MethodSemanticsRaw as TableRow>::row_size(&sizes) as usize];
let mut offset = 0;
max_semantics
.row_write(&mut buffer, &mut offset, 1, &sizes)
.unwrap();
assert_eq!(buffer.len(), 6); }
#[test]
fn test_methodsemantics_known_binary_format() {
let sizes = Arc::new(TableInfo::new_test(
&[
(TableId::MethodDef, 1),
(TableId::Event, 1),
(TableId::Property, 1),
],
false,
false,
false,
));
let method_semantics = MethodSemanticsRaw {
rid: 1,
token: Token::new(0x18000001),
offset: 0,
semantics: 0x0101,
method: 0x0202,
association: CodedIndex::new(TableId::Event, 1, CodedIndexType::HasSemantics), };
let mut buffer = vec![0u8; <MethodSemanticsRaw as TableRow>::row_size(&sizes) as usize];
let mut offset = 0;
method_semantics
.row_write(&mut buffer, &mut offset, 1, &sizes)
.unwrap();
let expected = vec![
0x01, 0x01, 0x02, 0x02, 0x02, 0x00, ];
assert_eq!(buffer, expected);
}
}