forked from Proxmox/proxmox
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::mem;
|
||||
|
||||
use failure::Error;
|
||||
|
||||
@ -6,6 +7,7 @@ use proc_macro2::{Span, TokenStream};
|
||||
use quote::{quote, quote_spanned};
|
||||
use syn::spanned::Spanned;
|
||||
use syn::Ident;
|
||||
use syn::visit_mut::{self, VisitMut};
|
||||
|
||||
use super::{Schema, SchemaItem};
|
||||
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,
|
||||
)?;
|
||||
|
||||
// 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 mut ts = TokenStream::new();
|
||||
input_schema.to_typed_schema(&mut ts)?;
|
||||
@ -433,3 +438,38 @@ fn create_wrapper_function(
|
||||
|
||||
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)
|
||||
}
|
||||
|
||||
#[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;
|
||||
impl proxmox::api::RpcEnvironment for RpcEnv {
|
||||
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)
|
||||
.expect("func with option should work");
|
||||
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…
x
Reference in New Issue
Block a user