aboutsummaryrefslogtreecommitdiff
path: root/rust/qemu-api/src/errno.rs
diff options
context:
space:
mode:
Diffstat (limited to 'rust/qemu-api/src/errno.rs')
-rw-r--r--rust/qemu-api/src/errno.rs345
1 files changed, 0 insertions, 345 deletions
diff --git a/rust/qemu-api/src/errno.rs b/rust/qemu-api/src/errno.rs
deleted file mode 100644
index 18d1014..0000000
--- a/rust/qemu-api/src/errno.rs
+++ /dev/null
@@ -1,345 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-or-later
-
-//! Utility functions to convert `errno` to and from
-//! [`io::Error`]/[`io::Result`]
-//!
-//! QEMU C functions often have a "positive success/negative `errno`" calling
-//! convention. This module provides functions to portably convert an integer
-//! into an [`io::Result`] and back.
-
-use std::{convert::TryFrom, io, io::ErrorKind};
-
-/// An `errno` value that can be converted into an [`io::Error`]
-pub struct Errno(pub u16);
-
-// On Unix, from_raw_os_error takes an errno value and OS errors
-// are printed using strerror. On Windows however it takes a
-// GetLastError() value; therefore we need to convert errno values
-// into io::Error by hand. This is the same mapping that the
-// standard library uses to retrieve the kind of OS errors
-// (`std::sys::pal::unix::decode_error_kind`).
-impl From<Errno> for ErrorKind {
- fn from(value: Errno) -> ErrorKind {
- use ErrorKind::*;
- let Errno(errno) = value;
- match i32::from(errno) {
- libc::EPERM | libc::EACCES => PermissionDenied,
- libc::ENOENT => NotFound,
- libc::EINTR => Interrupted,
- x if x == libc::EAGAIN || x == libc::EWOULDBLOCK => WouldBlock,
- libc::ENOMEM => OutOfMemory,
- libc::EEXIST => AlreadyExists,
- libc::EINVAL => InvalidInput,
- libc::EPIPE => BrokenPipe,
- libc::EADDRINUSE => AddrInUse,
- libc::EADDRNOTAVAIL => AddrNotAvailable,
- libc::ECONNABORTED => ConnectionAborted,
- libc::ECONNREFUSED => ConnectionRefused,
- libc::ECONNRESET => ConnectionReset,
- libc::ENOTCONN => NotConnected,
- libc::ENOTSUP => Unsupported,
- libc::ETIMEDOUT => TimedOut,
- _ => Other,
- }
- }
-}
-
-// This is used on Windows for all io::Errors, but also on Unix if the
-// io::Error does not have a raw OS error. This is the reversed
-// mapping of the above; EIO is returned for unknown ErrorKinds.
-impl From<io::ErrorKind> for Errno {
- fn from(value: io::ErrorKind) -> Errno {
- use ErrorKind::*;
- let errno = match value {
- // can be both EPERM or EACCES :( pick one
- PermissionDenied => libc::EPERM,
- NotFound => libc::ENOENT,
- Interrupted => libc::EINTR,
- WouldBlock => libc::EAGAIN,
- OutOfMemory => libc::ENOMEM,
- AlreadyExists => libc::EEXIST,
- InvalidInput => libc::EINVAL,
- BrokenPipe => libc::EPIPE,
- AddrInUse => libc::EADDRINUSE,
- AddrNotAvailable => libc::EADDRNOTAVAIL,
- ConnectionAborted => libc::ECONNABORTED,
- ConnectionRefused => libc::ECONNREFUSED,
- ConnectionReset => libc::ECONNRESET,
- NotConnected => libc::ENOTCONN,
- Unsupported => libc::ENOTSUP,
- TimedOut => libc::ETIMEDOUT,
- _ => libc::EIO,
- };
- Errno(errno as u16)
- }
-}
-
-impl From<Errno> for io::Error {
- #[cfg(unix)]
- fn from(value: Errno) -> io::Error {
- let Errno(errno) = value;
- io::Error::from_raw_os_error(errno.into())
- }
-
- #[cfg(windows)]
- fn from(value: Errno) -> io::Error {
- let error_kind: ErrorKind = value.into();
- error_kind.into()
- }
-}
-
-impl From<io::Error> for Errno {
- fn from(value: io::Error) -> Errno {
- if cfg!(unix) {
- if let Some(errno) = value.raw_os_error() {
- return Errno(u16::try_from(errno).unwrap());
- }
- }
- value.kind().into()
- }
-}
-
-/// Internal traits; used to enable [`into_io_result`] and [`into_neg_errno`]
-/// for the "right" set of types.
-mod traits {
- use super::Errno;
-
- /// A signed type that can be converted into an
- /// [`io::Result`](std::io::Result)
- pub trait GetErrno {
- /// Unsigned variant of `Self`, used as the type for the `Ok` case.
- type Out;
-
- /// Return `Ok(self)` if positive, `Err(Errno(-self))` if negative
- fn into_errno_result(self) -> Result<Self::Out, Errno>;
- }
-
- /// A type that can be taken out of an [`io::Result`](std::io::Result) and
- /// converted into "positive success/negative `errno`" convention.
- pub trait MergeErrno {
- /// Signed variant of `Self`, used as the return type of
- /// [`into_neg_errno`](super::into_neg_errno).
- type Out: From<u16> + std::ops::Neg<Output = Self::Out>;
-
- /// Return `self`, asserting that it is in range
- fn map_ok(self) -> Self::Out;
- }
-
- macro_rules! get_errno {
- ($t:ty, $out:ty) => {
- impl GetErrno for $t {
- type Out = $out;
- fn into_errno_result(self) -> Result<Self::Out, Errno> {
- match self {
- 0.. => Ok(self as $out),
- -65535..=-1 => Err(Errno(-self as u16)),
- _ => panic!("{self} is not a negative errno"),
- }
- }
- }
- };
- }
-
- get_errno!(i32, u32);
- get_errno!(i64, u64);
- get_errno!(isize, usize);
-
- macro_rules! merge_errno {
- ($t:ty, $out:ty) => {
- impl MergeErrno for $t {
- type Out = $out;
- fn map_ok(self) -> Self::Out {
- self.try_into().unwrap()
- }
- }
- };
- }
-
- merge_errno!(u8, i32);
- merge_errno!(u16, i32);
- merge_errno!(u32, i32);
- merge_errno!(u64, i64);
-
- impl MergeErrno for () {
- type Out = i32;
- fn map_ok(self) -> i32 {
- 0
- }
- }
-}
-
-use traits::{GetErrno, MergeErrno};
-
-/// Convert an integer value into a [`io::Result`].
-///
-/// Positive values are turned into an `Ok` result; negative values
-/// are interpreted as negated `errno` and turned into an `Err`.
-///
-/// ```
-/// # use qemu_api::errno::into_io_result;
-/// # use std::io::ErrorKind;
-/// let ok = into_io_result(1i32).unwrap();
-/// assert_eq!(ok, 1u32);
-///
-/// let err = into_io_result(-1i32).unwrap_err(); // -EPERM
-/// assert_eq!(err.kind(), ErrorKind::PermissionDenied);
-/// ```
-///
-/// # Panics
-///
-/// Since the result is an unsigned integer, negative values must
-/// be close to 0; values that are too far away are considered
-/// likely overflows and will panic:
-///
-/// ```should_panic
-/// # use qemu_api::errno::into_io_result;
-/// # #[allow(dead_code)]
-/// let err = into_io_result(-0x1234_5678i32); // panic
-/// ```
-pub fn into_io_result<T: GetErrno>(value: T) -> io::Result<T::Out> {
- value.into_errno_result().map_err(Into::into)
-}
-
-/// Convert a [`Result`] into an integer value, using negative `errno`
-/// values to report errors.
-///
-/// ```
-/// # use qemu_api::errno::into_neg_errno;
-/// # use std::io::{self, ErrorKind};
-/// let ok: io::Result<()> = Ok(());
-/// assert_eq!(into_neg_errno(ok), 0);
-///
-/// let err: io::Result<()> = Err(ErrorKind::InvalidInput.into());
-/// assert_eq!(into_neg_errno(err), -22); // -EINVAL
-/// ```
-///
-/// Since this module also provides the ability to convert [`io::Error`]
-/// to an `errno` value, [`io::Result`] is the most commonly used type
-/// for the argument of this function:
-///
-/// # Panics
-///
-/// Since the result is a signed integer, integer `Ok` values must remain
-/// positive:
-///
-/// ```should_panic
-/// # use qemu_api::errno::into_neg_errno;
-/// # use std::io;
-/// let err: io::Result<u32> = Ok(0x8899_AABB);
-/// into_neg_errno(err) // panic
-/// # ;
-/// ```
-pub fn into_neg_errno<T: MergeErrno, E: Into<Errno>>(value: Result<T, E>) -> T::Out {
- match value {
- Ok(x) => x.map_ok(),
- Err(err) => -T::Out::from(err.into().0),
- }
-}
-
-#[cfg(test)]
-mod tests {
- use std::io::ErrorKind;
-
- use super::*;
- use crate::assert_match;
-
- #[test]
- pub fn test_from_u8() {
- let ok: io::Result<_> = Ok(42u8);
- assert_eq!(into_neg_errno(ok), 42);
-
- let err: io::Result<u8> = Err(io::ErrorKind::PermissionDenied.into());
- assert_eq!(into_neg_errno(err), -1);
-
- if cfg!(unix) {
- let os_err: io::Result<u8> = Err(io::Error::from_raw_os_error(10));
- assert_eq!(into_neg_errno(os_err), -10);
- }
- }
-
- #[test]
- pub fn test_from_u16() {
- let ok: io::Result<_> = Ok(1234u16);
- assert_eq!(into_neg_errno(ok), 1234);
-
- let err: io::Result<u16> = Err(io::ErrorKind::PermissionDenied.into());
- assert_eq!(into_neg_errno(err), -1);
-
- if cfg!(unix) {
- let os_err: io::Result<u16> = Err(io::Error::from_raw_os_error(10));
- assert_eq!(into_neg_errno(os_err), -10);
- }
- }
-
- #[test]
- pub fn test_i32() {
- assert_match!(into_io_result(1234i32), Ok(1234));
-
- let err = into_io_result(-1i32).unwrap_err();
- #[cfg(unix)]
- assert_match!(err.raw_os_error(), Some(1));
- assert_match!(err.kind(), ErrorKind::PermissionDenied);
- }
-
- #[test]
- pub fn test_from_u32() {
- let ok: io::Result<_> = Ok(1234u32);
- assert_eq!(into_neg_errno(ok), 1234);
-
- let err: io::Result<u32> = Err(io::ErrorKind::PermissionDenied.into());
- assert_eq!(into_neg_errno(err), -1);
-
- if cfg!(unix) {
- let os_err: io::Result<u32> = Err(io::Error::from_raw_os_error(10));
- assert_eq!(into_neg_errno(os_err), -10);
- }
- }
-
- #[test]
- pub fn test_i64() {
- assert_match!(into_io_result(1234i64), Ok(1234));
-
- let err = into_io_result(-22i64).unwrap_err();
- #[cfg(unix)]
- assert_match!(err.raw_os_error(), Some(22));
- assert_match!(err.kind(), ErrorKind::InvalidInput);
- }
-
- #[test]
- pub fn test_from_u64() {
- let ok: io::Result<_> = Ok(1234u64);
- assert_eq!(into_neg_errno(ok), 1234);
-
- let err: io::Result<u64> = Err(io::ErrorKind::InvalidInput.into());
- assert_eq!(into_neg_errno(err), -22);
-
- if cfg!(unix) {
- let os_err: io::Result<u64> = Err(io::Error::from_raw_os_error(6));
- assert_eq!(into_neg_errno(os_err), -6);
- }
- }
-
- #[test]
- pub fn test_isize() {
- assert_match!(into_io_result(1234isize), Ok(1234));
-
- let err = into_io_result(-4isize).unwrap_err();
- #[cfg(unix)]
- assert_match!(err.raw_os_error(), Some(4));
- assert_match!(err.kind(), ErrorKind::Interrupted);
- }
-
- #[test]
- pub fn test_from_unit() {
- let ok: io::Result<_> = Ok(());
- assert_eq!(into_neg_errno(ok), 0);
-
- let err: io::Result<()> = Err(io::ErrorKind::OutOfMemory.into());
- assert_eq!(into_neg_errno(err), -12);
-
- if cfg!(unix) {
- let os_err: io::Result<()> = Err(io::Error::from_raw_os_error(2));
- assert_eq!(into_neg_errno(os_err), -2);
- }
- }
-}