From 5e560d2f3d8247f74138d0841aa6c8d1e7eff9b0 Mon Sep 17 00:00:00 2001 From: alemi Date: Sat, 21 Sep 2024 17:36:51 +0200 Subject: [PATCH] feat: return compiler errors, throw java err no more random panicing --- README.md | 4 +++- src/lib.rs | 35 +++++++++++++++++++++-------------- 2 files changed, 24 insertions(+), 15 deletions(-) diff --git a/README.md b/README.md index 0fd19db..3a1e40f 100644 --- a/README.md +++ b/README.md @@ -15,10 +15,12 @@ fn your_function_name(arg: i32) -> Result<(), String> { by specifying package and class, this crate will write an appropriate wrapper with the right function name. If inner function returns a `Result<>`, wrapper will also handle it. (currently just panics, soon will throw exceptions!) +note that input/output arguments must be natively FFI safe: there will be no hidden translations! you will have to un-marshal strings yourself + ## examples the following function: ```rust -#[java_easy_jni::jni(package = "mp.code", class = "Client")] +#[jni_macro::jni(package = "mp.code", class = "Client")] fn connect(env: JNIEnv, cacca: JString) -> Result<(), ConnectionError> { let config = codemp::api::Config::new("asd".into(), "dsa".into()); tokio().block_on(codemp::Client::connect(config))?; diff --git a/src/lib.rs b/src/lib.rs index 5b16428..98c10c3 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -21,10 +21,8 @@ use syn::{FnArg, Item, ReturnType, Type}; fn generate_jni_wrapper(attrs: TokenStream, input: TokenStream) -> Result { let mut out = TokenStream::new(); - let item = syn::parse2(input.clone())?; - - let Item::Fn(fn_item) = item else { - panic!("can only be applied to functions"); // TODO throw err instead of panic + let Item::Fn(fn_item) = syn::parse2(input.clone())? else { + return Err(syn::Error::new(Span::call_site(), "#[jni] is only supported on functions")); }; let mut what_next = WhatNext::Nothing; @@ -39,7 +37,7 @@ fn generate_jni_wrapper(attrs: TokenStream, input: TokenStream) -> Result what_next = WhatNext::Package, "class" => what_next = WhatNext::Class, - _ => panic!("unexpected keyword in attrs: {}", attr), + _ => return Err(syn::Error::new(Span::call_site(), "unexpected attribute on macro: {attr}")), } } }, @@ -60,15 +58,15 @@ fn generate_jni_wrapper(attrs: TokenStream, input: TokenStream) -> Result (false, fn_item.sig.output), syn::ReturnType::Type(_tok, ty) => match *ty { syn::Type::Path(ref path) => { let Some(last) = path.path.segments.last() else { - panic!("empty type path"); + return Err(syn::Error::new(Span::call_site(), "empty Result type is not valid")); }; // TODO this is terrible, macro returns a function and we call it?? there must be a @@ -80,8 +78,8 @@ fn generate_jni_wrapper(attrs: TokenStream, input: TokenStream) -> Result panic!("result without generics is not valid"), - syn::PathArguments::Parenthesized(_) => panic!("parenthesized result is not valid"), + syn::PathArguments::None => return Err(syn::Error::new(Span::call_site(), "Result without generics is not valid")), + syn::PathArguments::Parenthesized(_) => return Err(syn::Error::new(Span::call_site(), "Parenthesized Result is not valid")), syn::PathArguments::AngleBracketed(ref generics) => for generic in generics.args.iter() { match generic { syn::GenericArgument::Lifetime(_) => continue, @@ -89,7 +87,7 @@ fn generate_jni_wrapper(attrs: TokenStream, input: TokenStream) -> Result](Span::call_site()), Box::new(ty.clone()))); break; }, - _ => panic!("unexpected type in Result generic"), + _ => return Err(syn::Error::new(Span::call_site(), "unexpected type in Result")), } } } @@ -97,7 +95,7 @@ fn generate_jni_wrapper(attrs: TokenStream, input: TokenStream) -> Result panic!("unsupported return type"), + _ => return Err(syn::Error::new(Span::call_site(), "unsupported return type")), }, }; @@ -107,7 +105,7 @@ fn generate_jni_wrapper(attrs: TokenStream, input: TokenStream) -> Result Result(#incoming) #ret_type { match #fn_name_inner(#forwarding) { Ok(x) => x, - Err(e) => panic!("error in JNI!"), // TODO throw java exc + Err(e) => { + #env_ident + .throw_new("java/lang/RuntimeException", format!("{e:?}")) + .expect("failed throwing Java exception from native call"); + return 0; + } } } }