ferro_babe/model/
member.rs1use 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> {
10 inner: &'a FieldNode,
11}
12
13impl<'a> Field<'a> {
14 pub(crate) const fn new(inner: &'a FieldNode) -> Self {
15 Self { inner }
16 }
17
18 #[must_use]
20 pub fn access_flags(&self) -> u16 {
21 self.inner.access_flags
22 }
23
24 #[must_use]
26 pub fn name(&self) -> &str {
27 &self.inner.name
28 }
29
30 #[must_use]
32 pub fn descriptor(&self) -> &str {
33 &self.inner.descriptor
34 }
35}
36
37#[derive(Debug, Clone, Copy)]
38pub struct Method<'a> {
40 inner: &'a MethodNode,
41 constant_pool: &'a [CpInfo],
42}
43
44impl<'a> Method<'a> {
45 pub(crate) const fn new(inner: &'a MethodNode, constant_pool: &'a [CpInfo]) -> Self {
46 Self {
47 inner,
48 constant_pool,
49 }
50 }
51
52 #[must_use]
54 pub fn access_flags(&self) -> u16 {
55 self.inner.access_flags
56 }
57
58 #[must_use]
60 pub fn name(&self) -> &str {
61 &self.inner.name
62 }
63
64 #[must_use]
66 pub fn descriptor(&self) -> &str {
67 &self.inner.descriptor
68 }
69
70 #[must_use]
74 pub fn has_code(&self) -> bool {
75 self.inner.has_code
76 }
77
78 #[must_use]
82 pub fn max_stack(&self) -> u16 {
83 self.inner.max_stack
84 }
85
86 #[must_use]
90 pub fn max_locals(&self) -> u16 {
91 self.inner.max_locals
92 }
93
94 pub fn instructions(&self) -> Option<impl ExactSizeIterator<Item = Instruction<'a>> + '_> {
99 self.inner.has_code.then(|| {
100 self.inner
101 .instructions
102 .insns()
103 .iter()
104 .zip(self.inner.instruction_offsets.iter().copied())
105 .map(|(instruction, offset)| Instruction::new(offset, instruction))
106 })
107 }
108
109 pub fn exception_handlers(&self) -> impl ExactSizeIterator<Item = ExceptionHandler<'a>> + '_ {
113 self.inner
114 .exception_table
115 .iter()
116 .map(|entry| ExceptionHandler::new(entry, self.constant_pool))
117 }
118}
119
120#[derive(Debug, Clone, Copy)]
121pub struct ExceptionHandler<'a> {
123 start: ByteOffset,
124 end: ByteOffset,
125 handler: ByteOffset,
126 catch_type: Option<&'a str>,
127}
128
129impl<'a> ExceptionHandler<'a> {
130 fn new(entry: &'a ExceptionTableEntry, constant_pool: &'a [CpInfo]) -> Self {
131 let catch_type = (entry.catch_type != 0)
132 .then(|| class_name(constant_pool, entry.catch_type))
133 .flatten();
134
135 Self {
136 start: ByteOffset::new(entry.start_pc),
137 end: ByteOffset::new(entry.end_pc),
138 handler: ByteOffset::new(entry.handler_pc),
139 catch_type,
140 }
141 }
142
143 #[must_use]
145 pub const fn start(&self) -> ByteOffset {
146 self.start
147 }
148
149 #[must_use]
151 pub const fn end(&self) -> ByteOffset {
152 self.end
153 }
154
155 #[must_use]
157 pub const fn handler(&self) -> ByteOffset {
158 self.handler
159 }
160
161 #[must_use]
165 pub const fn catch_type(&self) -> Option<&'a str> {
166 self.catch_type
167 }
168}
169
170fn class_name(constant_pool: &[CpInfo], index: u16) -> Option<&str> {
171 let CpInfo::Class { name_index } = constant_pool.get(index as usize)? else {
172 return None;
173 };
174 let CpInfo::Utf8(name) = constant_pool.get(*name_index as usize)? else {
175 return None;
176 };
177 Some(name)
178}