[pbs-devel] [PATCH proxmox 13/18] api-macro: factor parameter extraction into a function
Wolfgang Bumiller
w.bumiller at proxmox.com
Fri Dec 18 12:26:01 CET 2020
Signed-off-by: Wolfgang Bumiller <w.bumiller at proxmox.com>
---
proxmox-api-macro/src/api/method.rs | 142 +++++++++++++++++-----------
1 file changed, 85 insertions(+), 57 deletions(-)
diff --git a/proxmox-api-macro/src/api/method.rs b/proxmox-api-macro/src/api/method.rs
index 3d6e9ed..ff5d3e0 100644
--- a/proxmox-api-macro/src/api/method.rs
+++ b/proxmox-api-macro/src/api/method.rs
@@ -458,63 +458,15 @@ fn create_wrapper_function(
ParameterType::ApiMethod => args.extend(quote_spanned! { span => api_method_param, }),
ParameterType::RpcEnv => args.extend(quote_spanned! { span => rpc_env_param, }),
ParameterType::Normal(param) => {
- let name_str = syn::LitStr::new(name.as_str(), span);
- let arg_name =
- Ident::new(&format!("input_arg_{}", name.as_ident().to_string()), span);
-
- // Optional parameters are expected to be Option<> types in the real function
- // signature, so we can just keep the returned Option from `input_map.remove()`.
- body.extend(quote_spanned! { span =>
- let #arg_name = input_map
- .remove(#name_str)
- .map(::serde_json::from_value)
- .transpose()?
- });
- let default_value = param.entry.schema.find_schema_property("default");
- if !param.entry.optional {
- // Non-optional types need to be extracted out of the option though (unless
- // they have a default):
- //
- // Whether the parameter is optional should have been verified by the schema
- // verifier already, so here we just use anyhow::bail! instead of building a
- // proper http error!
- body.extend(quote_spanned! { span =>
- .ok_or_else(|| ::anyhow::format_err!(
- "missing non-optional parameter: {}",
- #name_str,
- ))?
- });
- }
- let no_option_type = util::is_option_type(param.ty).is_none();
-
- if let Some(def) = &default_value {
- let name_uc = name.as_ident().to_string().to_uppercase();
- let name = Ident::new(
- &format!("API_METHOD_{}_PARAM_DEFAULT_{}", func_uc, name_uc),
- span,
- );
- // strip possible Option<> from this type:
- let ty = util::is_option_type(param.ty).unwrap_or(param.ty);
- default_consts.extend(quote_spanned! { span =>
- pub const #name: #ty = #def;
- });
- if param.entry.optional && no_option_type {
- // Optional parameter without an Option<T> type requires a default:
- body.extend(quote_spanned! { span =>
- .unwrap_or(#name)
- });
- }
- } else if param.entry.optional && no_option_type {
- // FIXME: we should not be able to reach this without having produced another
- // error above already anyway?
- error!(param.ty => "Optional parameter without Option<T> requires a default");
- // we produced an error so just write something that will compile
- body.extend(quote_spanned! { span =>
- .unwrap_or_else(|| unreachable!())
- });
- }
- body.extend(quote_spanned! { span => ; });
- args.extend(quote_spanned! { span => #arg_name, });
+ extract_normal_parameter(
+ param,
+ &mut body,
+ &mut args,
+ &func_uc,
+ name,
+ span,
+ default_consts,
+ )?;
}
}
}
@@ -573,6 +525,82 @@ fn create_wrapper_function(
Ok(api_func_name)
}
+fn extract_normal_parameter(
+ param: NormalParameter,
+ body: &mut TokenStream,
+ args: &mut TokenStream,
+ func_uc: &str,
+ name: FieldName,
+ name_span: Span,
+ default_consts: &mut TokenStream,
+) -> Result<(), Error> {
+ let span = name_span; // renamed during refactorization
+ let name_str = syn::LitStr::new(name.as_str(), span);
+ let arg_name = Ident::new(&format!("input_arg_{}", name.as_ident().to_string()), span);
+
+ // Optional parameters are expected to be Option<> types in the real function
+ // signature, so we can just keep the returned Option from `input_map.remove()`.
+ body.extend(quote_spanned! { span =>
+ let #arg_name = input_map
+ .remove(#name_str)
+ .map(::serde_json::from_value)
+ .transpose()?
+ });
+
+ let default_value = param.entry.schema.find_schema_property("default");
+ if !param.entry.optional {
+ // Non-optional types need to be extracted out of the option though (unless
+ // they have a default):
+ //
+ // Whether the parameter is optional should have been verified by the schema
+ // verifier already, so here we just use anyhow::bail! instead of building a
+ // proper http error!
+ body.extend(quote_spanned! { span =>
+ .ok_or_else(|| ::anyhow::format_err!(
+ "missing non-optional parameter: {}",
+ #name_str,
+ ))?
+ });
+ }
+
+ let no_option_type = util::is_option_type(param.ty).is_none();
+
+ if let Some(def) = &default_value {
+ let name_uc = name.as_ident().to_string().to_uppercase();
+ let name = Ident::new(
+ &format!("API_METHOD_{}_PARAM_DEFAULT_{}", func_uc, name_uc),
+ span,
+ );
+
+ // strip possible Option<> from this type:
+ let ty = util::is_option_type(param.ty).unwrap_or(param.ty);
+ default_consts.extend(quote_spanned! { span =>
+ pub const #name: #ty = #def;
+ });
+
+ if param.entry.optional && no_option_type {
+ // Optional parameter without an Option<T> type requires a default:
+ body.extend(quote_spanned! { span =>
+ .unwrap_or(#name)
+ });
+ }
+ } else if param.entry.optional && no_option_type {
+ // FIXME: we should not be able to reach this without having produced another
+ // error above already anyway?
+ error!(param.ty => "Optional parameter without Option<T> requires a default");
+
+ // we produced an error so just write something that will compile
+ body.extend(quote_spanned! { span =>
+ .unwrap_or_else(|| unreachable!())
+ });
+ }
+
+ body.extend(quote_spanned! { span => ; });
+ args.extend(quote_spanned! { span => #arg_name, });
+
+ Ok(())
+}
+
struct DefaultParameters<'a>(&'a Schema);
impl<'a> VisitMut for DefaultParameters<'a> {
--
2.20.1
More information about the pbs-devel
mailing list