Skip to main content

ferro_babe/model/
member.rs

1use rust_asm::class_reader::ExceptionTableEntry;
2use rust_asm::constant_pool::CpInfo;
3use rust_asm::nodes::{FieldNode, MethodNode};
4
5use super::{ByteOffset, Instruction};
6
7#[derive(Debug, Clone, Copy)]
8pub struct Field<'a> {
9    inner: &'a FieldNode,
10}
11
12impl<'a> Field<'a> {
13    pub(crate) const fn new(inner: &'a FieldNode) -> Self {
14        Self { inner }
15    }
16
17    #[must_use]
18    pub fn access_flags(&self) -> u16 {
19        self.inner.access_flags
20    }
21
22    #[must_use]
23    pub fn name(&self) -> &str {
24        &self.inner.name
25    }
26
27    #[must_use]
28    pub fn descriptor(&self) -> &str {
29        &self.inner.descriptor
30    }
31}
32
33#[derive(Debug, Clone, Copy)]
34pub struct Method<'a> {
35    inner: &'a MethodNode,
36    constant_pool: &'a [CpInfo],
37}
38
39impl<'a> Method<'a> {
40    pub(crate) const fn new(inner: &'a MethodNode, constant_pool: &'a [CpInfo]) -> Self {
41        Self {
42            inner,
43            constant_pool,
44        }
45    }
46
47    #[must_use]
48    pub fn access_flags(&self) -> u16 {
49        self.inner.access_flags
50    }
51
52    #[must_use]
53    pub fn name(&self) -> &str {
54        &self.inner.name
55    }
56
57    #[must_use]
58    pub fn descriptor(&self) -> &str {
59        &self.inner.descriptor
60    }
61
62    #[must_use]
63    pub fn has_code(&self) -> bool {
64        self.inner.has_code
65    }
66
67    #[must_use]
68    pub fn max_stack(&self) -> u16 {
69        self.inner.max_stack
70    }
71
72    #[must_use]
73    pub fn max_locals(&self) -> u16 {
74        self.inner.max_locals
75    }
76
77    pub fn instructions(&self) -> Option<impl ExactSizeIterator<Item = Instruction<'a>> + '_> {
78        self.inner.has_code.then(|| {
79            self.inner
80                .instructions
81                .insns()
82                .iter()
83                .zip(self.inner.instruction_offsets.iter().copied())
84                .map(|(instruction, offset)| Instruction::new(offset, instruction))
85        })
86    }
87
88    pub fn exception_handlers(&self) -> impl ExactSizeIterator<Item = ExceptionHandler<'a>> + '_ {
89        self.inner
90            .exception_table
91            .iter()
92            .map(|entry| ExceptionHandler::new(entry, self.constant_pool))
93    }
94}
95
96#[derive(Debug, Clone, Copy)]
97pub struct ExceptionHandler<'a> {
98    start: ByteOffset,
99    end: ByteOffset,
100    handler: ByteOffset,
101    catch_type: Option<&'a str>,
102}
103
104impl<'a> ExceptionHandler<'a> {
105    fn new(entry: &'a ExceptionTableEntry, constant_pool: &'a [CpInfo]) -> Self {
106        let catch_type = (entry.catch_type != 0)
107            .then(|| class_name(constant_pool, entry.catch_type))
108            .flatten();
109
110        Self {
111            start: ByteOffset::new(entry.start_pc),
112            end: ByteOffset::new(entry.end_pc),
113            handler: ByteOffset::new(entry.handler_pc),
114            catch_type,
115        }
116    }
117
118    #[must_use]
119    pub const fn start(&self) -> ByteOffset {
120        self.start
121    }
122
123    #[must_use]
124    pub const fn end(&self) -> ByteOffset {
125        self.end
126    }
127
128    #[must_use]
129    pub const fn handler(&self) -> ByteOffset {
130        self.handler
131    }
132
133    #[must_use]
134    pub const fn catch_type(&self) -> Option<&'a str> {
135        self.catch_type
136    }
137}
138
139fn class_name(constant_pool: &[CpInfo], index: u16) -> Option<&str> {
140    let CpInfo::Class { name_index } = constant_pool.get(index as usize)? else {
141        return None;
142    };
143    let CpInfo::Utf8(name) = constant_pool.get(*name_index as usize)? else {
144        return None;
145    };
146    Some(name)
147}