use crate::attributes::Attribute;
use crate::byte_reader::ByteReader;
use crate::constant_pool::ConstantPool;
use crate::error::Result;
use byteorder::{BigEndian, WriteBytesExt};
use std::fmt;
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct Record {
pub name_index: u16,
pub descriptor_index: u16,
pub attributes: Vec<Attribute>,
}
impl Record {
pub fn from_bytes(
constant_pool: &ConstantPool<'_>,
bytes: &mut ByteReader<'_>,
) -> Result<Record> {
let name_index = bytes.read_u16()?;
let descriptor_index = bytes.read_u16()?;
let attributes_count = bytes.read_u16()? as usize;
let mut attributes = Vec::with_capacity(attributes_count);
for _ in 0..attributes_count {
let attribute = Attribute::from_bytes(constant_pool, bytes)?;
attributes.push(attribute);
}
let record = Record {
name_index,
descriptor_index,
attributes,
};
Ok(record)
}
pub fn to_bytes(&self, bytes: &mut Vec<u8>) -> Result<()> {
bytes.write_u16::<BigEndian>(self.name_index)?;
bytes.write_u16::<BigEndian>(self.descriptor_index)?;
let attributes_length = u16::try_from(self.attributes.len())?;
bytes.write_u16::<BigEndian>(attributes_length)?;
for attribute in &self.attributes {
attribute.to_bytes(bytes)?;
}
Ok(())
}
}
impl fmt::Display for Record {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(
f,
"Record[name_index={}, descriptor_index={}, attributes={:?}]",
self.name_index, self.descriptor_index, self.attributes
)
}
}
#[cfg(test)]
mod test {
use super::*;
#[test]
fn test_to_string() {
let attribute = Attribute::ConstantValue {
name_index: 1,
constant_value_index: 42,
};
let record = Record {
name_index: 1,
descriptor_index: 2,
attributes: vec![attribute],
};
assert_eq!(
"Record[name_index=1, descriptor_index=2, attributes=[ConstantValue { name_index: 1, constant_value_index: 42 }]]",
record.to_string()
);
}
#[test]
fn test_serialization() -> Result<()> {
let attribute = Attribute::ConstantValue {
name_index: 1,
constant_value_index: 42,
};
let mut constant_pool = ConstantPool::default();
constant_pool.add_utf8("ConstantValue")?;
let record = Record {
name_index: 1,
descriptor_index: 2,
attributes: vec![attribute],
};
let expected_value = [0, 1, 0, 2, 0, 1, 0, 1, 0, 0, 0, 2, 0, 42];
let mut bytes = Vec::new();
record.clone().to_bytes(&mut bytes)?;
assert_eq!(expected_value, &bytes[..]);
let mut bytes = ByteReader::new(&expected_value);
assert_eq!(record, Record::from_bytes(&constant_pool, &mut bytes)?);
Ok(())
}
}