mirror of
https://git.proxmox.com/git/proxmox
synced 2025-05-30 00:28:13 +00:00
api-macro: add api_get_default!() macro
When writing an #[api] function, one can now access default values by parameter name (see test_default_option in tests/options.rs): #[api(...)] pub fn func(value: Option<isize>) { println!( "value: {}", value.unwrap_or(api_get_default!("value")), ); } Signed-off-by: Wolfgang Bumiller <w.bumiller@proxmox.com>
This commit is contained in:
parent
8beec0d6e6
commit
f5d15872f4
@ -1,4 +1,5 @@
|
|||||||
use std::convert::{TryFrom, TryInto};
|
use std::convert::{TryFrom, TryInto};
|
||||||
|
use std::mem;
|
||||||
|
|
||||||
use failure::Error;
|
use failure::Error;
|
||||||
|
|
||||||
@ -6,6 +7,7 @@ use proc_macro2::{Span, TokenStream};
|
|||||||
use quote::{quote, quote_spanned};
|
use quote::{quote, quote_spanned};
|
||||||
use syn::spanned::Spanned;
|
use syn::spanned::Spanned;
|
||||||
use syn::Ident;
|
use syn::Ident;
|
||||||
|
use syn::visit_mut::{self, VisitMut};
|
||||||
|
|
||||||
use super::{Schema, SchemaItem};
|
use super::{Schema, SchemaItem};
|
||||||
use crate::util::{self, FieldName, JSONObject};
|
use crate::util::{self, FieldName, JSONObject};
|
||||||
@ -55,6 +57,9 @@ pub fn handle_method(mut attribs: JSONObject, mut func: syn::ItemFn) -> Result<T
|
|||||||
&mut wrapper_ts,
|
&mut wrapper_ts,
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
|
// input schema is done, let's give the method body a chance to extract default parameters:
|
||||||
|
DefaultParameters(&input_schema).visit_item_fn_mut(&mut func);
|
||||||
|
|
||||||
let input_schema = {
|
let input_schema = {
|
||||||
let mut ts = TokenStream::new();
|
let mut ts = TokenStream::new();
|
||||||
input_schema.to_typed_schema(&mut ts)?;
|
input_schema.to_typed_schema(&mut ts)?;
|
||||||
@ -433,3 +438,38 @@ fn create_wrapper_function(
|
|||||||
|
|
||||||
Ok(api_func_name)
|
Ok(api_func_name)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct DefaultParameters<'a>(&'a Schema);
|
||||||
|
|
||||||
|
impl<'a> VisitMut for DefaultParameters<'a> {
|
||||||
|
fn visit_expr_mut(&mut self, i: &mut syn::Expr) {
|
||||||
|
if let syn::Expr::Macro(exprmac) = i {
|
||||||
|
if exprmac.mac.path.is_ident("api_get_default") {
|
||||||
|
// replace api_get_default macros with the actual default found in the #[api]
|
||||||
|
// macro.
|
||||||
|
match self.get_default(mem::take(&mut exprmac.mac.tokens)) {
|
||||||
|
Ok(expr) => *i = expr,
|
||||||
|
Err(err) => {
|
||||||
|
*i = syn::Expr::Verbatim(err.to_compile_error());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
visit_mut::visit_expr_mut(self, i)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> DefaultParameters<'a> {
|
||||||
|
fn get_default(&self, param_tokens: TokenStream) -> Result<syn::Expr, syn::Error> {
|
||||||
|
let param_name: syn::LitStr = syn::parse2(param_tokens)?;
|
||||||
|
match self.0.find_obj_property_by_ident(¶m_name.value()) {
|
||||||
|
Some((_ident, _optional, schema)) => match schema.find_schema_property("default") {
|
||||||
|
Some(def) => Ok(def.clone()),
|
||||||
|
None => bail!(param_name => "no default found in schema")
|
||||||
|
}
|
||||||
|
None => bail!(param_name => "todo"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -21,6 +21,24 @@ pub fn test_option(value: bool) -> Result<bool, Error> {
|
|||||||
Ok(value)
|
Ok(value)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[api(
|
||||||
|
input: {
|
||||||
|
properties: {
|
||||||
|
value: {
|
||||||
|
description: "The optional value with default.",
|
||||||
|
optional: true,
|
||||||
|
default: 5,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)]
|
||||||
|
/// Print the given message.
|
||||||
|
///
|
||||||
|
/// Returns: the input.
|
||||||
|
pub fn test_default_macro(value: Option<isize>) -> Result<isize, Error> {
|
||||||
|
Ok(value.unwrap_or(api_get_default!("value")))
|
||||||
|
}
|
||||||
|
|
||||||
struct RpcEnv;
|
struct RpcEnv;
|
||||||
impl proxmox::api::RpcEnvironment for RpcEnv {
|
impl proxmox::api::RpcEnvironment for RpcEnv {
|
||||||
fn set_result_attrib(&mut self, name: &str, value: Value) {
|
fn set_result_attrib(&mut self, name: &str, value: Value) {
|
||||||
@ -65,4 +83,8 @@ fn test_invocations() {
|
|||||||
let value = api_function_test_option(json!({"value": false}), &API_METHOD_TEST_OPTION, &mut env)
|
let value = api_function_test_option(json!({"value": false}), &API_METHOD_TEST_OPTION, &mut env)
|
||||||
.expect("func with option should work");
|
.expect("func with option should work");
|
||||||
assert_eq!(value, false);
|
assert_eq!(value, false);
|
||||||
|
|
||||||
|
let value = api_function_test_default_macro(json!({}), &API_METHOD_TEST_DEFAULT_MACRO, &mut env)
|
||||||
|
.expect("func with option should work");
|
||||||
|
assert_eq!(value, 5);
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user