From 808035f5248ceca1627c32a8802db80d28decb81 Mon Sep 17 00:00:00 2001 From: Wolfgang Bumiller Date: Mon, 16 Dec 2019 11:13:26 +0100 Subject: [PATCH] api-macro: support 'async fn' with new async api method Signed-off-by: Wolfgang Bumiller --- proxmox-api-macro/src/api/method.rs | 78 ++++++++++++++++++++++------- proxmox-api-macro/tests/api2.rs | 15 ++++++ 2 files changed, 74 insertions(+), 19 deletions(-) diff --git a/proxmox-api-macro/src/api/method.rs b/proxmox-api-macro/src/api/method.rs index d86b7bba..27961e32 100644 --- a/proxmox-api-macro/src/api/method.rs +++ b/proxmox-api-macro/src/api/method.rs @@ -47,6 +47,7 @@ pub fn handle_method(mut attribs: JSONObject, mut func: syn::ItemFn) -> Result Result #vis const #api_method_name: ::proxmox::api::ApiMethod = ::proxmox::api::ApiMethod::new( - &::proxmox::api::ApiHandler::Sync(&#api_func_name), + &#api_handler, &#input_schema, ) #returns_schema @@ -159,10 +166,7 @@ fn handle_function_signature( wrapper_ts: &mut TokenStream, ) -> Result { let sig = &func.sig; - - if sig.asyncness.is_some() { - bail!(sig => "async fn is currently not supported"); - } + let is_async = sig.asyncness.is_some(); let mut api_method_param = None; let mut rpc_env_param = None; @@ -296,7 +300,14 @@ fn handle_function_signature( } */ - create_wrapper_function(input_schema, returns_schema, param_list, func, wrapper_ts) + create_wrapper_function( + input_schema, + returns_schema, + param_list, + func, + wrapper_ts, + is_async, + ) } fn is_api_method_type(ty: &syn::Type) -> bool { @@ -351,6 +362,7 @@ fn create_wrapper_function( param_list: Vec<(FieldName, ParameterType)>, func: &syn::ItemFn, wrapper_ts: &mut TokenStream, + is_async: bool, ) -> Result { let api_func_name = Ident::new( &format!("api_function_{}", &func.sig.ident), @@ -401,25 +413,53 @@ fn create_wrapper_function( // build the wrapping function: let func_name = &func.sig.ident; + let await_keyword = if is_async { Some(quote!(.await)) } else { None }; + let question_mark = match func.sig.output { syn::ReturnType::Default => None, _ => Some(quote!(?)), }; - wrapper_ts.extend(quote! { - fn #api_func_name( - mut input_params: ::serde_json::Value, - api_method_param: &::proxmox::api::ApiMethod, - rpc_env_param: &mut dyn ::proxmox::api::RpcEnvironment, - ) -> Result<::serde_json::Value, ::failure::Error> { - if let ::serde_json::Value::Object(ref mut input_map) = &mut input_params { - #body - Ok(::serde_json::to_value(#func_name(#args) #question_mark)?) - } else { - ::failure::bail!("api function wrapper called with a non-object json value"); - } + let body = quote! { + if let ::serde_json::Value::Object(ref mut input_map) = &mut input_params { + #body + Ok(::serde_json::to_value(#func_name(#args) #await_keyword #question_mark)?) + } else { + ::failure::bail!("api function wrapper called with a non-object json value"); } - }); + }; + + if is_async { + wrapper_ts.extend(quote! { + fn #api_func_name<'a>( + mut input_params: ::serde_json::Value, + api_method_param: &'static ::proxmox::api::ApiMethod, + rpc_env_param: &'a mut dyn ::proxmox::api::RpcEnvironment, + ) -> ::proxmox::api::ApiFuture<'a> { + //async fn func<'a>( + // mut input_params: ::serde_json::Value, + // api_method_param: &'static ::proxmox::api::ApiMethod, + // rpc_env_param: &'a mut dyn ::proxmox::api::RpcEnvironment, + //) -> ::std::result::Result<::serde_json::Value, ::failure::Error> { + // #body + //} + //::std::boxed::Box::pin(async move { + // func(input_params, api_method_param, rpc_env_param).await + //}) + ::std::boxed::Box::pin(async move { #body }) + } + }); + } else { + wrapper_ts.extend(quote! { + fn #api_func_name( + mut input_params: ::serde_json::Value, + api_method_param: &::proxmox::api::ApiMethod, + rpc_env_param: &mut dyn ::proxmox::api::RpcEnvironment, + ) -> ::std::result::Result<::serde_json::Value, ::failure::Error> { + #body + } + }); + } Ok(api_func_name) } diff --git a/proxmox-api-macro/tests/api2.rs b/proxmox-api-macro/tests/api2.rs index 75df610e..a7db7038 100644 --- a/proxmox-api-macro/tests/api2.rs +++ b/proxmox-api-macro/tests/api2.rs @@ -1,6 +1,7 @@ use proxmox_api_macro::api; use failure::Error; +use serde_json::Value; #[api( input: { @@ -16,3 +17,17 @@ pub fn hello(message: String) -> Result<(), Error> { println!("Hello there. {}", message); Ok(()) } + +#[api( + input: { + properties: { + num: { + description: "The version to upgrade to", + }, + }, + }, +)] +/// Return the number... +pub async fn number(num: u32) -> Result { + Ok(num) +}