rust/util: add ensure macro
The macro is similar to anyhow::ensure but uses QEMU's variation on anyhow::Error. It can be used to easily check a condition and format an error message. Reviewed-by: Zhao Liu <zhao1.liu@intel.com> Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
This commit is contained in:
parent
71260a0120
commit
56dbf087a8
3 changed files with 86 additions and 13 deletions
|
|
@ -25,7 +25,10 @@ use system::{
|
|||
bindings::{address_space_memory, address_space_stl_le, hwaddr},
|
||||
MemoryRegion, MemoryRegionOps, MemoryRegionOpsBuilder, MEMTXATTRS_UNSPECIFIED,
|
||||
};
|
||||
use util::timer::{Timer, CLOCK_VIRTUAL, NANOSECONDS_PER_SECOND};
|
||||
use util::{
|
||||
ensure,
|
||||
timer::{Timer, CLOCK_VIRTUAL, NANOSECONDS_PER_SECOND},
|
||||
};
|
||||
|
||||
use crate::fw_cfg::HPETFwConfig;
|
||||
|
||||
|
|
@ -728,14 +731,14 @@ impl HPETState {
|
|||
}
|
||||
|
||||
fn realize(&self) -> util::Result<()> {
|
||||
if self.num_timers < HPET_MIN_TIMERS || self.num_timers > HPET_MAX_TIMERS {
|
||||
Err(format!(
|
||||
"hpet.num_timers must be between {HPET_MIN_TIMERS} and {HPET_MAX_TIMERS}"
|
||||
))?;
|
||||
}
|
||||
if self.int_route_cap == 0 {
|
||||
Err("hpet.hpet-intcap property not initialized")?;
|
||||
}
|
||||
ensure!(
|
||||
(HPET_MIN_TIMERS..=HPET_MAX_TIMERS).contains(&self.num_timers),
|
||||
"hpet.num_timers must be between {HPET_MIN_TIMERS} and {HPET_MAX_TIMERS}"
|
||||
);
|
||||
ensure!(
|
||||
self.int_route_cap != 0,
|
||||
"hpet.hpet-intcap property not initialized"
|
||||
);
|
||||
|
||||
self.hpet_id.set(HPETFwConfig::assign_hpet_id()?);
|
||||
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@
|
|||
use std::ptr::addr_of_mut;
|
||||
|
||||
use common::Zeroable;
|
||||
use util::{self, ensure};
|
||||
|
||||
/// Each `HPETState` represents a Event Timer Block. The v1 spec supports
|
||||
/// up to 8 blocks. QEMU only uses 1 block (in PC machine).
|
||||
|
|
@ -36,7 +37,7 @@ pub static mut hpet_fw_cfg: HPETFwConfig = HPETFwConfig {
|
|||
};
|
||||
|
||||
impl HPETFwConfig {
|
||||
pub(crate) fn assign_hpet_id() -> Result<usize, &'static str> {
|
||||
pub(crate) fn assign_hpet_id() -> util::Result<usize> {
|
||||
assert!(bql::is_locked());
|
||||
// SAFETY: all accesses go through these methods, which guarantee
|
||||
// that the accesses are protected by the BQL.
|
||||
|
|
@ -47,9 +48,7 @@ impl HPETFwConfig {
|
|||
fw_cfg.count = 0;
|
||||
}
|
||||
|
||||
if fw_cfg.count == 8 {
|
||||
Err("Only 8 instances of HPET are allowed")?;
|
||||
}
|
||||
ensure!(fw_cfg.count != 8, "Only 8 instances of HPET are allowed");
|
||||
|
||||
let id: usize = fw_cfg.count.into();
|
||||
fw_cfg.count += 1;
|
||||
|
|
|
|||
|
|
@ -86,6 +86,19 @@ impl Display for Error {
|
|||
}
|
||||
}
|
||||
|
||||
impl From<Cow<'static, str>> for Error {
|
||||
#[track_caller]
|
||||
fn from(msg: Cow<'static, str>) -> Self {
|
||||
let location = panic::Location::caller();
|
||||
Error {
|
||||
msg: Some(msg),
|
||||
cause: None,
|
||||
file: location.file(),
|
||||
line: location.line(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<String> for Error {
|
||||
#[track_caller]
|
||||
fn from(msg: String) -> Self {
|
||||
|
|
@ -126,6 +139,17 @@ impl From<anyhow::Error> for Error {
|
|||
}
|
||||
|
||||
impl Error {
|
||||
#[track_caller]
|
||||
#[doc(hidden)]
|
||||
pub fn format(args: fmt::Arguments) -> Self {
|
||||
if let Some(msg) = args.as_str() {
|
||||
Self::from(msg)
|
||||
} else {
|
||||
let msg = fmt::format(args);
|
||||
Self::from(msg)
|
||||
}
|
||||
}
|
||||
|
||||
/// Create a new error, prepending `msg` to the
|
||||
/// description of `cause`
|
||||
#[track_caller]
|
||||
|
|
@ -311,6 +335,53 @@ impl FromForeign for Error {
|
|||
}
|
||||
}
|
||||
|
||||
/// Ensure that a condition is true, returning an error if it is false.
|
||||
///
|
||||
/// This macro is similar to [`anyhow::ensure`] but returns a QEMU [`Result`].
|
||||
/// If the condition evaluates to `false`, the macro returns early with an error
|
||||
/// constructed from the provided message.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// # use util::{ensure, Result};
|
||||
/// # fn check_positive(x: i32) -> Result<()> {
|
||||
/// ensure!(x > 0, "value must be positive");
|
||||
/// # Ok(())
|
||||
/// # }
|
||||
/// ```
|
||||
///
|
||||
/// ```
|
||||
/// # use util::{ensure, Result};
|
||||
/// # const MIN: i32 = 123;
|
||||
/// # const MAX: i32 = 456;
|
||||
/// # fn check_range(x: i32) -> Result<()> {
|
||||
/// ensure!(
|
||||
/// x >= MIN && x <= MAX,
|
||||
/// "{} not between {} and {}",
|
||||
/// x,
|
||||
/// MIN,
|
||||
/// MAX
|
||||
/// );
|
||||
/// # Ok(())
|
||||
/// # }
|
||||
/// ```
|
||||
#[macro_export]
|
||||
macro_rules! ensure {
|
||||
($cond:expr, $fmt:literal, $($arg:tt)*) => {
|
||||
if !$cond {
|
||||
let e = $crate::Error::format(format_args!($fmt, $($arg)*));
|
||||
return $crate::Result::Err(e);
|
||||
}
|
||||
};
|
||||
($cond:expr, $err:expr $(,)?) => {
|
||||
if !$cond {
|
||||
let s = ::std::borrow::Cow::<'static, str>::from($err);
|
||||
return $crate::Result::Err(s.into());
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use std::ffi::CStr;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue