diff --git a/proxmox-schema/src/schema.rs b/proxmox-schema/src/schema.rs index 0f90682a..79b240f1 100644 --- a/proxmox-schema/src/schema.rs +++ b/proxmox-schema/src/schema.rs @@ -21,6 +21,32 @@ pub struct ParameterError { error_list: Vec<(String, Error)>, } +/// Like anyhow's `format_err` but producing a `ParameterError`. +#[macro_export] +macro_rules! param_format_err { + ($field:expr, $err:expr) => { + $crate::ParameterError::from(($field, $err)) + }; + + ($field:expr, $($msg:tt)+) => { + $crate::ParameterError::from(($field, ::anyhow::format_err!($($msg)+))) + }; +} + +/// Like anyhow's `bail` but enclosing a `ParameterError`, so +/// a `downcast` can extract it later. This is useful for +/// API calls that need to do parameter checking manually. +#[macro_export] +macro_rules! param_bail { + ($field:expr, $err:expr) => {{ + return Err($crate::param_format_err!($field, $err).into()); + }}; + + ($field:expr, $($msg:tt)+) => {{ + return Err($crate::param_format_err!($field, $($msg)+).into()); + }}; +} + impl std::error::Error for ParameterError {} impl ParameterError { @@ -538,7 +564,7 @@ impl ArraySchema { for (i, item) in list.iter().enumerate() { let result = self.items.verify_json(item); if let Err(err) = result { - return Err(ParameterError::from((format!("[{}]", i), err)).into()); + param_bail!(format!("[{}]", i), err); } } diff --git a/proxmox-schema/tests/schema.rs b/proxmox-schema/tests/schema.rs index ed09bb18..a0d79866 100644 --- a/proxmox-schema/tests/schema.rs +++ b/proxmox-schema/tests/schema.rs @@ -395,3 +395,16 @@ fn test_verify_complex_array() { assert!(res.is_err()); } } + +#[test] +fn test_parameter_error_macro() { + fn _bail_with_format() -> Result<(), anyhow::Error> { + let baz = "baz"; + param_bail!("foo", "bar: {}", baz); + } + + fn _bail_with_err() -> Result<(), anyhow::Error> { + let err = anyhow::format_err!("bar"); + param_bail!("foo", err); + } +}