1use crate::error::MethodDescriptorErr;
2use crate::jtype::{JavaType, ReturnType};
3
4pub type FieldDescriptor = JavaType;
7
8#[derive(Debug, Clone, PartialEq, Eq)]
11pub struct MethodDescriptor {
12 pub params: Vec<JavaType>,
13 pub ret: ReturnType,
14}
15
16impl MethodDescriptor {
17 pub fn to_java_signature(&self, class_name: &str, method_name: &str) -> String {
18 let mut buffer = String::with_capacity(
19 class_name.len() + method_name.len() + self.params.len() * 10 + 10,
20 );
21
22 use std::fmt::Write;
23 write!(buffer, "{} ", self.ret).unwrap();
24
25 for c in class_name.chars() {
26 buffer.push(if c == '/' { '.' } else { c });
27 }
28
29 write!(buffer, ".{}(", method_name).unwrap();
30
31 for (i, p) in self.params.iter().enumerate() {
32 if i > 0 {
33 buffer.push_str(", ");
34 }
35 write!(buffer, "{}", p).unwrap();
36 }
37
38 buffer.push(')');
39 buffer
40 }
41}
42
43impl TryFrom<&str> for MethodDescriptor {
44 type Error = MethodDescriptorErr;
45
46 fn try_from(desc: &str) -> Result<Self, Self::Error> {
47 let mut chars = desc.chars().peekable();
48
49 if chars.next() != Some('(') {
50 return Err(MethodDescriptorErr::ShouldStartWithParentheses(
51 desc.to_string(),
52 ));
53 }
54
55 let mut params = Vec::new();
56 loop {
57 match chars.peek() {
58 Some(')') => {
59 chars.next();
60 break;
61 }
62 Some(_) => params.push(
63 JavaType::try_recursive(&mut chars)
64 .map_err(|e| MethodDescriptorErr::Type(desc.to_string(), e))?,
65 ),
66 None => {
67 return Err(MethodDescriptorErr::MissingClosingParenthesis(
68 desc.to_string(),
69 ));
70 }
71 }
72 }
73
74 let ret = ReturnType::try_recursive(&mut chars)
75 .map_err(|e| MethodDescriptorErr::Type(desc.to_string(), e))?;
76
77 if chars.next().is_some() {
78 return Err(MethodDescriptorErr::TrailingCharacters);
79 }
80
81 Ok(MethodDescriptor { params, ret })
82 }
83}
84
85#[cfg(test)]
86mod tests {
87 use super::*;
88 use crate::jtype::PrimitiveType;
89
90 #[test]
92 fn parse_two_ints_void() {
93 let signature = "(II)V";
95 let expected_param = vec![
96 JavaType::Primitive(PrimitiveType::Int),
97 JavaType::Primitive(PrimitiveType::Int),
98 ];
99 let expected_ret = ReturnType::Void;
100
101 let md = MethodDescriptor::try_from(signature).unwrap();
103
104 assert_eq!(md.params, expected_param);
106 assert_eq!(md.ret, expected_ret);
107 }
108
109 #[test]
111 fn parse_no_params_int_return() {
112 let signature = "()I";
114 let expected_param: Vec<JavaType> = Vec::new();
115 let expected_ret = ReturnType::Type(JavaType::Primitive(PrimitiveType::Int));
116
117 let md = MethodDescriptor::try_from(signature).unwrap();
119
120 assert_eq!(md.params, expected_param);
122 assert_eq!(md.ret, expected_ret);
123 }
124
125 #[test]
127 fn parse_string_param_string_return() {
128 let signature = "(Ljava/lang/String;)Ljava/lang/String;";
130 let expected_param = vec![JavaType::Instance("java/lang/String".into())];
131 let expected_ret = ReturnType::Type(JavaType::Instance("java/lang/String".into()));
132
133 let md = MethodDescriptor::try_from(signature).unwrap();
135
136 assert_eq!(md.params, expected_param);
138 assert_eq!(md.ret, expected_ret);
139 }
140
141 #[test]
143 fn parse_array_param_and_return() {
144 let signature = "(I[Ljava/lang/String;)[I";
146 let expected_param = vec![
147 JavaType::Primitive(PrimitiveType::Int),
148 JavaType::Array(Box::new(JavaType::Instance("java/lang/String".into()))),
149 ];
150 let expected_ret = ReturnType::Type(JavaType::Array(Box::new(JavaType::Primitive(
151 PrimitiveType::Int,
152 ))));
153
154 let md = MethodDescriptor::try_from(signature).unwrap();
156
157 assert_eq!(md.params, expected_param);
159 assert_eq!(md.ret, expected_ret);
160 }
161
162 #[test]
164 fn parse_multi_dimensional_arrays() {
165 let signature = "([[Ljava/lang/Object;)[[Ljava/lang/Object;";
167 let obj = JavaType::Instance("java/lang/Object".into());
168 let two_d_obj = JavaType::Array(Box::new(JavaType::Array(Box::new(obj.clone()))));
169 let expected_param = vec![two_d_obj.clone()];
170 let expected_ret = ReturnType::Type(two_d_obj);
171
172 let md = MethodDescriptor::try_from(signature).unwrap();
174
175 assert_eq!(md.params, expected_param);
177 assert_eq!(md.ret, expected_ret);
178 }
179
180 #[test]
182 fn parse_void_param_should_fail() {
183 let signature = "(V)I";
184 let result = MethodDescriptor::try_from(signature);
185 assert!(result.is_err());
186 }
187
188 #[test]
190 fn parse_field_descriptor_int() {
191 let mut chars = "I".chars().peekable();
192 let field = JavaType::try_recursive(&mut chars).unwrap();
193 assert_eq!(field, JavaType::Primitive(PrimitiveType::Int));
194 }
195
196 #[test]
197 fn parse_field_descriptor_string() {
198 let mut chars = "Ljava/lang/String;".chars().peekable();
199 let field = JavaType::try_recursive(&mut chars).unwrap();
200 assert_eq!(field, JavaType::Instance("java/lang/String".into()));
201 }
202
203 #[test]
204 fn parse_field_descriptor_array() {
205 let mut chars = "[I".chars().peekable();
206 let field = JavaType::try_recursive(&mut chars).unwrap();
207 assert_eq!(
208 field,
209 JavaType::Array(Box::new(JavaType::Primitive(PrimitiveType::Int)))
210 );
211 }
212
213 #[test]
215 fn parse_field_descriptor_void_should_fail() {
216 let mut chars = "V".chars().peekable();
217 let result = JavaType::try_recursive(&mut chars);
218 assert!(result.is_err());
219 }
220}