summary refs log tree commit diff stats
path: root/rust/qemu-api/src/error.rs
diff options
context:
space:
mode:
Diffstat (limited to 'rust/qemu-api/src/error.rs')
-rw-r--r--rust/qemu-api/src/error.rs416
1 files changed, 0 insertions, 416 deletions
diff --git a/rust/qemu-api/src/error.rs b/rust/qemu-api/src/error.rs
deleted file mode 100644
index e114fc4178..0000000000
--- a/rust/qemu-api/src/error.rs
+++ /dev/null
@@ -1,416 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-or-later
-
-//! Error propagation for QEMU Rust code
-//!
-//! This module contains [`Error`], the bridge between Rust errors and
-//! [`Result`](std::result::Result)s and QEMU's C [`Error`](bindings::Error)
-//! struct.
-//!
-//! For FFI code, [`Error`] provides functions to simplify conversion between
-//! the Rust ([`Result<>`](std::result::Result)) and C (`Error**`) conventions:
-//!
-//! * [`ok_or_propagate`](crate::Error::ok_or_propagate),
-//!   [`bool_or_propagate`](crate::Error::bool_or_propagate),
-//!   [`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`
-//!
-//! This module is most commonly used at the boundary between C and Rust code;
-//! other code will usually access it through the
-//! [`qemu_api::Result`](crate::Result) type alias, and will use the
-//! [`std::error::Error`] interface to let C errors participate in Rust's error
-//! handling functionality.
-//!
-//! Rust code can also create use this module to create an error object that
-//! will be passed up to C code, though in most cases this will be done
-//! transparently through the `?` operator.  Errors can be constructed from a
-//! simple error string, from an [`anyhow::Error`] to pass any other Rust error
-//! type up to C code, or from a combination of the two.
-//!
-//! The third case, corresponding to [`Error::with_error`], is the only one that
-//! requires mentioning [`qemu_api::Error`](crate::Error) explicitly.  Similar
-//! to how QEMU's C code handles errno values, the string and the
-//! `anyhow::Error` object will be concatenated with `:` as the separator.
-
-use std::{
-    borrow::Cow,
-    ffi::{c_char, c_int, c_void, CStr},
-    fmt::{self, Display},
-    panic, ptr,
-};
-
-use foreign::{prelude::*, OwnedPointer};
-
-use crate::bindings;
-
-pub type Result<T> = std::result::Result<T, Error>;
-
-#[derive(Debug)]
-pub struct Error {
-    msg: Option<Cow<'static, str>>,
-    /// Appends the print string of the error to the msg if not None
-    cause: Option<anyhow::Error>,
-    file: &'static str,
-    line: u32,
-}
-
-impl std::error::Error for Error {
-    fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
-        self.cause.as_ref().map(AsRef::as_ref)
-    }
-
-    #[allow(deprecated)]
-    fn description(&self) -> &str {
-        self.msg
-            .as_deref()
-            .or_else(|| self.cause.as_deref().map(std::error::Error::description))
-            .expect("no message nor cause?")
-    }
-}
-
-impl Display for Error {
-    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        let mut prefix = "";
-        if let Some(ref msg) = self.msg {
-            write!(f, "{msg}")?;
-            prefix = ": ";
-        }
-        if let Some(ref cause) = self.cause {
-            write!(f, "{prefix}{cause}")?;
-        } else if prefix.is_empty() {
-            panic!("no message nor cause?");
-        }
-        Ok(())
-    }
-}
-
-impl From<String> for Error {
-    #[track_caller]
-    fn from(msg: String) -> Self {
-        let location = panic::Location::caller();
-        Error {
-            msg: Some(Cow::Owned(msg)),
-            cause: None,
-            file: location.file(),
-            line: location.line(),
-        }
-    }
-}
-
-impl From<&'static str> for Error {
-    #[track_caller]
-    fn from(msg: &'static str) -> Self {
-        let location = panic::Location::caller();
-        Error {
-            msg: Some(Cow::Borrowed(msg)),
-            cause: None,
-            file: location.file(),
-            line: location.line(),
-        }
-    }
-}
-
-impl From<anyhow::Error> for Error {
-    #[track_caller]
-    fn from(error: anyhow::Error) -> Self {
-        let location = panic::Location::caller();
-        Error {
-            msg: None,
-            cause: Some(error),
-            file: location.file(),
-            line: location.line(),
-        }
-    }
-}
-
-impl Error {
-    /// Create a new error, prepending `msg` to the
-    /// description of `cause`
-    #[track_caller]
-    pub fn with_error(msg: impl Into<Cow<'static, str>>, cause: impl Into<anyhow::Error>) -> Self {
-        let location = panic::Location::caller();
-        Error {
-            msg: Some(msg.into()),
-            cause: Some(cause.into()),
-            file: location.file(),
-            line: location.line(),
-        }
-    }
-
-    /// Consume a result, returning `false` if it is an error and
-    /// `true` if it is successful.  The error is propagated into
-    /// `errp` like the C API `error_propagate` would do.
-    ///
-    /// # Safety
-    ///
-    /// `errp` must be a valid argument to `error_propagate`;
-    /// typically it is received from C code and need not be
-    /// checked further at the Rust↔C boundary.
-    pub unsafe fn bool_or_propagate(result: Result<()>, errp: *mut *mut bindings::Error) -> bool {
-        // SAFETY: caller guarantees errp is valid
-        unsafe { Self::ok_or_propagate(result, errp) }.is_some()
-    }
-
-    /// Consume a result, returning a `NULL` pointer if it is an error and
-    /// a C representation of the contents if it is successful.  This is
-    /// similar to the C API `error_propagate`, but it panics if `*errp`
-    /// is not `NULL`.
-    ///
-    /// # Safety
-    ///
-    /// `errp` must be a valid argument to `error_propagate`;
-    /// typically it is received from C code and need not be
-    /// checked further at the Rust↔C boundary.
-    ///
-    /// See [`propagate`](Error::propagate) for more information.
-    #[must_use]
-    pub unsafe fn ptr_or_propagate<T: CloneToForeign>(
-        result: Result<T>,
-        errp: *mut *mut bindings::Error,
-    ) -> *mut T::Foreign {
-        // SAFETY: caller guarantees errp is valid
-        unsafe { Self::ok_or_propagate(result, errp) }.clone_to_foreign_ptr()
-    }
-
-    /// Consume a result in the same way as `self.ok()`, but also propagate
-    /// a possible error into `errp`.  This is similar to the C API
-    /// `error_propagate`, but it panics if `*errp` is not `NULL`.
-    ///
-    /// # Safety
-    ///
-    /// `errp` must be a valid argument to `error_propagate`;
-    /// typically it is received from C code and need not be
-    /// checked further at the Rust↔C boundary.
-    ///
-    /// See [`propagate`](Error::propagate) for more information.
-    pub unsafe fn ok_or_propagate<T>(
-        result: Result<T>,
-        errp: *mut *mut bindings::Error,
-    ) -> Option<T> {
-        result.map_err(|err| unsafe { err.propagate(errp) }).ok()
-    }
-
-    /// Equivalent of the C function `error_propagate`.  Fill `*errp`
-    /// with the information container in `self` if `errp` is not NULL;
-    /// then consume it.
-    ///
-    /// This is similar to the C API `error_propagate`, but it panics if
-    /// `*errp` is not `NULL`.
-    ///
-    /// # Safety
-    ///
-    /// `errp` must be a valid argument to `error_propagate`; it can be
-    /// `NULL` or it can point to any of:
-    /// * `error_abort`
-    /// * `error_fatal`
-    /// * a local variable of (C) type `Error *`
-    ///
-    /// Typically `errp` is received from C code and need not be
-    /// checked further at the Rust↔C boundary.
-    pub unsafe fn propagate(self, errp: *mut *mut bindings::Error) {
-        if errp.is_null() {
-            return;
-        }
-
-        // SAFETY: caller guarantees that errp and *errp are valid
-        unsafe {
-            assert_eq!(*errp, ptr::null_mut());
-            bindings::error_propagate(errp, self.clone_to_foreign_ptr());
-        }
-    }
-
-    /// Convert a C `Error*` into a Rust `Result`, using
-    /// `Ok(())` if `c_error` is NULL.  Free the `Error*`.
-    ///
-    /// # 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, 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),
-        }
-    }
-}
-
-impl FreeForeign for Error {
-    type Foreign = bindings::Error;
-
-    unsafe fn free_foreign(p: *mut bindings::Error) {
-        // SAFETY: caller guarantees p is valid
-        unsafe {
-            bindings::error_free(p);
-        }
-    }
-}
-
-impl CloneToForeign for Error {
-    fn clone_to_foreign(&self) -> OwnedPointer<Self> {
-        // SAFETY: all arguments are controlled by this function
-        unsafe {
-            let err: *mut c_void = libc::malloc(std::mem::size_of::<bindings::Error>());
-            let err: &mut bindings::Error = &mut *err.cast();
-            *err = bindings::Error {
-                msg: format!("{self}").clone_to_foreign_ptr(),
-                err_class: bindings::ERROR_CLASS_GENERIC_ERROR,
-                src_len: self.file.len() as c_int,
-                src: self.file.as_ptr().cast::<c_char>(),
-                line: self.line as c_int,
-                func: ptr::null_mut(),
-                hint: ptr::null_mut(),
-            };
-            OwnedPointer::new(err)
-        }
-    }
-}
-
-impl FromForeign for Error {
-    unsafe fn cloned_from_foreign(c_error: *const bindings::Error) -> Self {
-        // SAFETY: caller guarantees c_error is valid
-        unsafe {
-            let error = &*c_error;
-            let file = if error.src_len < 0 {
-                // NUL-terminated
-                CStr::from_ptr(error.src).to_str()
-            } else {
-                // Can become str::from_utf8 with Rust 1.87.0
-                std::str::from_utf8(std::slice::from_raw_parts(
-                    &*error.src.cast::<u8>(),
-                    error.src_len as usize,
-                ))
-            };
-
-            Error {
-                msg: FromForeign::cloned_from_foreign(error.msg),
-                cause: None,
-                file: file.unwrap(),
-                line: error.line as u32,
-            }
-        }
-    }
-}
-
-#[cfg(test)]
-mod tests {
-    use std::ffi::CStr;
-
-    use anyhow::anyhow;
-    use foreign::OwnedPointer;
-
-    use super::*;
-    use crate::{assert_match, bindings};
-
-    #[track_caller]
-    fn error_for_test(msg: &CStr) -> OwnedPointer<Error> {
-        // SAFETY: all arguments are controlled by this function
-        let location = panic::Location::caller();
-        unsafe {
-            let err: *mut c_void = libc::malloc(std::mem::size_of::<bindings::Error>());
-            let err: &mut bindings::Error = &mut *err.cast();
-            *err = bindings::Error {
-                msg: msg.clone_to_foreign_ptr(),
-                err_class: bindings::ERROR_CLASS_GENERIC_ERROR,
-                src_len: location.file().len() as c_int,
-                src: location.file().as_ptr().cast::<c_char>(),
-                line: location.line() as c_int,
-                func: ptr::null_mut(),
-                hint: ptr::null_mut(),
-            };
-            OwnedPointer::new(err)
-        }
-    }
-
-    unsafe fn error_get_pretty<'a>(local_err: *mut bindings::Error) -> &'a CStr {
-        unsafe { CStr::from_ptr(bindings::error_get_pretty(local_err)) }
-    }
-
-    #[test]
-    #[allow(deprecated)]
-    fn test_description() {
-        use std::error::Error;
-
-        assert_eq!(super::Error::from("msg").description(), "msg");
-        assert_eq!(super::Error::from("msg".to_owned()).description(), "msg");
-    }
-
-    #[test]
-    fn test_display() {
-        assert_eq!(&*format!("{}", Error::from("msg")), "msg");
-        assert_eq!(&*format!("{}", Error::from("msg".to_owned())), "msg");
-        assert_eq!(&*format!("{}", Error::from(anyhow!("msg"))), "msg");
-
-        assert_eq!(
-            &*format!("{}", Error::with_error("msg", anyhow!("cause"))),
-            "msg: cause"
-        );
-    }
-
-    #[test]
-    fn test_bool_or_propagate() {
-        unsafe {
-            let mut local_err: *mut bindings::Error = ptr::null_mut();
-
-            assert!(Error::bool_or_propagate(Ok(()), &mut local_err));
-            assert_eq!(local_err, ptr::null_mut());
-
-            let my_err = Error::from("msg");
-            assert!(!Error::bool_or_propagate(Err(my_err), &mut local_err));
-            assert_ne!(local_err, ptr::null_mut());
-            assert_eq!(error_get_pretty(local_err), c"msg");
-            bindings::error_free(local_err);
-        }
-    }
-
-    #[test]
-    fn test_ptr_or_propagate() {
-        unsafe {
-            let mut local_err: *mut bindings::Error = ptr::null_mut();
-
-            let ret = Error::ptr_or_propagate(Ok("abc".to_owned()), &mut local_err);
-            assert_eq!(String::from_foreign(ret), "abc");
-            assert_eq!(local_err, ptr::null_mut());
-
-            let my_err = Error::from("msg");
-            assert_eq!(
-                Error::ptr_or_propagate(Err::<String, _>(my_err), &mut local_err),
-                ptr::null_mut()
-            );
-            assert_ne!(local_err, ptr::null_mut());
-            assert_eq!(error_get_pretty(local_err), c"msg");
-            bindings::error_free(local_err);
-        }
-    }
-
-    #[test]
-    fn test_err_or_unit() {
-        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();
-            assert_eq!(&*format!("{err}"), "msg");
-        }
-    }
-}