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> {
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}