From fab021028781c8005df121a4d2ce7e46eb253d19 Mon Sep 17 00:00:00 2001 From: Wolfgang Bumiller Date: Tue, 30 Jul 2019 10:06:32 +0200 Subject: [PATCH] api, macro: implement 'format' verifier for structs Signed-off-by: Wolfgang Bumiller --- proxmox-api-macro/src/api_def.rs | 9 +++++++++ proxmox-api-macro/src/api_macro.rs | 12 ++++++++++++ proxmox-api-macro/src/parsing.rs | 7 +++++++ proxmox-api/src/meta.rs | 28 ++++++++++++++++++++++++++++ 4 files changed, 56 insertions(+) diff --git a/proxmox-api-macro/src/api_def.rs b/proxmox-api-macro/src/api_def.rs index 4b57bb2c..f63d80ed 100644 --- a/proxmox-api-macro/src/api_def.rs +++ b/proxmox-api-macro/src/api_def.rs @@ -101,6 +101,12 @@ pub struct ParameterDefinition { pub minimum_length: Option, #[builder(default)] pub validate: Option, + + /// Formats are module paths. The module must contain a verify function: + /// `fn verify(Option<&str>) -> bool`, and a `NAME` constant used in error messages to refer to + /// the format name. + #[builder(default)] + pub format: Option, } impl ParameterDefinition { @@ -135,6 +141,9 @@ impl ParameterDefinition { "validate" => { def.validate(Some(value.expect_expr()?)); } + "format" => { + def.format(Some(value.expect_path()?)); + } other => c_bail!(key.span(), "invalid key in type definition: {}", other), } } diff --git a/proxmox-api-macro/src/api_macro.rs b/proxmox-api-macro/src/api_macro.rs index d2cbbe8d..09f2f697 100644 --- a/proxmox-api-macro/src/api_macro.rs +++ b/proxmox-api-macro/src/api_macro.rs @@ -635,6 +635,18 @@ fn named_struct_impl_verify(span: Span, fields: &[StructField]) -> Result + if !#value::verify(::proxmox::api::meta::AsOptionStr::as_option_str( + &self.#field_ident, + )) { + error_string.push_str( + &format!("field {} does not match format {}", #field_str, #value::NAME) + ); + } + }); + } } if !body.is_empty() { diff --git a/proxmox-api-macro/src/parsing.rs b/proxmox-api-macro/src/parsing.rs index 00042317..1082f44e 100644 --- a/proxmox-api-macro/src/parsing.rs +++ b/proxmox-api-macro/src/parsing.rs @@ -257,6 +257,13 @@ impl Expression { } } + pub fn expect_path(self) -> Result { + match self { + Expression::Expr(Expr::Path(path)) => Ok(path.path), + other => c_bail!(other.span(), "expected expression, found {:?}", other), + } + } + pub fn expect_object(self) -> Result { match self { Expression::Object(obj) => Ok(obj), diff --git a/proxmox-api/src/meta.rs b/proxmox-api/src/meta.rs index 8021028d..331345ed 100644 --- a/proxmox-api/src/meta.rs +++ b/proxmox-api/src/meta.rs @@ -26,3 +26,31 @@ where *self = Some(value); } } + +pub trait AsOptionStr { + fn as_option_str(&self) -> Option<&str>; +} + +impl AsOptionStr for String { + fn as_option_str(&self) -> Option<&str> { + Some(self.as_str()) + } +} + +impl AsOptionStr for str { + fn as_option_str(&self) -> Option<&str> { + Some(self) + } +} + +impl AsOptionStr for Option { + fn as_option_str(&self) -> Option<&str> { + self.as_ref().map(String::as_str) + } +} + +impl AsOptionStr for Option<&str> { + fn as_option_str(&self) -> Option<&str> { + *self + } +}