From: Paolo Bonzini Date: Fri, 19 Sep 2025 11:59:27 +0000 (+0200) Subject: rust/util: replace Error::err_or_unit/err_or_else with Error::with_errp X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=113a7f5bf3b0bea56e8961c63fe7e6abec32f53d;p=thirdparty%2Fqemu.git 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 Signed-off-by: Paolo Bonzini --- diff --git a/rust/util/src/error.rs b/rust/util/src/error.rs index 11b574ca59..346577e2e5 100644 --- a/rust/util/src/error.rs +++ b/rust/util/src/error.rs @@ -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, || ()) } - } - - /// 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>( - c_error: *mut bindings::Error, - f: F, - ) -> Result { - // SAFETY: caller guarantees c_error is valid - let err = unsafe { Option::::from_foreign(c_error) }; - match err { - None => Ok(f()), - Some(err) => Err(err), + /// 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: F) -> Result { + let mut c_error: *mut bindings::Error = ptr::null_mut(); + + // 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 err = error_for_test(c"msg"); - let err = Error::err_or_unit(err.into_inner()).unwrap_err(); + let result = Error::with_errp(|_errp| true); + assert_match!(result, Ok(true)); + + let err = Error::with_errp(|errp| { + *errp = error_for_test(c"msg").into_inner(); + false + }) + .unwrap_err(); assert_eq!(&*format!("{err}"), "msg"); } }