use {AccessFlags, Type};
#[derive(Clone, Debug)]
pub struct Method
{
pub access_flags: AccessFlags,
pub name: String,
pub signature: MethodSignature,
pub bitcode: Vec<u8>,
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct MethodSignature
{
pub ret: Type,
pub parameters: Vec<Type>,
}
impl MethodSignature
{
pub fn parse_descriptor(s: &str) -> Option<Self> {
let closing_paren_idx = s.chars().position(|c| c == ')').unwrap();
let (mut before_paren, mut after_paren) = s.split_at(closing_paren_idx);
before_paren = &before_paren[1..]; after_paren = &after_paren[1..];
if before_paren.chars().last() == Some(';') {
before_paren = &before_paren[0..before_paren.len()-1];
}
if after_paren.chars().last() == Some(';') {
after_paren = &after_paren[0..after_paren.len()-1];
}
let ret = match Type::parse_descriptor(after_paren) {
Some(ty) => ty,
None => return None,
};
let mut parameters = Vec::new();
let mut chars_read = 0;
while chars_read != before_paren.len() {
let param_ty = Type::parse_descriptor(&before_paren[chars_read..]).unwrap();
chars_read += param_ty.descriptor().len();
parameters.push(param_ty);
}
Some(MethodSignature {
ret: ret,
parameters: parameters,
})
}
pub fn descriptor(&self) -> String {
let parameter_descriptors: Vec<_> = self.parameters.iter().map(Type::descriptor).collect();
let param_descriptor = format!("{};", parameter_descriptors.join(""));
format!("({}){};", param_descriptor, self.ret.descriptor())
}
}
#[cfg(test)]
mod test
{
use {Type, PrimitiveType};
use super::*;
#[test]
fn basic_signature_has_correct_descriptor() {
let sig = MethodSignature {
ret: Type::Class { name: "java/lang/Object".to_owned() },
parameters: vec![
Type::Primitive(PrimitiveType::Integer),
Type::Primitive(PrimitiveType::Double),
Type::Class { name: "java/lang/Thread".to_owned() },
],
};
assert_eq!(sig.descriptor(), "(IDLjava/lang/Thread;)Ljava/lang/Object;");
}
#[test]
fn can_parse_basic_sig() {
let sig = MethodSignature::parse_descriptor("(IDLjava/lang/Thread;)Ljava/lang/Object;");
assert_eq!(sig, Some(MethodSignature {
ret: Type::Class { name: "java/lang/Object".to_owned() },
parameters: vec![
Type::Primitive(PrimitiveType::Integer),
Type::Primitive(PrimitiveType::Double),
Type::Class { name: "java/lang/Thread".to_owned() },
],
}));
}
#[test]
fn can_parse_void_sig() {
let sig = MethodSignature::parse_descriptor("()V");
assert_eq!(sig, Some(MethodSignature {
ret: Type::Primitive(PrimitiveType::Void),
parameters: Vec::new(),
}));
}
}