1use argument::{DuchessDeclaration, MethodSelector};
2use parse::Parser;
3use proc_macro::TokenStream;
4use rust_format::Formatter;
5use std::path::PathBuf;
6
7mod argument;
8mod check;
9mod class_info;
10mod codegen;
11mod derive;
12mod java_function;
13mod parse;
14mod reflect;
15mod signature;
16mod substitution;
17mod upcasts;
18
19#[proc_macro]
32pub fn java_package(input: TokenStream) -> TokenStream {
33 let input: proc_macro2::TokenStream = input.into();
34 let decl = match Parser::from(input).parse::<DuchessDeclaration>() {
35 Ok(decl) => decl,
36 Err(err) => return err.to_compile_error().into(),
37 };
38
39 match decl.to_tokens() {
40 Ok(t) => return t.into(),
41 Err(e) => return e.into_compile_error().into(),
42 }
43}
44
45#[proc_macro_attribute]
46pub fn java_function(args: TokenStream, input: TokenStream) -> TokenStream {
47 let args: proc_macro2::TokenStream = args.into();
48 let args = match Parser::from(args).parse::<MethodSelector>() {
49 Ok(decl) => decl,
50 Err(err) => return err.to_compile_error().into(),
51 };
52
53 let item_fn = match syn::parse::<syn::ItemFn>(input) {
54 Ok(item_fn) => item_fn,
55 Err(err) => return err.into_compile_error().into(),
56 };
57
58 match java_function::java_function(args, item_fn) {
59 Ok(t) => t.into(),
60 Err(err) => err.into_compile_error().into(),
61 }
62}
63
64synstructure::decl_derive!([ToRust, attributes(java)] => derive::derive_to_rust);
65
66synstructure::decl_derive!([ToJava, attributes(java)] => derive::derive_to_java);
67
68lazy_static::lazy_static! {
69 static ref DEBUG_DIR: PathBuf = {
70 let tmp_dir = tempfile::TempDir::new().expect("failed to create temp directory");
71 tmp_dir.into_path()
72 };
73}
74
75fn debug_tokens(name: impl std::fmt::Display, token_stream: &proc_macro2::TokenStream) {
76 let Ok(debug_filter) = std::env::var("DUCHESS_DEBUG") else {
77 return;
78 };
79 let name = name.to_string();
80 let debug_enabled = match debug_filter {
81 f if f.eq_ignore_ascii_case("true") || f.eq_ignore_ascii_case("1") => true,
82 filter => name.starts_with(&filter)
83 };
84 if debug_enabled {
85 let path = DEBUG_DIR.join(name.replace('.', "_")).with_extension("rs");
86 match rust_format::RustFmt::default().format_tokens(token_stream.clone()) {
87 Ok(formatted_tokens) => {
88 std::fs::write(&path, formatted_tokens).expect("failed to write to debug file");
89 }
90 Err(_) => {
91 std::fs::write(&path, format!("{token_stream:?}")).expect("failed to write to debug file");
92 }
93 }
94 if running_in_jetbrains() {
97 eprintln!("file:///{}", path.display())
98 } else {
99 eprintln!("{}", path.display())
100 }
101 }
102}
103
104fn running_in_jetbrains() -> bool {
105 std::env::var("TERMINAL_EMULATOR").map(|var|var.contains("JetBrains")).unwrap_or_default()
106}