mod instructions;
mod locals;
mod stack_map;
pub use instructions::*;
pub use locals::*;
pub use stack_map::*;
use crate::reader::decoding::*;
use crate::reader::{cpool, Attribute};
use crate::{error::*, mutf8, MStr};
use std::fmt;
use super::FromAttribute;
#[derive(Clone)]
pub struct Code<'input> {
max_stack: u16,
max_locals: u16,
raw_instructions: RawInstructions<'input>,
exception_handlers: ExceptionHandlers<'input>,
attributes: DecodeMany<'input, Attribute<'input>, u16>,
}
impl<'input> Code<'input> {
#[must_use]
pub fn max_stack(&self) -> u16 {
self.max_stack
}
#[must_use]
pub fn max_locals(&self) -> u16 {
self.max_locals
}
#[must_use]
pub fn raw_instructions(&self) -> RawInstructions<'input> {
self.raw_instructions.clone()
}
pub fn raw_instructions_from(&self, index: Index) -> Result<RawInstructions<'input>, DecodeError> {
let mut instructions = self.raw_instructions();
instructions.decoder.advance(index.as_u32() as usize)?;
Ok(instructions)
}
#[must_use]
pub fn exception_handlers(&self) -> ExceptionHandlers<'input> {
self.exception_handlers.clone()
}
#[must_use]
pub fn attributes(&self) -> DecodeMany<'input, Attribute<'input>, u16> {
self.attributes.clone()
}
}
impl<'input> DecodeInto<'input> for Code<'input> {
fn decode_into(mut decoder: Decoder<'input>) -> Result<Self, DecodeError> {
let max_stack = decoder.read()?;
let max_locals = decoder.read()?;
let code_length = decoder.read::<u32>()? as usize;
let raw_instructions = RawInstructions {
start_position: decoder.file_position(),
decoder: decoder.limit(code_length, Context::Code)?,
};
decoder.advance(code_length)?;
let exception_count: u16 = decoder.read()?;
let exception_table_bytes = exception_count as usize * 8;
let exception_handlers = ExceptionHandlers {
decoder: decoder.limit(exception_table_bytes, Context::Code)?,
};
decoder.advance(exception_table_bytes)?;
let attributes = decoder.read()?;
Ok(Code {
max_stack,
max_locals,
raw_instructions,
exception_handlers,
attributes,
})
}
}
impl<'input> FromAttribute<'input> for Code<'input> {
const NAME: &'static MStr = mutf8!("Code");
}
impl<'input> fmt::Debug for Code<'input> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("Code").finish()
}
}
#[derive(Clone)]
pub struct ExceptionHandlers<'input> {
decoder: Decoder<'input>,
}
impl<'input> Iterator for ExceptionHandlers<'input> {
type Item = ExceptionHandler<'input>;
fn next(&mut self) -> Option<Self::Item> {
self.decoder.read().ok()
}
}
impl<'input> fmt::Debug for ExceptionHandlers<'input> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("ExceptionHandlers").finish()
}
}
pub struct ExceptionHandler<'input> {
start: Index,
end: Index,
handler: Index,
catch_type: Option<cpool::Index<cpool::Class<'input>>>,
}
impl<'input> ExceptionHandler<'input> {
#[must_use]
pub fn start(&self) -> Index {
self.start
}
#[must_use]
pub fn end(&self) -> Index {
self.end
}
#[must_use]
pub fn handler(&self) -> Index {
self.handler
}
#[must_use]
pub fn catch_type(&self) -> Option<cpool::Index<cpool::Class<'input>>> {
self.catch_type
}
}
impl<'input> Decode<'input> for ExceptionHandler<'input> {
fn decode(decoder: &mut Decoder<'input>) -> Result<Self, DecodeError> {
let start: u16 = decoder.read()?;
let end: u16 = decoder.read()?;
let handler: u16 = decoder.read()?;
let catch_type = decoder.read()?;
Ok(ExceptionHandler {
start: Index::new(start.into()),
end: Index::new(end.into()),
handler: Index::new(handler.into()),
catch_type,
})
}
}
impl<'input> fmt::Debug for ExceptionHandler<'input> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("ExceptionHandler").finish()
}
}
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct Index {
index: u32,
}
impl Index {
#[must_use]
pub(crate) fn new(index: u32) -> Index {
Index { index }
}
#[must_use]
pub fn as_u32(self) -> u32 {
self.index
}
}
impl<'input> Decode<'input> for Index {
fn decode(decoder: &mut Decoder<'input>) -> Result<Index, DecodeError> {
Ok(Index::new(decoder.read()?))
}
}
impl fmt::Debug for Index {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_tuple("code::Index").field(&self.index).finish()
}
}
dec_structure! {
pub struct LineNumberTable<'input> into {
lines: DecodeMany<'input, Line<'input>, u16>,
}
}
dec_structure! {
pub struct Line<'input> {
start: Index,
line_number: u16,
}
}