ferro_babe/model/
member.rs1use rust_asm::class_reader::{AttributeInfo, ExceptionTableEntry};
2use rust_asm::constant_pool::CpInfo;
3use rust_asm::nodes::{FieldNode, MethodNode};
4
5use super::{ByteOffset, Instruction, StackMapFrame};
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 pub fn stack_map_frames(
125 &self,
126 ) -> Option<impl ExactSizeIterator<Item = StackMapFrame<'a>> + '_> {
127 let entries = self
128 .inner
129 .code_attributes
130 .iter()
131 .find_map(|attribute| match attribute {
132 AttributeInfo::StackMapTable { entries } => Some(entries),
133 _ => None,
134 })?;
135
136 Some(
137 entries
138 .iter()
139 .map(|frame| StackMapFrame::new(frame, self.constant_pool)),
140 )
141 }
142}
143
144#[derive(Debug, Clone, Copy)]
145pub struct ExceptionHandler<'a> {
147 start: ByteOffset,
148 end: ByteOffset,
149 handler: ByteOffset,
150 catch_type: Option<&'a str>,
151}
152
153impl<'a> ExceptionHandler<'a> {
154 fn new(entry: &'a ExceptionTableEntry, constant_pool: &'a [CpInfo]) -> Self {
155 let catch_type = (entry.catch_type != 0)
156 .then(|| class_name(constant_pool, entry.catch_type))
157 .flatten();
158
159 Self {
160 start: ByteOffset::new(entry.start_pc),
161 end: ByteOffset::new(entry.end_pc),
162 handler: ByteOffset::new(entry.handler_pc),
163 catch_type,
164 }
165 }
166
167 #[must_use]
169 pub const fn start(&self) -> ByteOffset {
170 self.start
171 }
172
173 #[must_use]
175 pub const fn end(&self) -> ByteOffset {
176 self.end
177 }
178
179 #[must_use]
181 pub const fn handler(&self) -> ByteOffset {
182 self.handler
183 }
184
185 #[must_use]
189 pub const fn catch_type(&self) -> Option<&'a str> {
190 self.catch_type
191 }
192}
193
194fn class_name(constant_pool: &[CpInfo], index: u16) -> Option<&str> {
195 let CpInfo::Class { name_index } = constant_pool.get(index as usize)? else {
196 return None;
197 };
198 let CpInfo::Utf8(name) = constant_pool.get(*name_index as usize)? else {
199 return None;
200 };
201 Some(name)
202}