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:
parent
0830ec9405
commit
113a7f5bf3
1 changed files with 20 additions and 32 deletions
|
|
@ -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");
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue