use crate::reader::byte_stream::ByteStream;
use crate::reader::metadata::Metadata;
use crate::reader::value_descriptor::ValueDescriptor;
use crate::reader::Error;
use crate::reader::{ChunkHeader, Result};
use crate::EVENT_TYPE_CONSTANT_POOL;
use rustc_hash::FxHashMap;
use std::io::{Read, Seek};
#[derive(Debug, Default)]
pub struct ConstantPool {
pub(crate) inner: FxHashMap<ConstantPoolKey, ValueDescriptor>,
}
#[derive(Debug, Default, Hash, Eq, PartialEq, Ord, PartialOrd, Copy, Clone)]
pub struct ConstantPoolKey {
pub class_id: i64,
pub constant_index: i64,
}
impl ConstantPool {
pub fn try_new<T: Read + Seek>(
stream: &mut ByteStream<T>,
header: &ChunkHeader,
metadata: &Metadata,
) -> Result<Self> {
let mut constant_pool = Self::default();
let mut offset = 0;
let mut delta = header.constant_pool_offset;
while delta != 0 {
offset += delta;
stream.seek(offset as u64)?;
delta = Self::read_constant_pool_event(stream, &mut constant_pool, metadata)?;
}
Ok(constant_pool)
}
pub fn register(&mut self, class_id: i64, constant_index: i64, value: ValueDescriptor) {
self.inner.insert(
ConstantPoolKey {
class_id,
constant_index,
},
value,
);
}
pub fn get(&self, class_id: &i64, constant_index: &i64) -> Option<&ValueDescriptor> {
self.inner.get(&ConstantPoolKey {
class_id: *class_id,
constant_index: *constant_index,
})
}
fn read_constant_pool_event<T: Read + Seek>(
stream: &mut ByteStream<T>,
constant_pool: &mut ConstantPool,
metadata: &Metadata,
) -> Result<i64> {
stream.read_i32()?;
if stream.read_i64()? != EVENT_TYPE_CONSTANT_POOL {
return Err(Error::InvalidFormat);
}
stream.read_i64()?;
stream.read_i64()?;
let delta = stream.read_i64()?;
stream.read_i8()?;
let pool_count = stream.read_i32()?;
for _ in 0..pool_count {
let class_id = stream.read_i64()?;
let constant_count = stream.read_i32()?;
for _ in 0..constant_count {
let constant_index = stream.read_i64()?;
let value = ValueDescriptor::try_new(stream, class_id, metadata)?;
constant_pool.register(class_id, constant_index, value);
}
}
Ok(delta)
}
}