@@ -2,8 +2,8 @@ use proc_macro2::{Ident, Span};
22use quote:: { ToTokens , quote, quote_spanned} ;
33use syn:: spanned:: Spanned ;
44use syn:: {
5- Abi , FnArg , GenericArgument , ItemFn , Pat , PatIdent , Path , PathArguments , ReturnType , Type ,
6- TypePath ,
5+ Abi , FnArg , GenericArgument , ItemFn , Pat , PatIdent , PatType , Path , PathArguments , ReturnType ,
6+ Type , TypePath ,
77} ;
88
99// jni_sys types
@@ -176,6 +176,34 @@ parameter_types!(
176176 ]
177177) ;
178178
179+ enum ParameterType {
180+ Strict ( SafeJniWrapperType ) ,
181+ Loose ( Box < Type > ) ,
182+ }
183+
184+ impl ParameterType {
185+ fn to_raw ( & self ) -> proc_macro2:: TokenStream {
186+ match self {
187+ ParameterType :: Strict ( inner) => inner. to_raw ( ) ,
188+ ParameterType :: Loose ( inner) => inner. to_token_stream ( ) ,
189+ }
190+ }
191+
192+ fn safe_conversion_fn ( & self , param_name : Ident ) -> proc_macro2:: TokenStream {
193+ match self {
194+ ParameterType :: Strict ( inner) => inner. safe_conversion_fn ( param_name) ,
195+ ParameterType :: Loose ( _inner) => param_name. to_token_stream ( ) ,
196+ }
197+ }
198+
199+ fn raw_conversion_fn ( & self , param_name : Ident ) -> proc_macro2:: TokenStream {
200+ match self {
201+ ParameterType :: Strict ( inner) => inner. raw_conversion_fn ( param_name) ,
202+ ParameterType :: Loose ( _inner) => param_name. to_token_stream ( ) ,
203+ }
204+ }
205+ }
206+
179207pub enum Error {
180208 MissingAbi ,
181209 BadAbi ,
@@ -189,7 +217,7 @@ impl Error {
189217 pub fn into_syn ( self , span : Span ) -> syn:: Error {
190218 match self {
191219 Error :: MissingAbi => syn:: Error :: new ( span, "Must specify an ABI" ) ,
192- Error :: BadAbi => syn:: Error :: new ( span, "Must specify \" system \" ABI" ) ,
220+ Error :: BadAbi => syn:: Error :: new ( span, "Must specify valid ABI" ) ,
193221 Error :: MissingEnv => syn:: Error :: new ( span, "First parameter must be a JniEnv" ) ,
194222 Error :: HasReceiver => syn:: Error :: new ( span, "JNI functions must be freestanding" ) ,
195223 Error :: BadParameterType ( ty) => syn:: Error :: new (
@@ -210,16 +238,16 @@ pub struct JniFn {
210238 pub errors : Vec < ( Error , Span ) > ,
211239}
212240
213- pub fn generate ( input : & ItemFn ) -> JniFn {
241+ pub fn generate ( input : & ItemFn , no_env : bool , no_strict_types : bool ) -> JniFn {
214242 let mut errors = Vec :: new ( ) ;
215243 validate_abi ( & mut errors, input) ;
216- let params = validate_params ( & mut errors, input) ;
217- let return_ty = validate_return ( & mut errors, input) ;
244+ let params = validate_params ( & mut errors, input, no_env , no_strict_types ) ;
245+ let return_ty = validate_return ( & mut errors, input, no_strict_types ) ;
218246
219247 let fn_name = & input. sig . ident ;
220248 let raw_mod_name = Ident :: new ( & format ! ( "raw_{}" , fn_name) , Span :: call_site ( ) ) ;
221249
222- let extern_fn_def = generate_extern_fn ( input, & params, return_ty) ;
250+ let extern_fn_def = generate_extern_fn ( input, & params, return_ty, no_env ) ;
223251 let extern_fn = quote ! {
224252 mod #raw_mod_name {
225253 use super :: * ;
@@ -249,28 +277,59 @@ fn validate_abi(errors: &mut Vec<(Error, Span)>, fun: &ItemFn) {
249277 return ;
250278 } ;
251279
252- if name. value ( ) != "system" {
280+ if name. value ( ) != "system" && name . value ( ) != "C" {
253281 errors. push ( ( Error :: BadAbi , fun. sig . span ( ) ) ) ;
254282 }
255283}
256284
257285fn validate_params (
258286 errors : & mut Vec < ( Error , Span ) > ,
259287 fun : & ItemFn ,
260- ) -> Vec < ( Ident , SafeJniWrapperType ) > {
288+ no_env : bool ,
289+ no_strict_types : bool ,
290+ ) -> Vec < ( Ident , ParameterType ) > {
291+ fn parse_type (
292+ fun : & ItemFn ,
293+ no_env : bool ,
294+ index : usize ,
295+ param : & FnArg ,
296+ arg : & PatType ,
297+ ) -> Result < Option < SafeJniWrapperType > , ( Error , Span ) > {
298+ let Type :: Path ( TypePath { path, .. } ) = & * arg. ty else {
299+ return Err ( (
300+ Error :: BadParameterType ( arg. ty . to_token_stream ( ) . to_string ( ) ) ,
301+ arg. ty . span ( ) ,
302+ ) ) ;
303+ } ;
304+
305+ let Some ( ( path_str, _optional) ) = path_str ( path) else {
306+ return Err ( (
307+ Error :: BadParameterType ( arg. ty . to_token_stream ( ) . to_string ( ) ) ,
308+ param. span ( ) ,
309+ ) ) ;
310+ } ;
311+ if index == 0 && !no_env {
312+ const JNI_ENV_PATHS : & [ & str ] = & [ "JniEnv" , "jni::env::JniEnv" ] ;
313+
314+ if !JNI_ENV_PATHS . contains ( & path_str. as_str ( ) ) {
315+ return Err ( ( Error :: MissingEnv , fun. sig . span ( ) ) ) ;
316+ }
317+
318+ // Implicit
319+ return Ok ( None ) ;
320+ }
321+
322+ match SafeJniWrapperType :: from_str ( & path_str, false ) {
323+ Some ( parsed) => Ok ( Some ( parsed) ) ,
324+ None => Err ( ( Error :: BadParameterType ( path_str) , param. span ( ) ) ) ,
325+ }
326+ }
327+
261328 let mut params = Vec :: new ( ) ;
262329 for ( index, param) in fun. sig . inputs . iter ( ) . enumerate ( ) {
263330 match param {
264331 FnArg :: Receiver ( receiver) => errors. push ( ( Error :: HasReceiver , receiver. span ( ) ) ) ,
265332 FnArg :: Typed ( arg) => {
266- let Type :: Path ( TypePath { path, .. } ) = & * arg. ty else {
267- errors. push ( (
268- Error :: BadParameterType ( arg. ty . to_token_stream ( ) . to_string ( ) ) ,
269- arg. ty . span ( ) ,
270- ) ) ;
271- continue ;
272- } ;
273-
274333 let Pat :: Ident ( PatIdent { ident, .. } ) = & * arg. pat else {
275334 errors. push ( (
276335 Error :: BadParameterType ( arg. ty . to_token_stream ( ) . to_string ( ) ) ,
@@ -279,42 +338,38 @@ fn validate_params(
279338 continue ;
280339 } ;
281340
282- let Some ( ( path_str, _optional) ) = path_str ( path) else {
283- errors. push ( (
284- Error :: BadParameterType ( arg. ty . to_token_stream ( ) . to_string ( ) ) ,
285- param. span ( ) ,
286- ) ) ;
287- continue ;
288- } ;
289- if index == 0 {
290- const JNI_ENV_PATHS : & [ & str ] = & [ "JniEnv" , "jni::env::JniEnv" ] ;
291-
292- if !JNI_ENV_PATHS . contains ( & path_str. as_str ( ) ) {
293- errors. push ( ( Error :: MissingEnv , fun. sig . span ( ) ) ) ;
294- continue ;
295- }
341+ match parse_type ( fun, no_env, index, param, arg) {
342+ Ok ( Some ( parsed) ) => params. push ( ( ident. clone ( ) , ParameterType :: Strict ( parsed) ) ) ,
343+ Ok ( None ) => { } ,
344+ Err ( e) => {
345+ if no_strict_types {
346+ params. push ( ( ident. clone ( ) , ParameterType :: Loose ( arg. ty . clone ( ) ) ) ) ;
347+ continue ;
348+ }
296349
297- continue ;
350+ errors. push ( e) ;
351+ } ,
298352 }
299-
300- let Some ( parsed) = SafeJniWrapperType :: from_str ( & path_str, false ) else {
301- errors. push ( ( Error :: BadParameterType ( path_str) , param. span ( ) ) ) ;
302- continue ;
303- } ;
304-
305- params. push ( ( ident. clone ( ) , parsed) ) ;
306353 } ,
307354 }
308355 }
309356
310357 params
311358}
312359
313- fn validate_return ( errors : & mut Vec < ( Error , Span ) > , fun : & ItemFn ) -> Option < SafeJniWrapperType > {
360+ fn validate_return (
361+ errors : & mut Vec < ( Error , Span ) > ,
362+ fun : & ItemFn ,
363+ no_strict_types : bool ,
364+ ) -> Option < ParameterType > {
314365 let ReturnType :: Type ( _, ty) = & fun. sig . output else {
315366 return None ;
316367 } ;
317368
369+ if no_strict_types {
370+ return Some ( ParameterType :: Loose ( ty. clone ( ) ) ) ;
371+ }
372+
318373 let Type :: Path ( TypePath { path, .. } ) = & * * ty else {
319374 errors. push ( (
320375 Error :: BadReturnType ( ty. to_token_stream ( ) . to_string ( ) ) ,
@@ -335,7 +390,7 @@ fn validate_return(errors: &mut Vec<(Error, Span)>, fun: &ItemFn) -> Option<Safe
335390 return None ;
336391 } ;
337392
338- Some ( parsed)
393+ Some ( ParameterType :: Strict ( parsed) )
339394}
340395
341396fn path_str ( path : & Path ) -> Option < ( String , bool ) > {
@@ -375,22 +430,38 @@ fn path_str(path: &Path) -> Option<(String, bool)> {
375430
376431fn generate_extern_fn (
377432 fun : & ItemFn ,
378- params : & [ ( Ident , SafeJniWrapperType ) ] ,
379- return_type : Option < SafeJniWrapperType > ,
433+ params : & [ ( Ident , ParameterType ) ] ,
434+ return_type : Option < ParameterType > ,
435+ no_env : bool ,
380436) -> proc_macro2:: TokenStream {
381437 let fn_name = & fun. sig . ident ;
382438
383- let sys_params = params. iter ( ) . map ( |( param, parsed_ty) | {
439+ let mut sys_params = Vec :: new ( ) ;
440+ if !no_env {
441+ sys_params. push ( quote ! { env: * mut :: jni:: sys:: JNIEnv } ) ;
442+ }
443+
444+ sys_params. extend ( params. iter ( ) . map ( |( param, parsed_ty) | {
384445 let ty = parsed_ty. to_raw ( ) ;
385446 quote ! { #param: #ty }
386- } ) ;
447+ } ) ) ;
448+
449+ let mut arg_conversions = Vec :: new ( ) ;
450+ if !no_env {
451+ arg_conversions. push ( quote ! { let env = unsafe { :: jni:: env:: JniEnv :: from_raw( env) } ; } ) ;
452+ }
387453
388- let arg_conversions = params. iter ( ) . map ( |( param, parsed_ty) | {
454+ arg_conversions. extend ( params. iter ( ) . map ( |( param, parsed_ty) | {
389455 let conversion = parsed_ty. safe_conversion_fn ( param. clone ( ) ) ;
390456 quote ! { let #param = #conversion; }
391- } ) ;
457+ } ) ) ;
458+
459+ let mut all_param_names = Vec :: new ( ) ;
460+ if !no_env {
461+ all_param_names. push ( Ident :: new ( "env" , Span :: call_site ( ) ) ) ;
462+ }
392463
393- let all_param_names = params. iter ( ) . map ( |( param, _) | param) ;
464+ all_param_names. extend ( params. iter ( ) . map ( |( param, _) | param. clone ( ) ) ) ;
394465
395466 let result_ident = Ident :: new ( "result" , Span :: call_site ( ) ) ;
396467
@@ -408,11 +479,10 @@ fn generate_extern_fn(
408479 quote ! {
409480 #[ unsafe ( no_mangle) ]
410481 #[ allow( non_snake_case) ]
411- pub unsafe extern "system" fn #fn_name( env: * mut :: jni:: sys:: JNIEnv , #( #sys_params) , * ) #ret {
412- let env = unsafe { :: jni:: env:: JniEnv :: from_raw( env) } ;
482+ pub unsafe extern "system" fn #fn_name( #( #sys_params) , * ) #ret {
413483 #( #arg_conversions) *
414484
415- let #result_ident = super :: #fn_name( env , #( #all_param_names) , * ) ;
485+ let #result_ident = super :: #fn_name( #( #all_param_names) , * ) ;
416486 #to_raw_conversion
417487 }
418488 }
0 commit comments