1use core::fmt::{Debug, Display};
2
3use smallvec::SmallVec;
4
5use crate::{Cursor, Parse, UnknownTypeTag, ty::FieldType};
6
7#[derive(Debug, Clone)]
9pub enum InvalidMethodDescriptor {
10 BrokenBrackets,
12 UnknownFieldTy(UnknownTypeTag),
14}
15
16impl core::error::Error for InvalidMethodDescriptor {}
17
18impl From<UnknownTypeTag> for InvalidMethodDescriptor {
19 fn from(value: UnknownTypeTag) -> Self {
20 Self::UnknownFieldTy(value)
21 }
22}
23
24impl Display for InvalidMethodDescriptor {
25 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
26 match self {
27 Self::BrokenBrackets => write!(f, "broken brackets"),
28 Self::UnknownFieldTy(unknown_field_ty) => {
29 write!(f, "{unknown_field_ty}")
30 }
31 }
32 }
33}
34
35#[derive(Clone, PartialEq, Eq, Hash)]
39pub struct MethodDescriptor<'a> {
40 pub params: SmallVec<[FieldType<'a>; 4]>,
42 pub ret: MethodReturnDescriptor<'a>,
44}
45
46impl Display for MethodDescriptor<'_> {
47 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
48 write!(f, "(")?;
49 for param in &self.params {
50 write!(f, "{param}")?;
51 }
52 write!(f, "){}", self.ret)
53 }
54}
55
56impl<'a> Parse<'a> for MethodDescriptor<'a> {
57 type Error = InvalidMethodDescriptor;
58
59 fn parse_from(cursor: &mut Cursor<'a>) -> Result<Self, Self::Error> {
60 if cursor.get_char() != '(' {
61 return Err(InvalidMethodDescriptor::BrokenBrackets);
62 }
63 let mut params_raw = Cursor::new(cursor.try_advance(|s| {
64 s.split_once(')')
65 .ok_or(InvalidMethodDescriptor::BrokenBrackets)
66 })?);
67 let mut params = SmallVec::new();
68 while !params_raw.get().is_empty() {
69 params.push(FieldType::parse_from(&mut params_raw)?);
70 }
71 Ok(Self {
72 params,
73 ret: MethodReturnDescriptor::parse_from(cursor)?,
74 })
75 }
76}
77
78#[derive(Clone, PartialEq, Eq, Hash)]
80pub enum MethodReturnDescriptor<'a> {
81 Void,
83 Type(FieldType<'a>),
85}
86
87impl Display for MethodReturnDescriptor<'_> {
88 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
89 match self {
90 MethodReturnDescriptor::Void => write!(f, "V"),
91 MethodReturnDescriptor::Type(field_ty) => write!(f, "{field_ty}"),
92 }
93 }
94}
95
96impl<'a> Parse<'a> for MethodReturnDescriptor<'a> {
97 type Error = UnknownTypeTag;
98
99 fn parse_from(cursor: &mut Cursor<'a>) -> Result<Self, Self::Error> {
100 if cursor.get().chars().next().is_some_and(|c| c == 'V') {
101 cursor.advance_by('V'.len_utf8());
102 Ok(Self::Void)
103 } else {
104 FieldType::parse_from(cursor).map(Self::Type)
105 }
106 }
107}
108
109impl Debug for MethodReturnDescriptor<'_> {
110 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
111 match self {
112 Self::Void => write!(f, "void"),
113 Self::Type(ty) => Debug::fmt(ty, f),
114 }
115 }
116}
117
118impl Debug for MethodDescriptor<'_> {
119 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
120 write!(f, "method(")?;
121 let mut it = self.params.iter();
122 if let Some(first) = it.next() {
123 Debug::fmt(first, f)?;
124 }
125 for param in it {
126 write!(f, ", ")?;
127 Debug::fmt(param, f)?;
128 }
129 write!(f, ") -> ")?;
130 Debug::fmt(&self.ret, f)
131 }
132}
133
134#[cfg(test)]
135mod tests {
136 use alloc::boxed::Box;
137 use smallvec::SmallVec;
138
139 use crate::{
140 FieldType, MethodDescriptor, MethodReturnDescriptor, PrimitiveType, parse, validate_rw,
141 };
142
143 #[test]
144 fn return_desc_void() {
145 assert_eq!(
146 parse::<'_, MethodReturnDescriptor<'_>>("V").unwrap(),
147 MethodReturnDescriptor::Void
148 );
149 validate_rw::<'_, MethodReturnDescriptor<'_>>("V");
150 }
151
152 #[test]
153 fn return_desc_primitive() {
154 assert_eq!(
155 parse::<'_, MethodReturnDescriptor<'_>>("I").unwrap(),
156 MethodReturnDescriptor::Type(FieldType::Primitive(PrimitiveType::Int))
157 );
158 validate_rw::<'_, MethodReturnDescriptor<'_>>("I");
159 }
160
161 #[test]
162 fn empty_to_void() {
163 assert_eq!(
164 parse::<'_, MethodDescriptor<'_>>("()V").unwrap(),
165 MethodDescriptor {
166 params: SmallVec::new(),
167 ret: MethodReturnDescriptor::Void
168 }
169 );
170 validate_rw::<'_, MethodDescriptor<'_>>("()V");
171 }
172
173 #[test]
174 fn mixed() {
175 assert_eq!(
176 parse::<'_, MethodDescriptor<'_>>(
177 "(I[BLjava/lang/String;Ljava/lang/Object;Z)[Ljava/lang/String;"
178 )
179 .unwrap(),
180 MethodDescriptor {
181 params: smallvec::smallvec![
182 FieldType::Primitive(PrimitiveType::Int),
183 FieldType::Array(Box::new(FieldType::Primitive(PrimitiveType::Byte))),
184 FieldType::Class("java/lang/String"),
185 FieldType::Class("java/lang/Object"),
186 FieldType::Primitive(PrimitiveType::Boolean),
187 ],
188 ret: MethodReturnDescriptor::Type(FieldType::Array(Box::new(FieldType::Class(
189 "java/lang/String"
190 ))))
191 }
192 );
193 validate_rw::<'_, MethodDescriptor<'_>>(
194 "(I[BLjava/lang/String;Ljava/lang/Object;Z)[Ljava/lang/String;",
195 );
196 }
197}