From b77733c8efd76fc6858a363569b690f7c3f9cc68 Mon Sep 17 00:00:00 2001 From: Wolfgang Bumiller Date: Mon, 29 Jul 2019 14:40:04 +0200 Subject: [PATCH] api: macro: implement minimum/maximum_length checks Signed-off-by: Wolfgang Bumiller --- proxmox-api-macro/src/api_def.rs | 10 ++++++ proxmox-api-macro/src/api_macro.rs | 53 ++++++++++++++++++++++-------- proxmox-api/src/verify.rs | 29 ++++++++++++++++ 3 files changed, 78 insertions(+), 14 deletions(-) diff --git a/proxmox-api-macro/src/api_def.rs b/proxmox-api-macro/src/api_def.rs index 5801c086..4b57bb2c 100644 --- a/proxmox-api-macro/src/api_def.rs +++ b/proxmox-api-macro/src/api_def.rs @@ -96,6 +96,10 @@ pub struct ParameterDefinition { #[builder(default)] pub minimum: Option, #[builder(default)] + pub maximum_length: Option, + #[builder(default)] + pub minimum_length: Option, + #[builder(default)] pub validate: Option, } @@ -122,6 +126,12 @@ impl ParameterDefinition { "minimum" => { def.minimum(Some(value.expect_expr()?)); } + "maximum_length" => { + def.maximum_length(Some(value.expect_expr()?)); + } + "minimum_length" => { + def.minimum_length(Some(value.expect_expr()?)); + } "validate" => { def.validate(Some(value.expect_expr()?)); } diff --git a/proxmox-api-macro/src/api_macro.rs b/proxmox-api-macro/src/api_macro.rs index f47bc994..d2cbbe8d 100644 --- a/proxmox-api-macro/src/api_macro.rs +++ b/proxmox-api-macro/src/api_macro.rs @@ -580,32 +580,57 @@ fn handle_struct_named( }) } -fn named_struct_impl_verify( - span: Span, - fields: &[StructField], -) -> Result { +fn named_struct_impl_verify(span: Span, fields: &[StructField]) -> Result { let mut body = TokenStream::new(); for field in fields { let field_ident = field.ident; let field_str = &field.strlit; - if let Some(ref minimum) = field.def.minimum { - body.extend(quote_spanned! { minimum.span() => - let minimum = #minimum; - if !::proxmox::api::verify::TestMinMax::test_minimum(&self.#field_ident, &minimum) { + if let Some(ref value) = field.def.minimum { + body.extend(quote_spanned! { value.span() => + let value = #value; + if !::proxmox::api::verify::TestMinMax::test_minimum(&self.#field_ident, &value) { error_string.push_str( - &format!("field {} out of range, must be >= {}", #field_str, minimum) + &format!("field {} out of range, must be >= {}", #field_str, value) ); } }); } - if let Some(ref maximum) = field.def.maximum { - body.extend(quote_spanned! { maximum.span() => - let maximum = #maximum; - if !::proxmox::api::verify::TestMinMax::test_maximum(&self.#field_ident, &maximum) { + if let Some(ref value) = field.def.maximum { + body.extend(quote_spanned! { value.span() => + let value = #value; + if !::proxmox::api::verify::TestMinMax::test_maximum(&self.#field_ident, &value) { error_string.push_str( - &format!("field {} out of range, must be <= {}", #field_str, maximum) + &format!("field {} out of range, must be <= {}", #field_str, value) + ); + } + }); + } + + if let Some(ref value) = field.def.minimum_length { + body.extend(quote_spanned! { value.span() => + let value = #value; + if !::proxmox::api::verify::TestMinMaxLen::test_minimum_length( + &self.#field_ident, + value, + ) { + error_string.push_str( + &format!("field {} too short, must be >= {} characters", #field_str, value) + ); + } + }); + } + + if let Some(ref value) = field.def.maximum_length { + body.extend(quote_spanned! { value.span() => + let value = #value; + if !::proxmox::api::verify::TestMinMaxLen::test_maximum_length( + &self.#field_ident, + value, + ) { + error_string.push_str( + &format!("field {} too long, must be <= {} characters", #field_str, value) ); } }); diff --git a/proxmox-api/src/verify.rs b/proxmox-api/src/verify.rs index defa5d8e..328cf80e 100644 --- a/proxmox-api/src/verify.rs +++ b/proxmox-api/src/verify.rs @@ -74,3 +74,32 @@ where self.as_ref().map(|x| *x <= *maximum).unwrap_or(true) } } + +pub trait TestMinMaxLen { + fn test_minimum_length(&self, minimum: usize) -> bool; + fn test_maximum_length(&self, maximum: usize) -> bool; +} + +impl> TestMinMaxLen for T { + #[inline] + fn test_minimum_length(&self, minimum: usize) -> bool { + self.as_ref().len() >= minimum + } + + #[inline] + fn test_maximum_length(&self, maximum: usize) -> bool { + self.as_ref().len() <= maximum + } +} + +impl> TestMinMaxLen for Option { + #[inline] + fn test_minimum_length(&self, minimum: usize) -> bool { + self.as_ref().map(|x| x.as_ref().len() >= minimum).unwrap_or(true) + } + + #[inline] + fn test_maximum_length(&self, maximum: usize) -> bool { + self.as_ref().map(|x| x.as_ref().len() <= maximum).unwrap_or(true) + } +}