use crate::{
metadata::tables::{
constant::ConstantRaw,
types::{CodedIndexType, RowWritable, TableInfoRef},
},
utils::{write_le_at, write_le_at_dyn},
Result,
};
impl RowWritable for ConstantRaw {
fn row_write(
&self,
data: &mut [u8],
offset: &mut usize,
_rid: u32,
sizes: &TableInfoRef,
) -> Result<()> {
write_le_at(data, offset, self.base)?;
write_le_at(data, offset, 0u8)?;
let parent_value = sizes.encode_coded_index(
self.parent.tag,
self.parent.row,
CodedIndexType::HasConstant,
)?;
write_le_at_dyn(
data,
offset,
parent_value,
sizes.coded_index_bits(CodedIndexType::HasConstant) > 16,
)?;
write_le_at_dyn(data, offset, self.value, sizes.is_large_blob())?;
Ok(())
}
}
#[cfg(test)]
mod tests {
use std::sync::Arc;
use crate::metadata::tables::{
constant::ConstantRaw,
types::{
CodedIndex, CodedIndexType, RowReadable, RowWritable, TableId, TableInfo, TableRow,
},
};
use crate::metadata::token::Token;
#[test]
fn test_constant_row_size() {
let sizes = Arc::new(TableInfo::new_test(
&[
(TableId::Field, 100),
(TableId::Param, 50),
(TableId::Property, 25),
],
false,
false,
false,
));
let expected_size = 1 + 1 + 2 + 2; assert_eq!(<ConstantRaw as TableRow>::row_size(&sizes), expected_size);
let sizes_large = Arc::new(TableInfo::new_test(
&[
(TableId::Field, 0x10000),
(TableId::Param, 0x10000),
(TableId::Property, 0x10000),
],
true,
true,
true,
));
let expected_size_large = 1 + 1 + 4 + 4; assert_eq!(
<ConstantRaw as TableRow>::row_size(&sizes_large),
expected_size_large
);
}
#[test]
fn test_constant_row_write_small() {
let sizes = Arc::new(TableInfo::new_test(
&[
(TableId::Field, 100),
(TableId::Param, 50),
(TableId::Property, 25),
],
false,
false,
false,
));
let constant = ConstantRaw {
rid: 1,
token: Token::new(0x0B000001),
offset: 0,
base: 0x01,
parent: CodedIndex::new(TableId::Property, 128, CodedIndexType::HasConstant), value: 0x0303,
};
let mut buffer = vec![0u8; <ConstantRaw as TableRow>::row_size(&sizes) as usize];
let mut offset = 0;
constant
.row_write(&mut buffer, &mut offset, 1, &sizes)
.unwrap();
let expected = vec![
0x01, 0x00, 0x02,
0x02, 0x03, 0x03, ];
assert_eq!(buffer, expected);
assert_eq!(offset, expected.len());
}
#[test]
fn test_constant_row_write_large() {
let sizes = Arc::new(TableInfo::new_test(
&[
(TableId::Field, 0x10000),
(TableId::Param, 0x10000),
(TableId::Property, 0x10000),
],
true,
true,
true,
));
let constant = ConstantRaw {
rid: 1,
token: Token::new(0x0B000001),
offset: 0,
base: 0x01,
parent: CodedIndex::new(TableId::Property, 0x808080, CodedIndexType::HasConstant), value: 0x03030303,
};
let mut buffer = vec![0u8; <ConstantRaw as TableRow>::row_size(&sizes) as usize];
let mut offset = 0;
constant
.row_write(&mut buffer, &mut offset, 1, &sizes)
.unwrap();
let expected = vec![
0x01, 0x00, 0x02, 0x02, 0x02,
0x02, 0x03, 0x03, 0x03, 0x03, ];
assert_eq!(buffer, expected);
assert_eq!(offset, expected.len());
}
#[test]
fn test_constant_round_trip() {
let sizes = Arc::new(TableInfo::new_test(
&[
(TableId::Field, 100),
(TableId::Param, 50),
(TableId::Property, 25),
],
false,
false,
false,
));
let original = ConstantRaw {
rid: 42,
token: Token::new(0x0B00002A),
offset: 0,
base: 0x08, parent: CodedIndex::new(TableId::Field, 25, CodedIndexType::HasConstant), value: 128, };
let mut buffer = vec![0u8; <ConstantRaw 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 = ConstantRaw::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.base, read_back.base);
assert_eq!(original.parent, read_back.parent);
assert_eq!(original.value, read_back.value);
}
#[test]
fn test_constant_different_parent_types() {
let sizes = Arc::new(TableInfo::new_test(
&[
(TableId::Field, 100),
(TableId::Param, 50),
(TableId::Property, 25),
],
false,
false,
false,
));
let test_cases = vec![
(TableId::Field, 1, 0x08, 0x100), (TableId::Param, 1, 0x0E, 0x200), (TableId::Property, 1, 0x0C, 0x300), (TableId::Field, 50, 0x05, 0x400), (TableId::Param, 25, 0x06, 0x500), ];
for (parent_tag, parent_row, element_type, blob_index) in test_cases {
let constant = ConstantRaw {
rid: 1,
token: Token::new(0x0B000001),
offset: 0,
base: element_type,
parent: CodedIndex::new(parent_tag, parent_row, CodedIndexType::HasConstant),
value: blob_index,
};
let mut buffer = vec![0u8; <ConstantRaw as TableRow>::row_size(&sizes) as usize];
let mut offset = 0;
constant
.row_write(&mut buffer, &mut offset, 1, &sizes)
.unwrap();
let mut read_offset = 0;
let read_back = ConstantRaw::row_read(&buffer, &mut read_offset, 1, &sizes).unwrap();
assert_eq!(constant.base, read_back.base);
assert_eq!(constant.parent, read_back.parent);
assert_eq!(constant.value, read_back.value);
}
}
#[test]
fn test_constant_element_types() {
let sizes = Arc::new(TableInfo::new_test(
&[
(TableId::Field, 100),
(TableId::Param, 50),
(TableId::Property, 25),
],
false,
false,
false,
));
let element_type_cases = vec![
(0x02, "ELEMENT_TYPE_BOOLEAN"),
(0x03, "ELEMENT_TYPE_CHAR"),
(0x04, "ELEMENT_TYPE_I1"),
(0x05, "ELEMENT_TYPE_U1"),
(0x06, "ELEMENT_TYPE_I2"),
(0x07, "ELEMENT_TYPE_U2"),
(0x08, "ELEMENT_TYPE_I4"),
(0x09, "ELEMENT_TYPE_U4"),
(0x0A, "ELEMENT_TYPE_I8"),
(0x0B, "ELEMENT_TYPE_U8"),
(0x0C, "ELEMENT_TYPE_R4"),
(0x0D, "ELEMENT_TYPE_R8"),
(0x0E, "ELEMENT_TYPE_STRING"),
(0x12, "ELEMENT_TYPE_CLASS"), ];
for (element_type, _description) in element_type_cases {
let constant = ConstantRaw {
rid: 1,
token: Token::new(0x0B000001),
offset: 0,
base: element_type,
parent: CodedIndex::new(TableId::Field, 1, CodedIndexType::HasConstant),
value: 100,
};
let mut buffer = vec![0u8; <ConstantRaw as TableRow>::row_size(&sizes) as usize];
let mut offset = 0;
constant
.row_write(&mut buffer, &mut offset, 1, &sizes)
.unwrap();
assert_eq!(buffer[0], element_type);
assert_eq!(buffer[1], 0x00);
}
}
#[test]
fn test_constant_edge_cases() {
let sizes = Arc::new(TableInfo::new_test(
&[
(TableId::Field, 100),
(TableId::Param, 50),
(TableId::Property, 25),
],
false,
false,
false,
));
let zero_constant = ConstantRaw {
rid: 1,
token: Token::new(0x0B000001),
offset: 0,
base: 0,
parent: CodedIndex::new(TableId::Field, 0, CodedIndexType::HasConstant), value: 0,
};
let mut buffer = vec![0u8; <ConstantRaw as TableRow>::row_size(&sizes) as usize];
let mut offset = 0;
zero_constant
.row_write(&mut buffer, &mut offset, 1, &sizes)
.unwrap();
let expected = vec![
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ];
assert_eq!(buffer, expected);
let max_constant = ConstantRaw {
rid: 1,
token: Token::new(0x0B000001),
offset: 0,
base: 0xFF,
parent: CodedIndex::new(TableId::Property, 0x3FFF, CodedIndexType::HasConstant), value: 0xFFFF,
};
let mut buffer = vec![0u8; <ConstantRaw as TableRow>::row_size(&sizes) as usize];
let mut offset = 0;
max_constant
.row_write(&mut buffer, &mut offset, 1, &sizes)
.unwrap();
assert_eq!(buffer.len(), 6); }
#[test]
fn test_constant_padding_always_zero() {
let sizes = Arc::new(TableInfo::new_test(
&[
(TableId::Field, 100),
(TableId::Param, 50),
(TableId::Property, 25),
],
false,
false,
false,
));
let test_constants = vec![
(0x08, TableId::Field, 1, 100),
(0x0E, TableId::Param, 2, 200),
(0x0C, TableId::Property, 3, 300),
(0x12, TableId::Field, 4, 400),
];
for (element_type, parent_tag, parent_row, blob_index) in test_constants {
let constant = ConstantRaw {
rid: 1,
token: Token::new(0x0B000001),
offset: 0,
base: element_type,
parent: CodedIndex::new(parent_tag, parent_row, CodedIndexType::HasConstant),
value: blob_index,
};
let mut buffer = vec![0u8; <ConstantRaw as TableRow>::row_size(&sizes) as usize];
let mut offset = 0;
constant
.row_write(&mut buffer, &mut offset, 1, &sizes)
.unwrap();
assert_eq!(buffer[1], 0x00, "Padding byte must always be zero");
}
}
#[test]
fn test_constant_known_binary_format() {
let sizes = Arc::new(TableInfo::new_test(
&[(TableId::Property, 1)],
false,
false,
false,
));
let constant = ConstantRaw {
rid: 1,
token: Token::new(0x0B000001),
offset: 0,
base: 0x01,
parent: CodedIndex::new(TableId::Property, 128, CodedIndexType::HasConstant), value: 0x0303,
};
let mut buffer = vec![0u8; <ConstantRaw as TableRow>::row_size(&sizes) as usize];
let mut offset = 0;
constant
.row_write(&mut buffer, &mut offset, 1, &sizes)
.unwrap();
let expected = vec![
0x01, 0x00, 0x02, 0x02, 0x03, 0x03, ];
assert_eq!(buffer, expected);
}
}