Skip to content

Commit

Permalink
Support generating static class methods in the generator.
Browse files Browse the repository at this point in the history
Related to #76.
  • Loading branch information
Monnoroch committed Jul 25, 2018
1 parent cc05a6c commit 7d0ad57
Show file tree
Hide file tree
Showing 2 changed files with 149 additions and 29 deletions.
169 changes: 140 additions & 29 deletions generator/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -197,6 +197,7 @@ struct JavaClassMethod {
return_type: JavaName,
arguments: Vec<MethodArgument>,
public: bool,
is_static: bool,
}

#[derive(Debug, PartialEq, Eq, Clone)]
Expand Down Expand Up @@ -354,9 +355,10 @@ fn parse_metadata(tokens: TokenStream) -> Metadata {

fn parse_method(tokens: &[TokenTree]) -> JavaClassMethod {
let public = tokens.iter().any(|token| is_identifier(token, "public"));
let is_static = tokens.iter().any(|token| is_identifier(token, "static"));
let tokens = tokens
.iter()
.filter(|token| !is_identifier(token, "public"))
.filter(|token| !is_identifier(token, "public") && !is_identifier(token, "static"))
.cloned()
.collect::<Vec<_>>();
let name = match tokens[tokens.len() - 2].clone() {
Expand Down Expand Up @@ -393,6 +395,7 @@ fn parse_method(tokens: &[TokenTree]) -> JavaClassMethod {
name,
return_type,
arguments,
is_static,
}
}

Expand Down Expand Up @@ -955,6 +958,7 @@ struct ClassGeneratorDefinition {
signature: Literal,
full_signature: Literal,
methods: Vec<ClassMethodGeneratorDefinition>,
static_methods: Vec<ClassMethodGeneratorDefinition>,
}

#[derive(Debug, Clone)]
Expand Down Expand Up @@ -1012,6 +1016,32 @@ fn public_token(public: bool) -> TokenStream {
}
}

fn to_generator_method(method: JavaClassMethod) -> ClassMethodGeneratorDefinition {
let JavaClassMethod {
name,
public,
return_type,
arguments,
..
} = method;
let public = public_token(public);
let java_name = Literal::string(&name.to_string());
ClassMethodGeneratorDefinition {
name,
java_name,
public,
return_type: return_type.as_rust_type(),
argument_names: arguments
.iter()
.map(|argument| argument.name.clone())
.collect(),
argument_types: arguments
.iter()
.map(|argument| argument.data_type.clone().as_rust_type_reference())
.collect(),
}
}

fn to_generator_data(definitions: JavaDefinitions) -> GeneratorData {
let mut interface_extends = HashMap::new();
definitions
Expand Down Expand Up @@ -1153,35 +1183,17 @@ fn to_generator_data(definitions: JavaDefinitions) -> GeneratorData {
.map(|name| name.with_double_colons())
.collect::<Vec<_>>();
implements.sort_by(|left, right| left.to_string().cmp(&right.to_string()));
let static_methods = methods
.iter()
.filter(|method| method.is_static)
.cloned()
.map(to_generator_method)
.collect();
let methods = methods
.into_iter()
.map(|method| {
let JavaClassMethod {
name,
public,
return_type,
arguments,
..
} = method;
let public = public_token(public);
let java_name = Literal::string(&name.to_string());
ClassMethodGeneratorDefinition {
name,
java_name,
public,
return_type: return_type.as_rust_type(),
argument_names: arguments
.iter()
.map(|argument| argument.name.clone())
.collect(),
argument_types: arguments
.iter()
.map(|argument| {
argument.data_type.clone().as_rust_type_reference()
})
.collect(),
}
})
.iter()
.filter(|method| !method.is_static)
.cloned()
.map(to_generator_method)
.collect();
GeneratorDefinition::Class(ClassGeneratorDefinition {
class: definition_name,
Expand All @@ -1192,6 +1204,7 @@ fn to_generator_data(definitions: JavaDefinitions) -> GeneratorData {
signature,
full_signature,
methods,
static_methods,
})
}
JavaDefinitionKind::Interface(interface) => {
Expand Down Expand Up @@ -1286,6 +1299,7 @@ mod to_generator_data_tests {
signature: Literal::string("a/b/test1"),
full_signature: Literal::string("La/b/test1;"),
methods: vec![],
static_methods: vec![],
})],
}
);
Expand Down Expand Up @@ -1318,6 +1332,7 @@ mod to_generator_data_tests {
signature: Literal::string("a/b/test1"),
full_signature: Literal::string("La/b/test1;"),
methods: vec![],
static_methods: vec![],
})],
}
);
Expand Down Expand Up @@ -1381,6 +1396,7 @@ mod to_generator_data_tests {
signature: Literal::string("c/d/test2"),
full_signature: Literal::string("Lc/d/test2;"),
methods: vec![],
static_methods: vec![],
}),
GeneratorDefinition::Class(ClassGeneratorDefinition {
class: Ident::new("test1", Span::call_site()),
Expand All @@ -1396,6 +1412,7 @@ mod to_generator_data_tests {
signature: Literal::string("a/b/test1"),
full_signature: Literal::string("La/b/test1;"),
methods: vec![],
static_methods: vec![],
}),
],
}
Expand Down Expand Up @@ -1452,6 +1469,7 @@ mod to_generator_data_tests {
signature: Literal::string("a/b/test1"),
full_signature: Literal::string("La/b/test1;"),
methods: vec![],
static_methods: vec![],
}),
],
}
Expand Down Expand Up @@ -1519,6 +1537,7 @@ mod to_generator_data_tests {
signature: Literal::string("a/b/test1"),
full_signature: Literal::string("La/b/test1;"),
methods: vec![],
static_methods: vec![],
}),
],
}
Expand Down Expand Up @@ -1582,6 +1601,7 @@ mod to_generator_data_tests {
signature: Literal::string("a/b/test1"),
full_signature: Literal::string("La/b/test1;"),
methods: vec![],
static_methods: vec![],
}),
],
}
Expand Down Expand Up @@ -1615,6 +1635,7 @@ mod to_generator_data_tests {
signature: Literal::string("a/b/test1"),
full_signature: Literal::string("La/b/test1;"),
methods: vec![],
static_methods: vec![],
})],
}
);
Expand Down Expand Up @@ -1789,6 +1810,7 @@ mod to_generator_data_tests {
signature: Literal::string("a/b/test1"),
full_signature: Literal::string("La/b/test1;"),
methods: vec![],
static_methods: vec![],
}),
GeneratorDefinition::Class(ClassGeneratorDefinition {
class: Ident::new("test2", Span::call_site()),
Expand All @@ -1799,6 +1821,7 @@ mod to_generator_data_tests {
signature: Literal::string("test2"),
full_signature: Literal::string("Ltest2;"),
methods: vec![],
static_methods: vec![],
}),
],
}
Expand Down Expand Up @@ -1854,6 +1877,39 @@ fn generate_class_method(method: ClassMethodGeneratorDefinition) -> TokenStream
}
}

