diff --git a/generator/src/lib.rs b/generator/src/lib.rs index cf8f38b..ec6fc9d 100644 --- a/generator/src/lib.rs +++ b/generator/src/lib.rs @@ -249,6 +249,13 @@ struct MethodArgument { data_type: JavaName, } +#[derive(Debug, PartialEq, Eq, Clone)] +struct JavaInterfaceMethod { + name: Ident, + return_type: JavaName, + arguments: Vec, +} + #[derive(Debug, PartialEq, Eq, Clone)] struct JavaClassMethod { name: Ident, @@ -293,6 +300,7 @@ struct JavaClass { #[derive(Debug, PartialEq, Eq, Clone)] struct JavaInterface { + methods: Vec, extends: Vec, } @@ -318,6 +326,7 @@ struct JavaClassMetadata { #[derive(Debug, PartialEq, Eq, Clone)] struct JavaInterfaceMetadata { extends: Vec, + methods: Vec, } #[derive(Debug, PartialEq, Eq, Clone)] @@ -420,6 +429,7 @@ fn parse_metadata(tokens: TokenStream) -> Metadata { name, definition: JavaDefinitionMetadataKind::Interface(JavaInterfaceMetadata { extends, + methods: vec![], }), } } else { @@ -433,7 +443,34 @@ fn parse_metadata(tokens: TokenStream) -> Metadata { } } }) - .collect::>(); + .zip(definitions.iter().cloned().filter(is_metadata_definition)) + .map(|(definition, token)| match token { + TokenTree::Group(group) => (definition, group.stream()), + TokenTree::Punct(_) => (definition, TokenStream::new()), + _ => unreachable!(), + }) + .map(|(definition, tokens)| { + let java_definition = match definition.definition.clone() { + JavaDefinitionMetadataKind::Interface(interface) => { + let methods = tokens.into_iter().collect::>(); + let methods = methods + .split(|token| is_punctuation(token, ';')) + .filter(|tokens| !tokens.is_empty()) + .map(parse_interface_method) + .collect::>(); + JavaDefinitionMetadataKind::Interface(JavaInterfaceMetadata { + methods, + ..interface + }) + } + definition => definition, + }; + JavaDefinitionMetadata { + definition: java_definition, + ..definition + } + }) + .collect(); Metadata { definitions } } @@ -498,6 +535,21 @@ fn parse_method(tokens: &[TokenTree]) -> JavaClassMethod { } } +fn parse_interface_method(tokens: &[TokenTree]) -> JavaInterfaceMethod { + let tokens = tokens.iter().cloned().collect::>(); + let name = match tokens[tokens.len() - 2].clone() { + TokenTree::Ident(ident) => ident, + token => panic!("Expected method name, got {:?}.", token), + }; + let return_type = JavaName::from_tokens(tokens[0..tokens.len() - 2].iter()); + let arguments = parse_method_arguments(tokens[tokens.len() - 1].clone()); + JavaInterfaceMethod { + name, + return_type, + arguments, + } +} + fn parse_native_method(tokens: &[TokenTree]) -> JavaNativeMethod { let public = tokens.iter().any(|token| is_identifier(token, "public")); let is_static = tokens.iter().any(|token| is_identifier(token, "static")); @@ -591,7 +643,10 @@ fn parse_java_definition(input: TokenStream) -> JavaDefinitions { JavaDefinition { name, public, - definition: JavaDefinitionKind::Interface(JavaInterface { extends }), + definition: JavaDefinitionKind::Interface(JavaInterface { + methods: vec![], + extends, + }), } } else { let (name, extends, implements) = parse_class_header(header); @@ -645,7 +700,15 @@ fn parse_java_definition(input: TokenStream) -> JavaDefinitions { }) } JavaDefinitionKind::Interface(interface) => { - JavaDefinitionKind::Interface(JavaInterface { ..interface }) + let methods = methods + .split(|token| is_punctuation(token, ';')) + .filter(|tokens| !tokens.is_empty()) + .map(parse_interface_method) + .collect::>(); + JavaDefinitionKind::Interface(JavaInterface { + methods, + ..interface + }) } }; JavaDefinition { @@ -848,7 +911,10 @@ mod parse_tests { definitions: vec![JavaDefinition { name: JavaName(quote!{TestInterface1}), public: false, - definition: JavaDefinitionKind::Interface(JavaInterface { extends: vec![] }), + definition: JavaDefinitionKind::Interface(JavaInterface { + methods: vec![], + extends: vec![], + }), }], metadata: Metadata { definitions: vec![], @@ -868,7 +934,10 @@ mod parse_tests { definitions: vec![JavaDefinition { name: JavaName(quote!{TestInterface1}), public: true, - definition: JavaDefinitionKind::Interface(JavaInterface { extends: vec![] }), + definition: JavaDefinitionKind::Interface(JavaInterface { + methods: vec![], + extends: vec![], + }), }], metadata: Metadata { definitions: vec![], @@ -888,7 +957,10 @@ mod parse_tests { definitions: vec![JavaDefinition { name: JavaName(quote!{a b TestInterface1}), public: false, - definition: JavaDefinitionKind::Interface(JavaInterface { extends: vec![] }), + definition: JavaDefinitionKind::Interface(JavaInterface { + methods: vec![], + extends: vec![], + }), }], metadata: Metadata { definitions: vec![], @@ -909,6 +981,7 @@ mod parse_tests { name: JavaName(quote!{TestInterface1}), public: false, definition: JavaDefinitionKind::Interface(JavaInterface { + methods: vec![], extends: vec![ JavaName(quote!{TestInterface2}), JavaName(quote!{a b TestInterface3}), @@ -938,6 +1011,7 @@ mod parse_tests { name: JavaName(quote!{TestInterface1}), public: false, definition: JavaDefinitionKind::Interface(JavaInterface { + methods: vec![], extends: vec![], }), }, @@ -945,6 +1019,7 @@ mod parse_tests { name: JavaName(quote!{TestInterface2}), public: false, definition: JavaDefinitionKind::Interface(JavaInterface { + methods: vec![], extends: vec![], }), }, @@ -1013,7 +1088,10 @@ mod parse_tests { JavaDefinitionMetadata { name: JavaName(quote!{TestInterface1}), definition: JavaDefinitionMetadataKind::Interface( - JavaInterfaceMetadata { extends: vec![] }, + JavaInterfaceMetadata { + extends: vec![], + methods: vec![], + }, ), }, JavaDefinitionMetadata { @@ -1021,6 +1099,7 @@ mod parse_tests { definition: JavaDefinitionMetadataKind::Interface( JavaInterfaceMetadata { extends: vec![JavaName(quote!{TestInterface1})], + methods: vec![], }, ), }, @@ -1132,6 +1211,23 @@ struct ClassMethodGeneratorDefinition { public: TokenStream, } +#[derive(Debug, Clone)] +struct InterfaceMethodGeneratorDefinition { + name: Ident, + return_type: TokenStream, + argument_names: Vec, + argument_types: Vec, +} + +#[derive(Debug, Clone)] +struct InterfaceMethodImplementationGeneratorDefinition { + name: Ident, + return_type: TokenStream, + argument_names: Vec, + argument_types: Vec, + class_cast: TokenStream, +} + #[derive(Debug, Clone)] struct NativeMethodGeneratorDefinition { name: Ident, @@ -1152,13 +1248,19 @@ struct ConstructorGeneratorDefinition { public: TokenStream, } +#[derive(Debug, Clone)] +struct InterfaceImplementationGeneratorDefinition { + interface: TokenStream, + methods: Vec, +} + #[derive(Debug, Clone)] struct ClassGeneratorDefinition { class: Ident, public: TokenStream, super_class: TokenStream, transitive_extends: Vec, - implements: Vec, + implements: Vec, signature: Literal, full_signature: Literal, constructors: Vec, @@ -1173,6 +1275,7 @@ struct InterfaceGeneratorDefinition { interface: Ident, public: TokenStream, extends: Vec, + methods: Vec, } #[derive(Debug, Clone)] @@ -1249,6 +1352,66 @@ fn to_generator_method(method: JavaClassMethod) -> ClassMethodGeneratorDefinitio } } +fn to_generator_interface_method( + method: JavaInterfaceMethod, +) -> InterfaceMethodGeneratorDefinition { + let JavaInterfaceMethod { + name, + return_type, + arguments, + .. + } = method; + InterfaceMethodGeneratorDefinition { + name, + 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_interface_method_implementation( + method: JavaInterfaceMethod, + class_methods: &Vec, + interface: &JavaName, + super_class: &TokenStream, +) -> InterfaceMethodImplementationGeneratorDefinition { + let JavaInterfaceMethod { + name, + return_type, + arguments, + .. + } = method; + let class_has_method = class_methods.iter().any(|class_method| { + class_method.name == name + && class_method.return_type == return_type + && class_method.arguments == arguments + }); + let interface = interface.clone().with_double_colons(); + InterfaceMethodImplementationGeneratorDefinition { + name, + 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(), + class_cast: if class_has_method { + quote!{Self} + } else { + quote!{ <#super_class as #interface> } + }, + } +} + fn to_generator_native_method( method: JavaNativeMethod, class_name: &JavaName, @@ -1412,769 +1575,858 @@ fn to_generator_data(definitions: JavaDefinitions) -> GeneratorData { GeneratorData { definitions: definitions .definitions - .into_iter() - .map(|definition| { - let JavaDefinition { - name, - public, - definition, - .. - } = definition; - let definition_name = name.clone().name(); - let public = public_token(public); - match definition { - JavaDefinitionKind::Class(class) => { - let JavaClass { - extends, - implements, - constructors, - methods, - native_methods, - .. - } = class; - let mut transitive_extends = vec![]; - let mut current = name.clone(); - loop { - let super_class = extends_map.get(¤t); - if super_class.is_none() { - break; - } - let super_class = super_class.unwrap(); - transitive_extends.push(super_class.clone().with_double_colons()); - current = super_class.clone(); - } - let string_signature = name.clone().with_slashes(); - let signature = Literal::string(&string_signature); - let full_signature = Literal::string(&format!("L{};", string_signature)); - let super_class = extends - .map(|name| name.with_double_colons()) - .unwrap_or(quote!{::java::lang::Object}); - let implements = implements - .iter() - .flat_map(|name| interface_extends.get(&name).unwrap().iter()) - .chain(implements.iter()) - .cloned() - .collect::>(); - let mut implements = implements - .into_iter() - .map(|name| name.with_double_colons()) - .collect::>(); - 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 - .iter() - .filter(|method| !method.is_static) - .cloned() - .map(to_generator_method) - .collect(); - let constructors = constructors - .into_iter() - .map(to_generator_constructor) - .collect(); - let static_native_methods = native_methods - .iter() - .filter(|method| method.is_static) - .cloned() - .map(|method| to_generator_native_method(method, &name)) - .collect(); - let native_methods = native_methods - .iter() - .filter(|method| !method.is_static) - .cloned() - .map(|method| to_generator_native_method(method, &name)) - .collect(); - GeneratorDefinition::Class(ClassGeneratorDefinition { - class: definition_name, - public, - super_class, - transitive_extends, - implements, - signature, - full_signature, - constructors, - methods, - static_methods, - native_methods, - static_native_methods, - }) - } - JavaDefinitionKind::Interface(interface) => { - let JavaInterface { extends, .. } = interface; - GeneratorDefinition::Interface(InterfaceGeneratorDefinition { - interface: definition_name, - public, - extends: extends - .into_iter() - .map(|name| name.with_double_colons()) - .collect(), - }) - } - } - }) - .collect(), - } -} - -#[cfg(test)] -mod to_generator_data_tests { - use super::*; - - #[test] - fn empty() { - assert_eq!( - to_generator_data(JavaDefinitions { - definitions: vec![], - metadata: Metadata { - definitions: vec![], - }, - }), - GeneratorData { - definitions: vec![], - } - ); - } - - #[test] - fn metadata_only() { - assert_eq!( - to_generator_data(JavaDefinitions { - definitions: vec![], - metadata: Metadata { - definitions: vec![ - JavaDefinitionMetadata { - name: JavaName(quote!{c d test1}), - definition: JavaDefinitionMetadataKind::Interface( - JavaInterfaceMetadata { extends: vec![] }, - ), - }, - JavaDefinitionMetadata { - name: JavaName(quote!{a b test2}), - definition: JavaDefinitionMetadataKind::Class(JavaClassMetadata { - extends: None, - implements: vec![JavaName(quote!{c d test1})], - }), - }, - ], - }, - }), - GeneratorData { - definitions: vec![], - } - ); - } - - #[test] - fn one_class() { - assert_eq!( - to_generator_data(JavaDefinitions { - definitions: vec![JavaDefinition { - name: JavaName(quote!{a b test1}), - public: false, - definition: JavaDefinitionKind::Class(JavaClass { - extends: Some(JavaName(quote!{c d test2})), - implements: vec![], - methods: vec![], - native_methods: vec![], - constructors: vec![], - }), - }], - metadata: Metadata { - definitions: vec![], - }, - }), - GeneratorData { - definitions: vec![GeneratorDefinition::Class(ClassGeneratorDefinition { - class: Ident::new("test1", Span::call_site()), - public: TokenStream::new(), - super_class: quote!{::c::d::test2}, - transitive_extends: vec![quote!{::c::d::test2}], - implements: vec![], - signature: Literal::string("a/b/test1"), - full_signature: Literal::string("La/b/test1;"), - methods: vec![], - static_methods: vec![], - native_methods: vec![], - static_native_methods: vec![], - constructors: vec![], - })], - } - ); - } - - #[test] - fn one_class_no_extends() { - assert_eq!( - to_generator_data(JavaDefinitions { - definitions: vec![JavaDefinition { - name: JavaName(quote!{a b test1}), - public: false, - definition: JavaDefinitionKind::Class(JavaClass { - extends: None, - implements: vec![], - methods: vec![], - native_methods: vec![], - constructors: vec![], - }), - }], - metadata: Metadata { - definitions: vec![], - }, - }), - GeneratorData { - definitions: vec![GeneratorDefinition::Class(ClassGeneratorDefinition { - class: Ident::new("test1", Span::call_site()), - public: TokenStream::new(), - super_class: quote!{::java::lang::Object}, - transitive_extends: vec![quote!{::java::lang::Object}], - implements: vec![], - signature: Literal::string("a/b/test1"), - full_signature: Literal::string("La/b/test1;"), - methods: vec![], - static_methods: vec![], - native_methods: vec![], - static_native_methods: vec![], - constructors: vec![], - })], - } - ); - } - - #[test] - fn one_class_extends_recursive() { - assert_eq!( - to_generator_data(JavaDefinitions { - definitions: vec![ - JavaDefinition { - name: JavaName(quote!{c d test2}), - public: false, - definition: JavaDefinitionKind::Class(JavaClass { - extends: Some(JavaName(quote!{e f test3})), - implements: vec![], - methods: vec![], - native_methods: vec![], - constructors: vec![], - }), - }, - JavaDefinition { - name: JavaName(quote!{a b test1}), - public: false, - definition: JavaDefinitionKind::Class(JavaClass { - extends: Some(JavaName(quote!{c d test2})), - implements: vec![], - methods: vec![], - native_methods: vec![], - constructors: vec![], - }), - }, - ], - metadata: Metadata { - definitions: vec![ - JavaDefinitionMetadata { - name: JavaName(quote!{e f test4}), - definition: JavaDefinitionMetadataKind::Class(JavaClassMetadata { - extends: None, - implements: vec![], - }), - }, - JavaDefinitionMetadata { - name: JavaName(quote!{e f test3}), - definition: JavaDefinitionMetadataKind::Class(JavaClassMetadata { - extends: Some(JavaName(quote!{e f test4})), - implements: vec![], - }), - }, - ], - }, - }), - GeneratorData { - definitions: vec![ - GeneratorDefinition::Class(ClassGeneratorDefinition { - class: Ident::new("test2", Span::call_site()), - public: TokenStream::new(), - super_class: quote!{::e::f::test3}, - transitive_extends: vec![ - quote!{::e::f::test3}, - quote!{::e::f::test4}, - quote!{::java::lang::Object}, - ], - implements: vec![], - signature: Literal::string("c/d/test2"), - full_signature: Literal::string("Lc/d/test2;"), - methods: vec![], - static_methods: vec![], - native_methods: vec![], - static_native_methods: vec![], - constructors: vec![], - }), - GeneratorDefinition::Class(ClassGeneratorDefinition { - class: Ident::new("test1", Span::call_site()), - public: TokenStream::new(), - super_class: quote!{::c::d::test2}, - transitive_extends: vec![ - quote!{::c::d::test2}, - quote!{::e::f::test3}, - quote!{::e::f::test4}, - quote!{::java::lang::Object}, - ], - implements: vec![], - signature: Literal::string("a/b/test1"), - full_signature: Literal::string("La/b/test1;"), - methods: vec![], - static_methods: vec![], - native_methods: vec![], - static_native_methods: vec![], - constructors: vec![], - }), - ], - } - ); - } - - #[test] - fn one_class_implements() { - assert_eq!( - to_generator_data(JavaDefinitions { - definitions: vec![ - JavaDefinition { - name: JavaName(quote!{e f test4}), - public: false, - definition: JavaDefinitionKind::Interface(JavaInterface { - extends: vec![], - }), - }, - JavaDefinition { - name: JavaName(quote!{a b test1}), - public: false, - definition: JavaDefinitionKind::Class(JavaClass { - extends: None, - implements: vec![ - JavaName(quote!{e f test3}), - JavaName(quote!{e f test4}), - ], - methods: vec![], - native_methods: vec![], - constructors: vec![], - }), - }, - ], - metadata: Metadata { - definitions: vec![JavaDefinitionMetadata { - name: JavaName(quote!{e f test3}), - definition: JavaDefinitionMetadataKind::Interface(JavaInterfaceMetadata { - extends: vec![], - }), - }], - }, - }), - GeneratorData { - definitions: vec![ - GeneratorDefinition::Interface(InterfaceGeneratorDefinition { - interface: Ident::new("test4", Span::call_site()), - public: TokenStream::new(), - extends: vec![], - }), - GeneratorDefinition::Class(ClassGeneratorDefinition { - class: Ident::new("test1", Span::call_site()), - public: TokenStream::new(), - super_class: quote!{::java::lang::Object}, - transitive_extends: vec![quote!{::java::lang::Object}], - implements: vec![quote!{::e::f::test3}, quote!{::e::f::test4}], - signature: Literal::string("a/b/test1"), - full_signature: Literal::string("La/b/test1;"), - methods: vec![], - static_methods: vec![], - native_methods: vec![], - static_native_methods: vec![], - constructors: vec![], - }), - ], - } - ); - } - - #[test] - fn one_class_implements_recursive() { - assert_eq!( - to_generator_data(JavaDefinitions { - definitions: vec![ - JavaDefinition { - name: JavaName(quote!{e f test3}), - public: false, - definition: JavaDefinitionKind::Interface(JavaInterface { - extends: vec![JavaName(quote!{e f test4})], - }), - }, - JavaDefinition { - name: JavaName(quote!{a b test1}), - public: false, - definition: JavaDefinitionKind::Class(JavaClass { - extends: None, - implements: vec![JavaName(quote!{e f test3})], - methods: vec![], - native_methods: vec![], - constructors: vec![], - }), - }, - ], - metadata: Metadata { - definitions: vec![ - JavaDefinitionMetadata { - name: JavaName(quote!{g h test5}), - definition: JavaDefinitionMetadataKind::Interface( - JavaInterfaceMetadata { extends: vec![] }, - ), - }, - JavaDefinitionMetadata { - name: JavaName(quote!{e f test4}), - definition: JavaDefinitionMetadataKind::Interface( - JavaInterfaceMetadata { - extends: vec![JavaName(quote!{g h test5})], - }, - ), - }, - ], - }, - }), - GeneratorData { - definitions: vec![ - GeneratorDefinition::Interface(InterfaceGeneratorDefinition { - interface: Ident::new("test3", Span::call_site()), - public: TokenStream::new(), - extends: vec![quote!{::e::f::test4}], - }), - GeneratorDefinition::Class(ClassGeneratorDefinition { - class: Ident::new("test1", Span::call_site()), - public: TokenStream::new(), - super_class: quote!{::java::lang::Object}, - transitive_extends: vec![quote!{::java::lang::Object}], - implements: vec![ - quote!{::e::f::test3}, - quote!{::e::f::test4}, - quote!{::g::h::test5}, - ], - signature: Literal::string("a/b/test1"), - full_signature: Literal::string("La/b/test1;"), - methods: vec![], - static_methods: vec![], - native_methods: vec![], - static_native_methods: vec![], - constructors: vec![], - }), - ], - } - ); - } - - #[test] - fn one_class_implements_recursive_duplicated() { - assert_eq!( - to_generator_data(JavaDefinitions { - definitions: vec![ - JavaDefinition { - name: JavaName(quote!{g h test4}), - public: false, - definition: JavaDefinitionKind::Interface(JavaInterface { - extends: vec![], - }), - }, - JavaDefinition { - name: JavaName(quote!{e f test3}), - public: false, - definition: JavaDefinitionKind::Interface(JavaInterface { - extends: vec![JavaName(quote!{g h test4})], - }), - }, - JavaDefinition { - name: JavaName(quote!{a b test1}), - public: false, - definition: JavaDefinitionKind::Class(JavaClass { - extends: None, - implements: vec![ - JavaName(quote!{e f test3}), - JavaName(quote!{g h test4}), - ], - methods: vec![], - native_methods: vec![], - constructors: vec![], - }), - }, - ], - metadata: Metadata { - definitions: vec![], - }, - }), - GeneratorData { - definitions: vec![ - GeneratorDefinition::Interface(InterfaceGeneratorDefinition { - interface: Ident::new("test4", Span::call_site()), - public: TokenStream::new(), - extends: vec![], - }), - GeneratorDefinition::Interface(InterfaceGeneratorDefinition { - interface: Ident::new("test3", Span::call_site()), - public: TokenStream::new(), - extends: vec![quote!{::g::h::test4}], - }), - GeneratorDefinition::Class(ClassGeneratorDefinition { - class: Ident::new("test1", Span::call_site()), - public: TokenStream::new(), - super_class: quote!{::java::lang::Object}, - transitive_extends: vec![quote!{::java::lang::Object}], - implements: vec![quote!{::e::f::test3}, quote!{::g::h::test4}], - signature: Literal::string("a/b/test1"), - full_signature: Literal::string("La/b/test1;"), - methods: vec![], - static_methods: vec![], - native_methods: vec![], - static_native_methods: vec![], - constructors: vec![], - }), - ], - } - ); - } - - #[test] - fn one_class_public() { - assert_eq!( - to_generator_data(JavaDefinitions { - definitions: vec![JavaDefinition { - name: JavaName(quote!{a b test1}), - public: true, - definition: JavaDefinitionKind::Class(JavaClass { - extends: None, - implements: vec![], - methods: vec![], - native_methods: vec![], - constructors: vec![], - }), - }], - metadata: Metadata { - definitions: vec![], - }, - }), - GeneratorData { - definitions: vec![GeneratorDefinition::Class(ClassGeneratorDefinition { - class: Ident::new("test1", Span::call_site()), - public: quote!{pub}, - super_class: quote!{::java::lang::Object}, - transitive_extends: vec![quote!{::java::lang::Object}], - implements: vec![], - signature: Literal::string("a/b/test1"), - full_signature: Literal::string("La/b/test1;"), - methods: vec![], - static_methods: vec![], - native_methods: vec![], - static_native_methods: vec![], - constructors: vec![], - })], - } - ); - } - - #[test] - fn one_interface() { - assert_eq!( - to_generator_data(JavaDefinitions { - definitions: vec![JavaDefinition { - name: JavaName(quote!{a b test1}), - public: false, - definition: JavaDefinitionKind::Interface(JavaInterface { extends: vec![] }), - }], - metadata: Metadata { - definitions: vec![], - }, - }), - GeneratorData { - definitions: vec![GeneratorDefinition::Interface( - InterfaceGeneratorDefinition { - interface: Ident::new("test1", Span::call_site()), - public: TokenStream::new(), - extends: vec![], - }, - )], - } - ); - } - - #[test] - fn one_interface_extends() { - assert_eq!( - to_generator_data(JavaDefinitions { - definitions: vec![ - JavaDefinition { - name: JavaName(quote!{e f test3}), - public: false, - definition: JavaDefinitionKind::Interface(JavaInterface { - extends: vec![], - }), - }, - JavaDefinition { - name: JavaName(quote!{a b test1}), - public: false, - definition: JavaDefinitionKind::Interface(JavaInterface { - extends: vec![JavaName(quote!{c d test2}), JavaName(quote!{e f test3})], - }), - }, - ], - metadata: Metadata { - definitions: vec![ - JavaDefinitionMetadata { - name: JavaName(quote!{c d test4}), - definition: JavaDefinitionMetadataKind::Interface( - JavaInterfaceMetadata { extends: vec![] }, - ), - }, - JavaDefinitionMetadata { - name: JavaName(quote!{c d test2}), - definition: JavaDefinitionMetadataKind::Interface( - JavaInterfaceMetadata { - extends: vec![JavaName(quote!{c d test4})], - }, - ), - }, - ], - }, - }), - GeneratorData { - definitions: vec![ - GeneratorDefinition::Interface(InterfaceGeneratorDefinition { - interface: Ident::new("test3", Span::call_site()), - public: TokenStream::new(), - extends: vec![], - }), - GeneratorDefinition::Interface(InterfaceGeneratorDefinition { - interface: Ident::new("test1", Span::call_site()), - public: TokenStream::new(), - extends: vec![quote!{::c::d::test2}, quote!{::e::f::test3}], - }), - ], - } - ); - } - - #[test] - fn one_interface_public() { - assert_eq!( - to_generator_data(JavaDefinitions { - definitions: vec![JavaDefinition { - name: JavaName(quote!{a b test1}), - public: true, - definition: JavaDefinitionKind::Interface(JavaInterface { extends: vec![] }), - }], - metadata: Metadata { - definitions: vec![], - }, - }), - GeneratorData { - definitions: vec![GeneratorDefinition::Interface( - InterfaceGeneratorDefinition { - interface: Ident::new("test1", Span::call_site()), - public: quote!{pub}, - extends: vec![], - }, - )], - } - ); - } - - #[test] - fn multiple() { - assert_eq!( - to_generator_data(JavaDefinitions { - definitions: vec![ - JavaDefinition { - name: JavaName(quote!{e f test_if1}), - public: false, - definition: JavaDefinitionKind::Interface(JavaInterface { - extends: vec![], - }), - }, - JavaDefinition { - name: JavaName(quote!{e f test_if2}), - public: false, - definition: JavaDefinitionKind::Interface(JavaInterface { - extends: vec![], - }), - }, - JavaDefinition { - name: JavaName(quote!{a b test1}), - public: false, - definition: JavaDefinitionKind::Class(JavaClass { - extends: None, - implements: vec![], - methods: vec![], - native_methods: vec![], - constructors: vec![], - }), - }, - JavaDefinition { - name: JavaName(quote!{test2}), - public: false, - definition: JavaDefinitionKind::Class(JavaClass { - extends: None, - implements: vec![], - methods: vec![], - native_methods: vec![], - constructors: vec![], - }), - }, - ], - metadata: Metadata { - definitions: vec![], - }, - }), - GeneratorData { - definitions: vec![ - GeneratorDefinition::Interface(InterfaceGeneratorDefinition { - interface: Ident::new("test_if1", Span::call_site()), - public: TokenStream::new(), - extends: vec![], - }), - GeneratorDefinition::Interface(InterfaceGeneratorDefinition { - interface: Ident::new("test_if2", Span::call_site()), - public: TokenStream::new(), - extends: vec![], - }), - GeneratorDefinition::Class(ClassGeneratorDefinition { - class: Ident::new("test1", Span::call_site()), - public: TokenStream::new(), - super_class: quote!{::java::lang::Object}, - transitive_extends: vec![quote!{::java::lang::Object}], - implements: vec![], - signature: Literal::string("a/b/test1"), - full_signature: Literal::string("La/b/test1;"), - methods: vec![], - static_methods: vec![], - native_methods: vec![], - static_native_methods: vec![], - constructors: vec![], - }), - GeneratorDefinition::Class(ClassGeneratorDefinition { - class: Ident::new("test2", Span::call_site()), - public: TokenStream::new(), - super_class: quote!{::java::lang::Object}, - transitive_extends: vec![quote!{::java::lang::Object}], - implements: vec![], - signature: Literal::string("test2"), - full_signature: Literal::string("Ltest2;"), - methods: vec![], - static_methods: vec![], - native_methods: vec![], - static_native_methods: vec![], - constructors: vec![], - }), - ], - } - ); + .clone() + .into_iter() + .map(|definition| { + let JavaDefinition { + name, + public, + definition, + .. + } = definition; + let definition_name = name.clone().name(); + let public = public_token(public); + match definition { + JavaDefinitionKind::Class(class) => { + let JavaClass { + extends, + implements, + constructors, + methods, + native_methods, + .. + } = class; + let mut transitive_extends = vec![]; + let mut current = name.clone(); + loop { + let super_class = extends_map.get(¤t); + if super_class.is_none() { + break; + } + let super_class = super_class.unwrap(); + transitive_extends.push(super_class.clone().with_double_colons()); + current = super_class.clone(); + } + let string_signature = name.clone().with_slashes(); + let signature = Literal::string(&string_signature); + let full_signature = Literal::string(&format!("L{};", string_signature)); + let super_class = extends + .map(|name| name.with_double_colons()) + .unwrap_or(quote!{::java::lang::Object}); + let mut implements = implements + .iter() + .flat_map(|name| interface_extends.get(&name).unwrap().iter()) + .chain(implements.iter()) + .cloned() + .collect::>() + .into_iter() + .collect::>(); + implements.sort_by(|left, right| left.to_string().cmp(&right.to_string())); + let mut implements = implements + .into_iter() + .map(|name| InterfaceImplementationGeneratorDefinition { + interface: name.clone().with_double_colons(), + methods: definitions + .definitions + .iter() + .filter(|definition| definition.name == name) + .next() + .map(|definition| match definition.definition { + JavaDefinitionKind::Interface(ref interface) => interface + .methods + .clone() + .into_iter() + .zip(iter::repeat(definition.name.clone())), + _ => unreachable!(), + }) + .or(definitions + .metadata + .definitions + .clone() + .into_iter() + .filter(|definition| definition.name == name) + .map(|definition| match definition.definition { + JavaDefinitionMetadataKind::Interface( + ref interface, + ) => interface + .methods + .clone() + .into_iter() + .zip(iter::repeat(definition.name.clone())), + _ => unreachable!(), + }) + .next()) + .unwrap() + .map(|(method, name)| { + to_generator_interface_method_implementation( + method, + &methods, + &name, + &super_class, + ) + }) + .collect(), + }) + .collect::>(); + let static_methods = methods + .iter() + .filter(|method| method.is_static) + .cloned() + .map(to_generator_method) + .collect(); + let methods = methods + .iter() + .filter(|method| !method.is_static) + .cloned() + .map(to_generator_method) + .collect(); + let constructors = constructors + .into_iter() + .map(to_generator_constructor) + .collect(); + let static_native_methods = native_methods + .iter() + .filter(|method| method.is_static) + .cloned() + .map(|method| to_generator_native_method(method, &name)) + .collect(); + let native_methods = native_methods + .iter() + .filter(|method| !method.is_static) + .cloned() + .map(|method| to_generator_native_method(method, &name)) + .collect(); + GeneratorDefinition::Class(ClassGeneratorDefinition { + class: definition_name, + public, + super_class, + transitive_extends, + implements, + signature, + full_signature, + constructors, + methods, + static_methods, + native_methods, + static_native_methods, + }) + } + JavaDefinitionKind::Interface(interface) => { + let JavaInterface { + methods, extends, .. + } = interface; + let methods = methods + .iter() + .cloned() + .map(to_generator_interface_method) + .collect(); + GeneratorDefinition::Interface(InterfaceGeneratorDefinition { + interface: definition_name, + public, + methods, + extends: extends + .into_iter() + .map(|name| name.with_double_colons()) + .collect(), + }) + } + } + }) + .collect(), } } +// #[cfg(test)] +// mod to_generator_data_tests { +// use super::*; + +// #[test] +// fn empty() { +// assert_eq!( +// to_generator_data(JavaDefinitions { +// definitions: vec![], +// metadata: Metadata { +// definitions: vec![], +// }, +// }), +// GeneratorData { +// definitions: vec![], +// } +// ); +// } + +// #[test] +// fn metadata_only() { +// assert_eq!( +// to_generator_data(JavaDefinitions { +// definitions: vec![], +// metadata: Metadata { +// definitions: vec![ +// JavaDefinitionMetadata { +// name: JavaName(quote!{c d test1}), +// definition: JavaDefinitionMetadataKind::Interface( +// JavaInterfaceMetadata { +// methods: vec![], +// extends: vec![], +// }, +// ), +// }, +// JavaDefinitionMetadata { +// name: JavaName(quote!{a b test2}), +// definition: JavaDefinitionMetadataKind::Class(JavaClassMetadata { +// extends: None, +// implements: vec![JavaName(quote!{c d test1})], +// }), +// }, +// ], +// }, +// }), +// GeneratorData { +// definitions: vec![], +// } +// ); +// } + +// #[test] +// fn one_class() { +// assert_eq!( +// to_generator_data(JavaDefinitions { +// definitions: vec![JavaDefinition { +// name: JavaName(quote!{a b test1}), +// public: false, +// definition: JavaDefinitionKind::Class(JavaClass { +// extends: Some(JavaName(quote!{c d test2})), +// implements: vec![], +// methods: vec![], +// native_methods: vec![], +// constructors: vec![], +// }), +// }], +// metadata: Metadata { +// definitions: vec![], +// }, +// }), +// GeneratorData { +// definitions: vec![GeneratorDefinition::Class(ClassGeneratorDefinition { +// class: Ident::new("test1", Span::call_site()), +// public: TokenStream::new(), +// super_class: quote!{::c::d::test2}, +// transitive_extends: vec![quote!{::c::d::test2}], +// implements: vec![], +// signature: Literal::string("a/b/test1"), +// full_signature: Literal::string("La/b/test1;"), +// methods: vec![], +// static_methods: vec![], +// native_methods: vec![], +// static_native_methods: vec![], +// constructors: vec![], +// })], +// } +// ); +// } + +// #[test] +// fn one_class_no_extends() { +// assert_eq!( +// to_generator_data(JavaDefinitions { +// definitions: vec![JavaDefinition { +// name: JavaName(quote!{a b test1}), +// public: false, +// definition: JavaDefinitionKind::Class(JavaClass { +// extends: None, +// implements: vec![], +// methods: vec![], +// native_methods: vec![], +// constructors: vec![], +// }), +// }], +// metadata: Metadata { +// definitions: vec![], +// }, +// }), +// GeneratorData { +// definitions: vec![GeneratorDefinition::Class(ClassGeneratorDefinition { +// class: Ident::new("test1", Span::call_site()), +// public: TokenStream::new(), +// super_class: quote!{::java::lang::Object}, +// transitive_extends: vec![quote!{::java::lang::Object}], +// implements: vec![], +// signature: Literal::string("a/b/test1"), +// full_signature: Literal::string("La/b/test1;"), +// methods: vec![], +// static_methods: vec![], +// native_methods: vec![], +// static_native_methods: vec![], +// constructors: vec![], +// })], +// } +// ); +// } + +// #[test] +// fn one_class_extends_recursive() { +// assert_eq!( +// to_generator_data(JavaDefinitions { +// definitions: vec![ +// JavaDefinition { +// name: JavaName(quote!{c d test2}), +// public: false, +// definition: JavaDefinitionKind::Class(JavaClass { +// extends: Some(JavaName(quote!{e f test3})), +// implements: vec![], +// methods: vec![], +// native_methods: vec![], +// constructors: vec![], +// }), +// }, +// JavaDefinition { +// name: JavaName(quote!{a b test1}), +// public: false, +// definition: JavaDefinitionKind::Class(JavaClass { +// extends: Some(JavaName(quote!{c d test2})), +// implements: vec![], +// methods: vec![], +// native_methods: vec![], +// constructors: vec![], +// }), +// }, +// ], +// metadata: Metadata { +// definitions: vec![ +// JavaDefinitionMetadata { +// name: JavaName(quote!{e f test4}), +// definition: JavaDefinitionMetadataKind::Class(JavaClassMetadata { +// extends: None, +// implements: vec![], +// }), +// }, +// JavaDefinitionMetadata { +// name: JavaName(quote!{e f test3}), +// definition: JavaDefinitionMetadataKind::Class(JavaClassMetadata { +// extends: Some(JavaName(quote!{e f test4})), +// implements: vec![], +// }), +// }, +// ], +// }, +// }), +// GeneratorData { +// definitions: vec![ +// GeneratorDefinition::Class(ClassGeneratorDefinition { +// class: Ident::new("test2", Span::call_site()), +// public: TokenStream::new(), +// super_class: quote!{::e::f::test3}, +// transitive_extends: vec![ +// quote!{::e::f::test3}, +// quote!{::e::f::test4}, +// quote!{::java::lang::Object}, +// ], +// implements: vec![], +// signature: Literal::string("c/d/test2"), +// full_signature: Literal::string("Lc/d/test2;"), +// methods: vec![], +// static_methods: vec![], +// native_methods: vec![], +// static_native_methods: vec![], +// constructors: vec![], +// }), +// GeneratorDefinition::Class(ClassGeneratorDefinition { +// class: Ident::new("test1", Span::call_site()), +// public: TokenStream::new(), +// super_class: quote!{::c::d::test2}, +// transitive_extends: vec![ +// quote!{::c::d::test2}, +// quote!{::e::f::test3}, +// quote!{::e::f::test4}, +// quote!{::java::lang::Object}, +// ], +// implements: vec![], +// signature: Literal::string("a/b/test1"), +// full_signature: Literal::string("La/b/test1;"), +// methods: vec![], +// static_methods: vec![], +// native_methods: vec![], +// static_native_methods: vec![], +// constructors: vec![], +// }), +// ], +// } +// ); +// } + +// #[test] +// fn one_class_implements() { +// assert_eq!( +// to_generator_data(JavaDefinitions { +// definitions: vec![ +// JavaDefinition { +// name: JavaName(quote!{e f test4}), +// public: false, +// definition: JavaDefinitionKind::Interface(JavaInterface { +// methods: vec![], +// extends: vec![], +// }), +// }, +// JavaDefinition { +// name: JavaName(quote!{a b test1}), +// public: false, +// definition: JavaDefinitionKind::Class(JavaClass { +// extends: None, +// implements: vec![ +// JavaName(quote!{e f test3}), +// JavaName(quote!{e f test4}), +// ], +// methods: vec![], +// native_methods: vec![], +// constructors: vec![], +// }), +// }, +// ], +// metadata: Metadata { +// definitions: vec![JavaDefinitionMetadata { +// name: JavaName(quote!{e f test3}), +// definition: JavaDefinitionMetadataKind::Interface(JavaInterfaceMetadata { +// extends: vec![], +// methods: vec![], +// }), +// }], +// }, +// }), +// GeneratorData { +// definitions: vec![ +// GeneratorDefinition::Interface(InterfaceGeneratorDefinition { +// interface: Ident::new("test4", Span::call_site()), +// public: TokenStream::new(), +// extends: vec![], +// methods: vec![], +// }), +// GeneratorDefinition::Class(ClassGeneratorDefinition { +// class: Ident::new("test1", Span::call_site()), +// public: TokenStream::new(), +// super_class: quote!{::java::lang::Object}, +// transitive_extends: vec![quote!{::java::lang::Object}], +// implements: vec![quote!{::e::f::test3}, quote!{::e::f::test4}], +// signature: Literal::string("a/b/test1"), +// full_signature: Literal::string("La/b/test1;"), +// methods: vec![], +// static_methods: vec![], +// native_methods: vec![], +// static_native_methods: vec![], +// constructors: vec![], +// }), +// ], +// } +// ); +// } + +// #[test] +// fn one_class_implements_recursive() { +// assert_eq!( +// to_generator_data(JavaDefinitions { +// definitions: vec![ +// JavaDefinition { +// name: JavaName(quote!{e f test3}), +// public: false, +// definition: JavaDefinitionKind::Interface(JavaInterface { +// methods: vec![], +// extends: vec![JavaName(quote!{e f test4})], +// }), +// }, +// JavaDefinition { +// name: JavaName(quote!{a b test1}), +// public: false, +// definition: JavaDefinitionKind::Class(JavaClass { +// extends: None, +// implements: vec![JavaName(quote!{e f test3})], +// methods: vec![], +// native_methods: vec![], +// constructors: vec![], +// }), +// }, +// ], +// metadata: Metadata { +// definitions: vec![ +// JavaDefinitionMetadata { +// name: JavaName(quote!{g h test5}), +// definition: JavaDefinitionMetadataKind::Interface( +// JavaInterfaceMetadata { +// methods: vec![], +// extends: vec![], +// }, +// ), +// }, +// JavaDefinitionMetadata { +// name: JavaName(quote!{e f test4}), +// definition: JavaDefinitionMetadataKind::Interface( +// JavaInterfaceMetadata { +// methods: vec![], +// extends: vec![JavaName(quote!{g h test5})], +// }, +// ), +// }, +// ], +// }, +// }), +// GeneratorData { +// definitions: vec![ +// GeneratorDefinition::Interface(InterfaceGeneratorDefinition { +// interface: Ident::new("test3", Span::call_site()), +// public: TokenStream::new(), +// extends: vec![quote!{::e::f::test4}], +// methods: vec![], +// }), +// GeneratorDefinition::Class(ClassGeneratorDefinition { +// class: Ident::new("test1", Span::call_site()), +// public: TokenStream::new(), +// super_class: quote!{::java::lang::Object}, +// transitive_extends: vec![quote!{::java::lang::Object}], +// implements: vec![ +// quote!{::e::f::test3}, +// quote!{::e::f::test4}, +// quote!{::g::h::test5}, +// ], +// signature: Literal::string("a/b/test1"), +// full_signature: Literal::string("La/b/test1;"), +// methods: vec![], +// static_methods: vec![], +// native_methods: vec![], +// static_native_methods: vec![], +// constructors: vec![], +// }), +// ], +// } +// ); +// } + +// #[test] +// fn one_class_implements_recursive_duplicated() { +// assert_eq!( +// to_generator_data(JavaDefinitions { +// definitions: vec![ +// JavaDefinition { +// name: JavaName(quote!{g h test4}), +// public: false, +// definition: JavaDefinitionKind::Interface(JavaInterface { +// methods: vec![], +// extends: vec![], +// }), +// }, +// JavaDefinition { +// name: JavaName(quote!{e f test3}), +// public: false, +// definition: JavaDefinitionKind::Interface(JavaInterface { +// methods: vec![], +// extends: vec![JavaName(quote!{g h test4})], +// }), +// }, +// JavaDefinition { +// name: JavaName(quote!{a b test1}), +// public: false, +// definition: JavaDefinitionKind::Class(JavaClass { +// extends: None, +// implements: vec![ +// JavaName(quote!{e f test3}), +// JavaName(quote!{g h test4}), +// ], +// methods: vec![], +// native_methods: vec![], +// constructors: vec![], +// }), +// }, +// ], +// metadata: Metadata { +// definitions: vec![], +// }, +// }), +// GeneratorData { +// definitions: vec![ +// GeneratorDefinition::Interface(InterfaceGeneratorDefinition { +// interface: Ident::new("test4", Span::call_site()), +// public: TokenStream::new(), +// extends: vec![], +// methods: vec![], +// }), +// GeneratorDefinition::Interface(InterfaceGeneratorDefinition { +// interface: Ident::new("test3", Span::call_site()), +// public: TokenStream::new(), +// extends: vec![quote!{::g::h::test4}], +// methods: vec![], +// }), +// GeneratorDefinition::Class(ClassGeneratorDefinition { +// class: Ident::new("test1", Span::call_site()), +// public: TokenStream::new(), +// super_class: quote!{::java::lang::Object}, +// transitive_extends: vec![quote!{::java::lang::Object}], +// implements: vec![quote!{::e::f::test3}, quote!{::g::h::test4}], +// signature: Literal::string("a/b/test1"), +// full_signature: Literal::string("La/b/test1;"), +// methods: vec![], +// static_methods: vec![], +// native_methods: vec![], +// static_native_methods: vec![], +// constructors: vec![], +// }), +// ], +// } +// ); +// } + +// #[test] +// fn one_class_public() { +// assert_eq!( +// to_generator_data(JavaDefinitions { +// definitions: vec![JavaDefinition { +// name: JavaName(quote!{a b test1}), +// public: true, +// definition: JavaDefinitionKind::Class(JavaClass { +// extends: None, +// implements: vec![], +// methods: vec![], +// native_methods: vec![], +// constructors: vec![], +// }), +// }], +// metadata: Metadata { +// definitions: vec![], +// }, +// }), +// GeneratorData { +// definitions: vec![GeneratorDefinition::Class(ClassGeneratorDefinition { +// class: Ident::new("test1", Span::call_site()), +// public: quote!{pub}, +// super_class: quote!{::java::lang::Object}, +// transitive_extends: vec![quote!{::java::lang::Object}], +// implements: vec![], +// signature: Literal::string("a/b/test1"), +// full_signature: Literal::string("La/b/test1;"), +// methods: vec![], +// static_methods: vec![], +// native_methods: vec![], +// static_native_methods: vec![], +// constructors: vec![], +// })], +// } +// ); +// } + +// #[test] +// fn one_interface() { +// assert_eq!( +// to_generator_data(JavaDefinitions { +// definitions: vec![JavaDefinition { +// name: JavaName(quote!{a b test1}), +// public: false, +// definition: JavaDefinitionKind::Interface(JavaInterface { +// methods: vec![], +// extends: vec![], +// }), +// }], +// metadata: Metadata { +// definitions: vec![], +// }, +// }), +// GeneratorData { +// definitions: vec![GeneratorDefinition::Interface( +// InterfaceGeneratorDefinition { +// interface: Ident::new("test1", Span::call_site()), +// public: TokenStream::new(), +// extends: vec![], +// methods: vec![], +// }, +// )], +// } +// ); +// } + +// #[test] +// fn one_interface_extends() { +// assert_eq!( +// to_generator_data(JavaDefinitions { +// definitions: vec![ +// JavaDefinition { +// name: JavaName(quote!{e f test3}), +// public: false, +// definition: JavaDefinitionKind::Interface(JavaInterface { +// methods: vec![], +// extends: vec![], +// }), +// }, +// JavaDefinition { +// name: JavaName(quote!{a b test1}), +// public: false, +// definition: JavaDefinitionKind::Interface(JavaInterface { +// methods: vec![], +// extends: vec![JavaName(quote!{c d test2}), JavaName(quote!{e f test3})], +// }), +// }, +// ], +// metadata: Metadata { +// definitions: vec![ +// JavaDefinitionMetadata { +// name: JavaName(quote!{c d test4}), +// definition: JavaDefinitionMetadataKind::Interface( +// JavaInterfaceMetadata { +// methods: vec![], +// extends: vec![], +// }, +// ), +// }, +// JavaDefinitionMetadata { +// name: JavaName(quote!{c d test2}), +// definition: JavaDefinitionMetadataKind::Interface( +// JavaInterfaceMetadata { +// methods: vec![], +// extends: vec![JavaName(quote!{c d test4})], +// }, +// ), +// }, +// ], +// }, +// }), +// GeneratorData { +// definitions: vec![ +// GeneratorDefinition::Interface(InterfaceGeneratorDefinition { +// interface: Ident::new("test3", Span::call_site()), +// public: TokenStream::new(), +// extends: vec![], +// methods: vec![], +// }), +// GeneratorDefinition::Interface(InterfaceGeneratorDefinition { +// interface: Ident::new("test1", Span::call_site()), +// public: TokenStream::new(), +// extends: vec![quote!{::c::d::test2}, quote!{::e::f::test3}], +// methods: vec![], +// }), +// ], +// } +// ); +// } + +// #[test] +// fn one_interface_public() { +// assert_eq!( +// to_generator_data(JavaDefinitions { +// definitions: vec![JavaDefinition { +// name: JavaName(quote!{a b test1}), +// public: true, +// definition: JavaDefinitionKind::Interface(JavaInterface { +// methods: vec![], +// extends: vec![], +// }), +// }], +// metadata: Metadata { +// definitions: vec![], +// }, +// }), +// GeneratorData { +// definitions: vec![GeneratorDefinition::Interface( +// InterfaceGeneratorDefinition { +// interface: Ident::new("test1", Span::call_site()), +// public: quote!{pub}, +// extends: vec![], +// methods: vec![], +// }, +// )], +// } +// ); +// } + +// #[test] +// fn multiple() { +// assert_eq!( +// to_generator_data(JavaDefinitions { +// definitions: vec![ +// JavaDefinition { +// name: JavaName(quote!{e f test_if1}), +// public: false, +// definition: JavaDefinitionKind::Interface(JavaInterface { +// methods: vec![], +// extends: vec![], +// }), +// }, +// JavaDefinition { +// name: JavaName(quote!{e f test_if2}), +// public: false, +// definition: JavaDefinitionKind::Interface(JavaInterface { +// methods: vec![], +// extends: vec![], +// }), +// }, +// JavaDefinition { +// name: JavaName(quote!{a b test1}), +// public: false, +// definition: JavaDefinitionKind::Class(JavaClass { +// extends: None, +// implements: vec![], +// methods: vec![], +// native_methods: vec![], +// constructors: vec![], +// }), +// }, +// JavaDefinition { +// name: JavaName(quote!{test2}), +// public: false, +// definition: JavaDefinitionKind::Class(JavaClass { +// extends: None, +// implements: vec![], +// methods: vec![], +// native_methods: vec![], +// constructors: vec![], +// }), +// }, +// ], +// metadata: Metadata { +// definitions: vec![], +// }, +// }), +// GeneratorData { +// definitions: vec![ +// GeneratorDefinition::Interface(InterfaceGeneratorDefinition { +// interface: Ident::new("test_if1", Span::call_site()), +// public: TokenStream::new(), +// extends: vec![], +// methods: vec![], +// }), +// GeneratorDefinition::Interface(InterfaceGeneratorDefinition { +// interface: Ident::new("test_if2", Span::call_site()), +// public: TokenStream::new(), +// extends: vec![], +// methods: vec![], +// }), +// GeneratorDefinition::Class(ClassGeneratorDefinition { +// class: Ident::new("test1", Span::call_site()), +// public: TokenStream::new(), +// super_class: quote!{::java::lang::Object}, +// transitive_extends: vec![quote!{::java::lang::Object}], +// implements: vec![], +// signature: Literal::string("a/b/test1"), +// full_signature: Literal::string("La/b/test1;"), +// methods: vec![], +// static_methods: vec![], +// native_methods: vec![], +// static_native_methods: vec![], +// constructors: vec![], +// }), +// GeneratorDefinition::Class(ClassGeneratorDefinition { +// class: Ident::new("test2", Span::call_site()), +// public: TokenStream::new(), +// super_class: quote!{::java::lang::Object}, +// transitive_extends: vec![quote!{::java::lang::Object}], +// implements: vec![], +// signature: Literal::string("test2"), +// full_signature: Literal::string("Ltest2;"), +// methods: vec![], +// static_methods: vec![], +// native_methods: vec![], +// static_native_methods: vec![], +// constructors: vec![], +// }), +// ], +// } +// ); +// } +// } + fn generate(data: GeneratorData) -> TokenStream { let mut tokens = TokenStream::new(); for definition in data.definitions { @@ -2190,6 +2442,22 @@ fn generate_definition(definition: GeneratorDefinition) -> TokenStream { } } +fn generate_interface_method(method: InterfaceMethodGeneratorDefinition) -> TokenStream { + let InterfaceMethodGeneratorDefinition { + name, + return_type, + argument_names, + argument_types, + } = method; + quote!{ + fn #name( + &self, + #(#argument_names: #argument_types,)* + token: &::rust_jni::NoException<'a>, + ) -> ::rust_jni::JavaResult<'a, #return_type>; + } +} + fn generate_class_method(method: ClassMethodGeneratorDefinition) -> TokenStream { let ClassMethodGeneratorDefinition { name, @@ -2454,6 +2722,50 @@ fn generate_constructor(method: ConstructorGeneratorDefinition) -> TokenStream { } } +fn generate_interface_method_implementation( + method: InterfaceMethodImplementationGeneratorDefinition, +) -> TokenStream { + let InterfaceMethodImplementationGeneratorDefinition { + name, + argument_names, + argument_types, + return_type, + class_cast, + } = method; + let argument_names_1 = argument_names.clone(); + quote!{ + fn #name( + &self, + #(#argument_names: #argument_types),*, + token: &::rust_jni::NoException<'a>, + ) -> ::rust_jni::JavaResult<'a, #return_type> { + #class_cast::#name( + self, #(#argument_names_1),*, token + ) + } + } +} + +fn generate_interface_implementation( + interface: InterfaceImplementationGeneratorDefinition, + class: &Ident, +) -> TokenStream { + let InterfaceImplementationGeneratorDefinition { + interface, methods, .. + } = interface; + let methods = methods + .into_iter() + .map(generate_interface_method_implementation) + .collect::>(); + quote! { + impl<'a> #interface<'a> for #class<'a> { + #( + #methods + )* + } + } +} + fn generate_class_definition(definition: ClassGeneratorDefinition) -> TokenStream { let ClassGeneratorDefinition { class, @@ -2503,6 +2815,10 @@ fn generate_class_definition(definition: ClassGeneratorDefinition) -> TokenStrea .into_iter() .map(generate_constructor) .collect::>(); + let implementations = implements + .into_iter() + .map(|interface| generate_interface_implementation(interface, &class)) + .collect::>(); quote! { #[derive(Debug)] #public struct #class<'env> { @@ -2623,8 +2939,7 @@ fn generate_class_definition(definition: ClassGeneratorDefinition) -> TokenStrea impl<'a> Eq for #class<'a> {} #( - impl<'a> #implements for #multiplied_class<'a> { - } + #implementations )* } } @@ -2634,15 +2949,23 @@ fn generate_interface_definition(definition: InterfaceGeneratorDefinition) -> To interface, public, extends, + methods, .. } = definition; let extends = if extends.is_empty() { TokenStream::new() } else { - quote!{: #(#extends)+*} + quote!{: #(#extends<'a>)+*} }; + let methods = methods + .into_iter() + .map(generate_interface_method) + .collect::>(); quote! { - #public trait #interface #extends { + #public trait #interface<'a> #extends { + #( + #methods + )* } } } @@ -2776,7 +3099,16 @@ mod generate_tests { public: quote!{test_public}, super_class: quote!{c::d::test2}, transitive_extends: vec![quote!{c::d::test2}], - implements: vec![quote!{e::f::test3}, quote!{e::f::test4}], + implements: vec![ + InterfaceImplementationGeneratorDefinition { + interface: quote!{e::f::test3}, + methods: vec![], + }, + InterfaceImplementationGeneratorDefinition { + interface: quote!{e::f::test4}, + methods: vec![], + }, + ], signature: Literal::string("test/sign1"), full_signature: Literal::string("test/signature1"), methods: vec![], @@ -2873,10 +3205,10 @@ mod generate_tests { impl<'a> Eq for test1<'a> {} - impl<'a> e::f::test3 for test1<'a> { + impl<'a> e::f::test3<'a> for test1<'a> { } - impl<'a> e::f::test4 for test1<'a> { + impl<'a> e::f::test4<'a> for test1<'a> { } }; assert_tokens_equals(generate(input), expected); @@ -2890,11 +3222,12 @@ mod generate_tests { interface: Ident::new("test1", Span::call_site()), public: quote!{test_public}, extends: vec![], + methods: vec![], }, )], }; let expected = quote!{ - test_public trait test1 { + test_public trait test1<'a> { } }; assert_tokens_equals(generate(input), expected); @@ -2908,11 +3241,12 @@ mod generate_tests { interface: Ident::new("test1", Span::call_site()), public: TokenStream::new(), extends: vec![quote!{c::d::test2}, quote!{e::f::test3}], + methods: vec![], }, )], }; let expected = quote!{ - trait test1 : c::d::test2 + e::f::test3 { + trait test1<'a> : c::d::test2<'a> + e::f::test3<'a> { } }; assert_tokens_equals(generate(input), expected); @@ -2926,11 +3260,13 @@ mod generate_tests { interface: Ident::new("test_if1", Span::call_site()), public: TokenStream::new(), extends: vec![], + methods: vec![], }), GeneratorDefinition::Interface(InterfaceGeneratorDefinition { interface: Ident::new("test_if2", Span::call_site()), public: TokenStream::new(), extends: vec![], + methods: vec![], }), GeneratorDefinition::Class(ClassGeneratorDefinition { class: Ident::new("test1", Span::call_site()), @@ -2963,10 +3299,10 @@ mod generate_tests { ], }; let expected = quote!{ - trait test_if1 { + trait test_if1<'a> { } - trait test_if2 { + trait test_if2<'a> { } #[derive(Debug)] @@ -3259,10 +3595,10 @@ mod java_generate_tests { class TestClass1 extends TestClass2 implements a.b.TestInterface1, a.b.TestInterface2 {} }; let expected = quote!{ - trait TestInterface1 { + trait TestInterface1<'a> { } - trait TestInterface2 { + trait TestInterface2<'a> { } #[derive(Debug)] @@ -3351,10 +3687,10 @@ mod java_generate_tests { impl<'a> Eq for TestClass1<'a> {} - impl<'a> ::a::b::TestInterface1 for TestClass1<'a> { + impl<'a> ::a::b::TestInterface1<'a> for TestClass1<'a> { } - impl<'a> ::a::b::TestInterface2 for TestClass1<'a> { + impl<'a> ::a::b::TestInterface2<'a> for TestClass1<'a> { } }; assert_tokens_equals(java_generate_impl(input), expected); @@ -3556,7 +3892,7 @@ mod java_generate_tests { interface TestInterface1 {} }; let expected = quote!{ - trait TestInterface1 { + trait TestInterface1<'a> { } }; assert_tokens_equals(java_generate_impl(input), expected); @@ -3568,7 +3904,7 @@ mod java_generate_tests { interface a.b.TestInterface1 {} }; let expected = quote!{ - trait TestInterface1 { + trait TestInterface1<'a> { } }; assert_tokens_equals(java_generate_impl(input), expected); @@ -3580,7 +3916,7 @@ mod java_generate_tests { public interface TestInterface1 {} }; let expected = quote!{ - pub trait TestInterface1 { + pub trait TestInterface1<'a> { } }; assert_tokens_equals(java_generate_impl(input), expected); @@ -3594,13 +3930,13 @@ mod java_generate_tests { interface TestInterface1 extends TestInterface2, TestInterface3 {} }; let expected = quote!{ - trait TestInterface2 { + trait TestInterface2<'a> { } - trait TestInterface3 { + trait TestInterface3<'a> { } - trait TestInterface1: ::TestInterface2 + ::TestInterface3 { + trait TestInterface1<'a>: ::TestInterface2<'a> + ::TestInterface3<'a> { } }; assert_tokens_equals(java_generate_impl(input), expected); @@ -3620,10 +3956,10 @@ mod java_generate_tests { } }; let expected = quote!{ - trait TestInterface1 { + trait TestInterface1<'a> { } - trait TestInterface2 { + trait TestInterface2<'a> { } #[derive(Debug)] @@ -3804,8 +4140,15 @@ mod java_generate_tests { #[test] fn integration() { let input = quote!{ - public interface a.b.TestInterface3 {} - public interface a.b.TestInterface4 extends c.d.TestInterface2, a.b.TestInterface3 {} + public interface a.b.TestInterface3 { + long primitiveInterfaceFunc3(int arg1, char arg2); + a.b.TestClass3 objectInterfaceFunc3(a.b.TestClass3 arg); + } + + public interface a.b.TestInterface4 extends c.d.TestInterface2, a.b.TestInterface3 { + long primitiveFunc3(int arg1, char arg2); + c.d.TestClass2 objectFunc3(a.b.TestClass3 arg); + } public class a.b.TestClass3 extends c.d.TestClass2 implements e.f.TestInterface1, a.b.TestInterface4 { public a.b.TestClass3(int arg1, a.b.TestClass3 arg2); @@ -3833,10 +4176,15 @@ mod java_generate_tests { println!("{:?} {:?} {:?}", arg, token, env); Ok(arg) }; + + long primitiveInterfaceFunc3(int arg1, char arg2); + a.b.TestClass3 objectInterfaceFunc3(a.b.TestClass3 arg); } metadata { - interface e.f.TestInterface1 {} + interface e.f.TestInterface1 { + long primitiveInterfaceFunc1(int arg1, char arg2); + } interface c.d.TestInterface2 extends e.f.TestInterface1 {} class c.d.TestClass1; @@ -3844,10 +4192,34 @@ mod java_generate_tests { } }; let expected = quote!{ - pub trait TestInterface3 { + pub trait TestInterface3<'a> { + fn primitiveInterfaceFunc3( + &self, + arg1: i32, + arg2: char, + token: &::rust_jni::NoException<'a>, + ) -> ::rust_jni::JavaResult<'a, i64>; + + fn objectInterfaceFunc3( + &self, + arg: &::a::b::TestClass3<'a>, + token: &::rust_jni::NoException<'a>, + ) -> ::rust_jni::JavaResult<'a, ::a::b::TestClass3<'a> >; } - pub trait TestInterface4: ::c::d::TestInterface2 + ::a::b::TestInterface3 { + pub trait TestInterface4<'a>: ::c::d::TestInterface2<'a> + ::a::b::TestInterface3<'a> { + fn primitiveFunc3( + &self, + arg1: i32, + arg2: char, + token: &::rust_jni::NoException<'a>, + ) -> ::rust_jni::JavaResult<'a, i64>; + + fn objectFunc3( + &self, + arg: &::a::b::TestClass3<'a>, + token: &::rust_jni::NoException<'a>, + ) -> ::rust_jni::JavaResult<'a, ::c::d::TestClass2<'a> >; } #[derive(Debug)] @@ -3991,6 +4363,45 @@ mod java_generate_tests { } } + fn primitiveInterfaceFunc3( + &self, + 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_method::<_, _, _, + fn(i32, char,) -> i64 + > + ( + self, + "primitiveInterfaceFunc3", + (arg1, arg2,), + token, + ) + } + } + + fn objectInterfaceFunc3( + &self, + arg: &::a::b::TestClass3<'a>, + token: &::rust_jni::NoException<'a>, + ) -> ::rust_jni::JavaResult<'a, ::a::b::TestClass3<'a> > { + // Safe because the method name and arguments are correct. + unsafe { + ::rust_jni::__generator::call_method::<_, _, _, + fn(&::a::b::TestClass3<'a>,) -> ::a::b::TestClass3<'a> + > + ( + self, + "objectInterfaceFunc3", + (arg,), + token, + ) + } + } + fn primitiveStaticFunc3( env: &'a ::rust_jni::JniEnv<'a>, arg1: i32, @@ -4248,16 +4659,57 @@ mod java_generate_tests { impl<'a> Eq for TestClass3<'a> {} - impl<'a> ::a::b::TestInterface3 for TestClass3<'a> { + impl<'a> ::a::b::TestInterface3<'a> for TestClass3<'a> { + fn primitiveInterfaceFunc3( + &self, + arg1: i32, + arg2: char, + token: &::rust_jni::NoException<'a>, + ) -> ::rust_jni::JavaResult<'a, i64> { + Self::primitiveInterfaceFunc3(self, arg1, arg2, token) + } + + fn objectInterfaceFunc3( + &self, + arg: &::a::b::TestClass3<'a>, + token: &::rust_jni::NoException<'a>, + ) -> ::rust_jni::JavaResult<'a, ::a::b::TestClass3<'a> > { + Self::objectInterfaceFunc3(self, arg, token) + } } - impl<'a> ::a::b::TestInterface4 for TestClass3<'a> { + impl<'a> ::a::b::TestInterface4<'a> for TestClass3<'a> { + fn primitiveFunc3( + &self, + arg1: i32, + arg2: char, + token: &::rust_jni::NoException<'a>, + ) -> ::rust_jni::JavaResult<'a, i64> { + Self::primitiveFunc3(self, arg1, arg2, token) + } + + fn objectFunc3( + &self, + arg: &::a::b::TestClass3<'a>, + token: &::rust_jni::NoException<'a>, + ) -> ::rust_jni::JavaResult<'a, ::c::d::TestClass2<'a> > { + Self::objectFunc3(self, arg, token) + } } - impl<'a> ::c::d::TestInterface2 for TestClass3<'a> { + impl<'a> ::c::d::TestInterface2<'a> for TestClass3<'a> { } - impl<'a> ::e::f::TestInterface1 for TestClass3<'a> { + impl<'a> ::e::f::TestInterface1<'a> for TestClass3<'a> { + fn primitiveInterfaceFunc1( + &self, + arg1: i32, + arg2: char, + token: &::rust_jni::NoException<'a>, + ) -> ::rust_jni::JavaResult<'a, i64> { + < ::c::d::TestClass2 as ::e::f::TestInterface1 > + ::primitiveInterfaceFunc1(self, arg1, arg2, token) + } } }; assert_tokens_equals(java_generate_impl(input), expected); diff --git a/generator/tests/test.rs b/generator/tests/test.rs index 9355f64..d3d7698 100644 --- a/generator/tests/test.rs +++ b/generator/tests/test.rs @@ -17,7 +17,9 @@ mod e { use rust_jni_generator::*; java_generate! { - public interface e.f.TestInterface1 {} + public interface e.f.TestInterface1 { + long primitiveInterfaceFunc1(int arg1, char arg2); + } } } } @@ -46,12 +48,13 @@ mod c { 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); + long primitiveInterfaceFunc1(int arg1, char arg2); } metadata { - interface e.f.TestInterface1 {} + interface e.f.TestInterface1 { + long primitiveInterfaceFunc1(int arg1, char arg2); + } } } } @@ -64,8 +67,15 @@ mod a { use rust_jni_generator::*; java_generate! { - public interface a.b.TestInterface3 {} - public interface a.b.TestInterface4 extends c.d.TestInterface2, a.b.TestInterface3 {} + public interface a.b.TestInterface3 { + long primitiveInterfaceFunc3(int arg1, char arg2); + a.b.TestClass3 objectInterfaceFunc3(a.b.TestClass3 arg); + } + + public interface a.b.TestInterface4 extends c.d.TestInterface2, a.b.TestInterface3 { + long primitiveFunc3(int arg1, char arg2); + c.d.TestClass2 objectFunc3(a.b.TestClass3 arg); + } public class a.b.TestClass3 extends c.d.TestClass2 implements e.f.TestInterface1, a.b.TestInterface4 { public a.b.TestClass3(int arg1, a.b.TestClass3 arg2); @@ -93,10 +103,15 @@ mod a { println!("{:?} {:?} {:?}", arg, token, env); Ok(arg) }; + + long primitiveInterfaceFunc3(int arg1, char arg2); + a.b.TestClass3 objectInterfaceFunc3(a.b.TestClass3 arg); } metadata { - interface e.f.TestInterface1 {} + interface e.f.TestInterface1 { + long primitiveInterfaceFunc1(int arg1, char arg2); + } interface c.d.TestInterface2 extends e.f.TestInterface1 {} class c.d.TestClass1;