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