fn generate_static_class_method(method: ClassMethodGeneratorDefinition) -> TokenStream {
let ClassMethodGeneratorDefinition {
name,
java_name,
return_type,
public,
argument_names,
argument_types,
} = method;
let argument_names_1 = argument_names.clone();
let argument_types_1 = argument_types.clone();
quote!{
#public fn #name(
env: &'a ::rust_jni::JniEnv<'a>,
#(#argument_names: #argument_types,)*
token: &::rust_jni::NoException<'a>,
) -> ::rust_jni::JavaResult<'a, #return_type> {
// Safe because the method name and arguments are correct.
unsafe {
::rust_jni::__generator::call_static_method::<Self, _, _,
fn(#(#argument_types_1,)*) -> #return_type
>
(
env,
#java_name,
(#(#argument_names_1,)*),
token,
)
}
}
}
}

fn generate_class_definition(definition: ClassGeneratorDefinition) -> TokenStream {
let ClassGeneratorDefinition {
class,
Expand All @@ -1864,6 +1920,7 @@ fn generate_class_definition(definition: ClassGeneratorDefinition) -> TokenStrea
signature,
full_signature,
methods,
static_methods,
..
} = definition;
let multiplied_class = iter::repeat(class.clone());
Expand All @@ -1873,6 +1930,10 @@ fn generate_class_definition(definition: ClassGeneratorDefinition) -> TokenStrea
.into_iter()
.map(generate_class_method)
.collect::<Vec<_>>();
let static_methods = static_methods
.into_iter()
.map(generate_static_class_method)
.collect::<Vec<_>>();
quote! {
#[derive(Debug)]
#public struct #class<'env> {
Expand Down Expand Up @@ -1950,6 +2011,10 @@ fn generate_class_definition(definition: ClassGeneratorDefinition) -> TokenStrea
#(
#methods
)*

#(
#static_methods
)*
}

impl<'a> ::std::fmt::Display for #class<'a> {
Expand Down Expand Up @@ -2016,6 +2081,7 @@ mod generate_tests {
signature: Literal::string("test/sign1"),
full_signature: Literal::string("test/signature1"),
methods: vec![],
static_methods: vec![],
})],
};
let expected = quote!{
Expand Down Expand Up @@ -2120,6 +2186,7 @@ mod generate_tests {
signature: Literal::string("test/sign1"),
full_signature: Literal::string("test/signature1"),
methods: vec![],
static_methods: vec![],
})],
};
let expected = quote!{
Expand Down Expand Up @@ -2277,6 +2344,7 @@ mod generate_tests {
signature: Literal::string("test/sign1"),
full_signature: Literal::string("test/signature1"),
methods: vec![],
static_methods: vec![],
}),
GeneratorDefinition::Class(ClassGeneratorDefinition {
class: Ident::new("test2", Span::call_site()),
Expand All @@ -2287,6 +2355,7 @@ mod generate_tests {
signature: Literal::string("test/sign2"),
full_signature: Literal::string("test/signature2"),
methods: vec![],
static_methods: vec![],
}),
],
};
Expand Down Expand Up @@ -3138,6 +3207,9 @@ mod java_generate_tests {
public class a.b.TestClass3 extends c.d.TestClass2 implements e.f.TestInterface1, a.b.TestInterface4 {
long primitiveFunc3(int arg1, char arg2);
public c.d.TestClass2 objectFunc3(a.b.TestClass3 arg);

static long primitiveStaticFunc3(int arg1, char arg2);
public static c.d.TestClass2 objectStaticFunc3(a.b.TestClass3 arg);
}

metadata {
Expand Down Expand Up @@ -3278,6 +3350,45 @@ mod java_generate_tests {
)
}
}

fn primitiveStaticFunc3(
env: &'a ::rust_jni::JniEnv<'a>,
arg1: i32,
arg2: char,
token: &::rust_jni::NoException<'a>,
) -> ::rust_jni::JavaResult<'a, i64> {
// Safe because the method name and arguments are correct.
unsafe {
::rust_jni::__generator::call_static_method::<Self, _, _,
fn(i32, char,) -> i64
>
(
env,
"primitiveStaticFunc3",
(arg1, arg2,),
token,
)
}
}

pub fn objectStaticFunc3(
env: &'a ::rust_jni::JniEnv<'a>,
arg: &::a::b::TestClass3,
token: &::rust_jni::NoException<'a>,
) -> ::rust_jni::JavaResult<'a, ::c::d::TestClass2<'a> > {
// Safe because the method name and arguments are correct.
unsafe {
::rust_jni::__generator::call_static_method::<Self, _, _,
fn(&::a::b::TestClass3,) -> ::c::d::TestClass2<'a>
>
(
env,
"objectStaticFunc3",
(arg,),
token,
)
}
}
}

impl<'a> ::std::fmt::Display for TestClass3<'a> {
Expand Down
9 changes: 9 additions & 0 deletions generator/tests/test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,10 +33,16 @@ mod c {
public class c.d.TestClass1 {
public long primitiveFunc1(int arg1, char arg2);
c.d.TestClass1 objectFunc1(c.d.TestClass1 arg);

public static long primitiveStaticFunc1(int arg1, char arg2);
static c.d.TestClass1 objectStaticFunc1(c.d.TestClass1 arg);
}
public class c.d.TestClass2 extends c.d.TestClass1 implements e.f.TestInterface1 {
long primitiveFunc2(int arg1, char arg2);
public c.d.TestClass2 objectFunc2(c.d.TestClass1 arg);

long static primitiveStaticFunc2(int arg1, char arg2);
public static c.d.TestClass2 objectStaticFunc2(c.d.TestClass1 arg);
}

metadata {
Expand All @@ -59,6 +65,9 @@ mod a {
public class a.b.TestClass3 extends c.d.TestClass2 implements e.f.TestInterface1, a.b.TestInterface4 {
long primitiveFunc3(int arg1, char arg2);
public c.d.TestClass2 objectFunc3(a.b.TestClass3 arg);

public static long primitiveStaticFunc3(int arg1, char arg2);
static c.d.TestClass1 objectStaticFunc3(c.d.TestClass1 arg);
}

metadata {
Expand Down

0 comments on commit 7d0ad57

Please sign in to comment.