rust/util: replace Error::err_or_unit/err_or_else with Error::with_errp

Introduce a simpler function that hides the creation of the Error**.

Reviewed-by: Zhao Liu <zhao1.liu@intel.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
This commit is contained in:
Paolo Bonzini 2025-09-19 13:59:27 +02:00
parent 0830ec9405
commit 113a7f5bf3

View file

@ -14,8 +14,7 @@
//! [`ptr_or_propagate`](crate::Error::ptr_or_propagate) can be used to build
//! a C return value while also propagating an error condition
//!
//! * [`err_or_else`](crate::Error::err_or_else) and
//! [`err_or_unit`](crate::Error::err_or_unit) can be used to build a `Result`
//! * [`with_errp`](crate::Error::with_errp) can be used to build a `Result`
//!
//! This module is most commonly used at the boundary between C and Rust code;
//! other code will usually access it through the
@ -213,35 +212,21 @@ impl Error {
}
}
/// Convert a C `Error*` into a Rust `Result`, using
/// `Ok(())` if `c_error` is NULL. Free the `Error*`.
/// Pass a C `Error*` to the closure, and convert the result
/// (either the return value of the closure, or the error)
/// into a Rust `Result`.
///
/// # Safety
///
/// `c_error` must be `NULL` or valid; typically it was initialized
/// with `ptr::null_mut()` and passed by reference to a C function.
pub unsafe fn err_or_unit(c_error: *mut bindings::Error) -> Result<()> {
// SAFETY: caller guarantees c_error is valid
unsafe { Self::err_or_else(c_error, || ()) }
}
/// One exit from `f`, `c_error` must be unchanged or point to a
/// valid C [`struct Error`](bindings::Error).
pub unsafe fn with_errp<T, F: FnOnce(&mut *mut bindings::Error) -> T>(f: F) -> Result<T> {
let mut c_error: *mut bindings::Error = ptr::null_mut();
/// Convert a C `Error*` into a Rust `Result`, calling `f()` to
/// obtain an `Ok` value if `c_error` is NULL. Free the `Error*`.
///
/// # Safety
///
/// `c_error` must be `NULL` or point to a valid C [`struct
/// Error`](bindings::Error); typically it was initialized with
/// `ptr::null_mut()` and passed by reference to a C function.
pub unsafe fn err_or_else<T, F: FnOnce() -> T>(
c_error: *mut bindings::Error,
f: F,
) -> Result<T> {
// SAFETY: caller guarantees c_error is valid
let err = unsafe { Option::<Self>::from_foreign(c_error) };
match err {
None => Ok(f()),
Some(err) => Err(err),
// SAFETY: guaranteed by the postcondition of `f`
match (f(&mut c_error), unsafe { c_error.into_native() }) {
(result, None) => Ok(result),
(_, Some(err)) => Err(err),
}
}
}
@ -432,13 +417,16 @@ mod tests {
}
#[test]
fn test_err_or_unit() {
fn test_with_errp() {
unsafe {
let result = Error::err_or_unit(ptr::null_mut());
assert_match!(result, Ok(()));
let result = Error::with_errp(|_errp| true);
assert_match!(result, Ok(true));
let err = error_for_test(c"msg");
let err = Error::err_or_unit(err.into_inner()).unwrap_err();
let err = Error::with_errp(|errp| {
*errp = error_for_test(c"msg").into_inner();
false
})
.unwrap_err();
assert_eq!(&*format!("{err}"), "msg");
}
}