1use core::fmt::{Debug, Display};
2
3use alloc::{boxed::Box, vec::Vec};
4use smallvec::SmallVec;
5
6use crate::{Cursor, Parse, TypeParameter, TypeSignature, UnknownTypeTag, ty::FieldType};
7
8#[derive(Debug, Clone)]
10#[non_exhaustive]
11pub enum InvalidMethodDescriptor {
12 BrokenBrackets,
14 UnknownFieldTy(UnknownTypeTag),
16}
17
18impl core::error::Error for InvalidMethodDescriptor {}
19
20impl From<UnknownTypeTag> for InvalidMethodDescriptor {
21 fn from(value: UnknownTypeTag) -> Self {
22 Self::UnknownFieldTy(value)
23 }
24}
25
26impl Display for InvalidMethodDescriptor {
27 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
28 match self {
29 Self::BrokenBrackets => write!(f, "broken brackets"),
30 Self::UnknownFieldTy(unknown_field_ty) => {
31 write!(f, "{unknown_field_ty}")
32 }
33 }
34 }
35}
36
37#[derive(Clone, PartialEq, Eq, Hash)]
41pub struct MethodDescriptor<'a> {
42 pub params: SmallVec<[FieldType<'a>; 4]>,
44 pub ret: MethodReturnDescriptor<'a>,
46}
47
48impl Display for MethodDescriptor<'_> {
49 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
50 write!(f, "(")?;
51 for param in &self.params {
52 write!(f, "{param}")?;
53 }
54 write!(f, "){}", self.ret)
55 }
56}
57
58impl<'a> Parse<'a> for MethodDescriptor<'a> {
59 type Error = InvalidMethodDescriptor;
60
61 fn parse_from(cursor: &mut Cursor<'a>) -> Result<Self, Self::Error> {
62 if cursor.get_char() != '(' {
63 return Err(InvalidMethodDescriptor::BrokenBrackets);
64 }
65 let mut params_raw = Cursor::new(cursor.try_advance(|s| {
66 s.split_once(')')
67 .ok_or(InvalidMethodDescriptor::BrokenBrackets)
68 })?);
69 let mut params = SmallVec::new();
70 while !params_raw.get().is_empty() {
71 params.push(FieldType::parse_from(&mut params_raw)?);
72 }
73 Ok(Self {
74 params,
75 ret: MethodReturnDescriptor::parse_from(cursor)?,
76 })
77 }
78}
79
80#[derive(Clone, PartialEq, Eq, Hash)]
82pub enum MethodReturnDescriptor<'a> {
83 Void,
85 Type(FieldType<'a>),
87}
88
89impl Display for MethodReturnDescriptor<'_> {
90 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
91 match self {
92 MethodReturnDescriptor::Void => write!(f, "V"),
93 MethodReturnDescriptor::Type(field_ty) => write!(f, "{field_ty}"),
94 }
95 }
96}
97
98impl<'a> Parse<'a> for MethodReturnDescriptor<'a> {
99 type Error = UnknownTypeTag;
100
101 fn parse_from(cursor: &mut Cursor<'a>) -> Result<Self, Self::Error> {
102 if cursor.get().chars().next().is_some_and(|c| c == 'V') {
103 cursor.advance_by('V'.len_utf8());
104 Ok(Self::Void)
105 } else {
106 FieldType::parse_from(cursor).map(Self::Type)
107 }
108 }
109}
110
111impl Debug for MethodReturnDescriptor<'_> {
112 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
113 match self {
114 Self::Void => write!(f, "void"),
115 Self::Type(ty) => Debug::fmt(ty, f),
116 }
117 }
118}
119
120impl Debug for MethodDescriptor<'_> {
121 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
122 write!(f, "method(")?;
123 let mut it = self.params.iter();
124 if let Some(first) = it.next() {
125 Debug::fmt(first, f)?;
126 }
127 for param in it {
128 write!(f, ", ")?;
129 Debug::fmt(param, f)?;
130 }
131 write!(f, ") -> ")?;
132 Debug::fmt(&self.ret, f)
133 }
134}
135
136#[derive(PartialEq, Eq, Clone)]
138pub struct MethodSignature<'a> {
139 pub params: SmallVec<[TypeParameter<'a>; 1]>,
141 pub args: SmallVec<[TypeSignature<'a>; 2]>,
143 pub result: MethodReturnSignature<'a>,
145 pub throws: Box<[TypeSignature<'a>]>,
147}
148
149#[derive(PartialEq, Eq, Clone)]
151pub enum MethodReturnSignature<'a> {
152 Void,
154 Type(TypeSignature<'a>),
156}
157
158#[derive(Debug, Clone)]
160#[non_exhaustive]
161pub enum InvalidMethodSignature {
162 UnclosedAngles,
164 UnclosedBrackets,
166 UnknownTypeTag(UnknownTypeTag),
168 ExpectedReference,
170 ExpectedBracket,
172 ExpectedClassOrTypeVar,
174}
175
176impl<'a> Parse<'a> for MethodSignature<'a> {
177 type Error = InvalidMethodSignature;
178
179 fn parse_from(cursor: &mut Cursor<'a>) -> Result<Self, Self::Error> {
180 let mut params = SmallVec::new();
181 if cursor.0.starts_with('<') {
182 cursor.get_char();
183 let contents = cursor.try_advance(|s| {
184 crate::angle_safe_split(s, &['>']).ok_or(InvalidMethodSignature::UnclosedAngles)
185 })?;
186 cursor.get_char();
187 let mut contents = Cursor(contents);
188 crate::parse_type_params(&mut contents, |param| params.push(param))?;
189 }
190
191 let mut args = SmallVec::new();
192 if cursor.get_char() != '(' {
193 return Err(InvalidMethodSignature::ExpectedBracket);
194 }
195 let contents = cursor.try_advance(|s| {
196 s.split_once(')')
198 .ok_or(InvalidMethodSignature::UnclosedBrackets)
199 })?;
200 let mut contents = Cursor(contents);
201 while !contents.0.is_empty() {
202 args.push(TypeSignature::parse_from(&mut contents)?);
203 }
204
205 let result = MethodReturnSignature::parse_from(cursor)?;
206
207 let mut throws = Vec::new();
208 while !cursor.0.is_empty() && cursor.get_char() == '^' {
209 let exception = TypeSignature::parse_from(cursor)?;
210 if !matches!(
211 exception,
212 TypeSignature::Class { .. } | TypeSignature::Type(_)
213 ) {
214 return Err(InvalidMethodSignature::ExpectedClassOrTypeVar);
215 }
216 throws.push(exception);
217 }
218
219 Ok(Self {
220 params,
221 args,
222 result,
223 throws: throws.into(),
224 })
225 }
226}
227
228impl Display for MethodSignature<'_> {
229 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
230 if !self.params.is_empty() {
231 crate::display_type_params(&self.params, f)?;
232 }
233 write!(f, "(")?;
234 for arg in &self.args {
235 write!(f, "{arg}")?;
236 }
237 write!(f, "){}", self.result)?;
238 for thrown in &self.throws {
239 write!(f, "^{}", thrown)?;
240 }
241 Ok(())
242 }
243}
244
245impl<'a> Parse<'a> for MethodReturnSignature<'a> {
246 type Error = UnknownTypeTag;
247
248 fn parse_from(cursor: &mut Cursor<'a>) -> Result<Self, Self::Error> {
249 if cursor.0.starts_with('V') {
250 cursor.advance_by(1);
251 Ok(Self::Void)
252 } else {
253 TypeSignature::parse_from(cursor).map(Self::Type)
254 }
255 }
256}
257
258impl Display for MethodReturnSignature<'_> {
259 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
260 match self {
261 MethodReturnSignature::Void => write!(f, "V"),
262 MethodReturnSignature::Type(sig) => write!(f, "{sig}"),
263 }
264 }
265}
266
267impl Display for InvalidMethodSignature {
268 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
269 match self {
270 Self::UnclosedAngles => write!(f, "unclosed angles"),
271 Self::UnclosedBrackets => write!(f, "unclosed brackets"),
272 Self::UnknownTypeTag(err) => write!(f, "{err}"),
273 Self::ExpectedReference => {
274 write!(f, "expected type signature to be `ReferenceTypeSignature`")
275 }
276 Self::ExpectedBracket => write!(f, "expected left bracket"),
277 Self::ExpectedClassOrTypeVar => write!(
278 f,
279 "expected exception signature to be either `ClassTypeSignature` or `TypeVariableSignature`"
280 ),
281 }
282 }
283}
284
285impl core::error::Error for InvalidMethodSignature {
286 fn source(&self) -> Option<&(dyn core::error::Error + 'static)> {
287 match self {
288 Self::UnknownTypeTag(err) => Some(err),
289 _ => None,
290 }
291 }
292}
293
294impl From<UnknownTypeTag> for InvalidMethodSignature {
295 fn from(value: UnknownTypeTag) -> Self {
296 Self::UnknownTypeTag(value)
297 }
298}
299
300impl From<crate::ParseTypeParamsError> for InvalidMethodSignature {
301 fn from(value: crate::ParseTypeParamsError) -> Self {
302 match value {
303 crate::ParseTypeParamsError::UnknownTypeTag(err) => Self::UnknownTypeTag(err),
304 crate::ParseTypeParamsError::ExpectedReference => Self::ExpectedReference,
305 }
306 }
307}
308
309impl Debug for MethodSignature<'_> {
310 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
311 if !self.params.is_empty() {
312 write!(f, "<")?;
313 let mut it = self.params.iter().peekable();
314 while let Some(param) = it.next() {
315 write!(f, "{param:?}")?;
316 if it.peek().is_some() {
317 write!(f, ", ")?;
318 }
319 }
320 write!(f, ">::")?;
321 }
322 write!(f, "(")?;
323 let mut it = self.args.iter().peekable();
324 while let Some(arg) = it.next() {
325 write!(f, "{arg:?}")?;
326 if it.peek().is_some() {
327 write!(f, ", ")?;
328 }
329 }
330 write!(f, ") -> {:?}", self.result)?;
331 if !self.throws.is_empty() {
332 write!(f, " throws ")?;
333 let mut it = self.throws.iter().peekable();
334 while let Some(exception) = it.next() {
335 write!(f, "{exception:?}")?;
336 if it.peek().is_some() {
337 write!(f, ", ")?;
338 }
339 }
340 }
341 Ok(())
342 }
343}
344
345impl Debug for MethodReturnSignature<'_> {
346 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
347 match self {
348 MethodReturnSignature::Void => write!(f, "void"),
349 MethodReturnSignature::Type(ty) => write!(f, "{ty:?}"),
350 }
351 }
352}
353
354#[cfg(test)]
355mod tests {
356 use alloc::boxed::Box;
357 use smallvec::SmallVec;
358
359 use crate::{
360 FieldType, MethodDescriptor, MethodReturnDescriptor, MethodReturnSignature,
361 MethodSignature, PrimitiveType, TypeParameter, TypeSignature, parse, validate_rw,
362 };
363
364 #[test]
365 fn return_desc_void() {
366 assert_eq!(
367 parse::<'_, MethodReturnDescriptor<'_>>("V").unwrap(),
368 MethodReturnDescriptor::Void
369 );
370 validate_rw::<'_, MethodReturnDescriptor<'_>>("V");
371 }
372
373 #[test]
374 fn return_desc_primitive() {
375 assert_eq!(
376 parse::<'_, MethodReturnDescriptor<'_>>("I").unwrap(),
377 MethodReturnDescriptor::Type(FieldType::Primitive(PrimitiveType::Int))
378 );
379 validate_rw::<'_, MethodReturnDescriptor<'_>>("I");
380 }
381
382 #[test]
383 fn empty_to_void() {
384 assert_eq!(
385 parse::<'_, MethodDescriptor<'_>>("()V").unwrap(),
386 MethodDescriptor {
387 params: SmallVec::new(),
388 ret: MethodReturnDescriptor::Void
389 }
390 );
391 validate_rw::<'_, MethodDescriptor<'_>>("()V");
392 }
393
394 #[test]
395 fn mixed() {
396 assert_eq!(
397 parse::<'_, MethodDescriptor<'_>>(
398 "(I[BLjava/lang/String;Ljava/lang/Object;Z)[Ljava/lang/String;"
399 )
400 .unwrap(),
401 MethodDescriptor {
402 params: smallvec::smallvec![
403 FieldType::Primitive(PrimitiveType::Int),
404 FieldType::Array(Box::new(FieldType::Primitive(PrimitiveType::Byte))),
405 FieldType::Class("java/lang/String"),
406 FieldType::Class("java/lang/Object"),
407 FieldType::Primitive(PrimitiveType::Boolean),
408 ],
409 ret: MethodReturnDescriptor::Type(FieldType::Array(Box::new(FieldType::Class(
410 "java/lang/String"
411 ))))
412 }
413 );
414 validate_rw::<'_, MethodDescriptor<'_>>(
415 "(I[BLjava/lang/String;Ljava/lang/Object;Z)[Ljava/lang/String;",
416 );
417 }
418
419 #[test]
420 fn method_sig() {
421 assert_eq!(
422 parse::<'_, MethodSignature<'_>>(
423 "(Ljava/lang/String;I)V^Ljava/io/IOException;^Ljava/lang/SecurityException;"
424 )
425 .unwrap(),
426 MethodSignature {
427 params: SmallVec::new(),
428 args: smallvec::smallvec![
429 TypeSignature::Class {
430 sig: crate::ReducedClassTypeSignature {
431 name: "java/lang/String",
432 args: SmallVec::new()
433 },
434 suffix: None
435 },
436 TypeSignature::Primitive(PrimitiveType::Int)
437 ],
438 result: MethodReturnSignature::Void,
439 throws: Box::new([
440 TypeSignature::Class {
441 sig: crate::ReducedClassTypeSignature {
442 name: "java/io/IOException",
443 args: SmallVec::new()
444 },
445 suffix: None
446 },
447 TypeSignature::Class {
448 sig: crate::ReducedClassTypeSignature {
449 name: "java/lang/SecurityException",
450 args: SmallVec::new()
451 },
452 suffix: None
453 },
454 ])
455 }
456 );
457 validate_rw::<'_, MethodSignature<'_>>(
458 "(Ljava/lang/String;I)V^Ljava/io/IOException;^Ljava/lang/SecurityException;",
459 );
460
461 assert_eq!(
462 parse::<'_, MethodSignature<'_>>("<T:Ljava/lang/Exception;>(TT;)TT;^TT;").unwrap(),
463 MethodSignature {
464 params: smallvec::smallvec![TypeParameter {
465 name: "T",
466 bound_class: Some(TypeSignature::Class {
467 sig: crate::ReducedClassTypeSignature {
468 name: "java/lang/Exception",
469 args: SmallVec::new()
470 },
471 suffix: None
472 }),
473 bound_interface: Box::new([])
474 }],
475 args: smallvec::smallvec![TypeSignature::Type("T")],
476 result: MethodReturnSignature::Type(TypeSignature::Type("T")),
477 throws: Box::new([TypeSignature::Type("T")])
478 }
479 );
480 validate_rw::<'_, MethodSignature<'_>>("<T:Ljava/lang/Exception;>(TT;)TT;^TT;");
481 }
482}