1*8a420dd1SPaolo Bonzini // SPDX-License-Identifier: GPL-2.0-or-later 2*8a420dd1SPaolo Bonzini 3*8a420dd1SPaolo Bonzini //! Utility functions to convert `errno` to and from 4*8a420dd1SPaolo Bonzini //! [`io::Error`]/[`io::Result`] 5*8a420dd1SPaolo Bonzini //! 6*8a420dd1SPaolo Bonzini //! QEMU C functions often have a "positive success/negative `errno`" calling 7*8a420dd1SPaolo Bonzini //! convention. This module provides functions to portably convert an integer 8*8a420dd1SPaolo Bonzini //! into an [`io::Result`] and back. 9*8a420dd1SPaolo Bonzini 10*8a420dd1SPaolo Bonzini use std::{convert::TryFrom, io, io::ErrorKind}; 11*8a420dd1SPaolo Bonzini 12*8a420dd1SPaolo Bonzini /// An `errno` value that can be converted into an [`io::Error`] 13*8a420dd1SPaolo Bonzini pub struct Errno(pub u16); 14*8a420dd1SPaolo Bonzini 15*8a420dd1SPaolo Bonzini // On Unix, from_raw_os_error takes an errno value and OS errors 16*8a420dd1SPaolo Bonzini // are printed using strerror. On Windows however it takes a 17*8a420dd1SPaolo Bonzini // GetLastError() value; therefore we need to convert errno values 18*8a420dd1SPaolo Bonzini // into io::Error by hand. This is the same mapping that the 19*8a420dd1SPaolo Bonzini // standard library uses to retrieve the kind of OS errors 20*8a420dd1SPaolo Bonzini // (`std::sys::pal::unix::decode_error_kind`). 21*8a420dd1SPaolo Bonzini impl From<Errno> for ErrorKind { 22*8a420dd1SPaolo Bonzini fn from(value: Errno) -> ErrorKind { 23*8a420dd1SPaolo Bonzini use ErrorKind::*; 24*8a420dd1SPaolo Bonzini let Errno(errno) = value; 25*8a420dd1SPaolo Bonzini match i32::from(errno) { 26*8a420dd1SPaolo Bonzini libc::EPERM | libc::EACCES => PermissionDenied, 27*8a420dd1SPaolo Bonzini libc::ENOENT => NotFound, 28*8a420dd1SPaolo Bonzini libc::EINTR => Interrupted, 29*8a420dd1SPaolo Bonzini x if x == libc::EAGAIN || x == libc::EWOULDBLOCK => WouldBlock, 30*8a420dd1SPaolo Bonzini libc::ENOMEM => OutOfMemory, 31*8a420dd1SPaolo Bonzini libc::EEXIST => AlreadyExists, 32*8a420dd1SPaolo Bonzini libc::EINVAL => InvalidInput, 33*8a420dd1SPaolo Bonzini libc::EPIPE => BrokenPipe, 34*8a420dd1SPaolo Bonzini libc::EADDRINUSE => AddrInUse, 35*8a420dd1SPaolo Bonzini libc::EADDRNOTAVAIL => AddrNotAvailable, 36*8a420dd1SPaolo Bonzini libc::ECONNABORTED => ConnectionAborted, 37*8a420dd1SPaolo Bonzini libc::ECONNREFUSED => ConnectionRefused, 38*8a420dd1SPaolo Bonzini libc::ECONNRESET => ConnectionReset, 39*8a420dd1SPaolo Bonzini libc::ENOTCONN => NotConnected, 40*8a420dd1SPaolo Bonzini libc::ENOTSUP => Unsupported, 41*8a420dd1SPaolo Bonzini libc::ETIMEDOUT => TimedOut, 42*8a420dd1SPaolo Bonzini _ => Other, 43*8a420dd1SPaolo Bonzini } 44*8a420dd1SPaolo Bonzini } 45*8a420dd1SPaolo Bonzini } 46*8a420dd1SPaolo Bonzini 47*8a420dd1SPaolo Bonzini // This is used on Windows for all io::Errors, but also on Unix if the 48*8a420dd1SPaolo Bonzini // io::Error does not have a raw OS error. This is the reversed 49*8a420dd1SPaolo Bonzini // mapping of the above; EIO is returned for unknown ErrorKinds. 50*8a420dd1SPaolo Bonzini impl From<io::ErrorKind> for Errno { 51*8a420dd1SPaolo Bonzini fn from(value: io::ErrorKind) -> Errno { 52*8a420dd1SPaolo Bonzini use ErrorKind::*; 53*8a420dd1SPaolo Bonzini let errno = match value { 54*8a420dd1SPaolo Bonzini // can be both EPERM or EACCES :( pick one 55*8a420dd1SPaolo Bonzini PermissionDenied => libc::EPERM, 56*8a420dd1SPaolo Bonzini NotFound => libc::ENOENT, 57*8a420dd1SPaolo Bonzini Interrupted => libc::EINTR, 58*8a420dd1SPaolo Bonzini WouldBlock => libc::EAGAIN, 59*8a420dd1SPaolo Bonzini OutOfMemory => libc::ENOMEM, 60*8a420dd1SPaolo Bonzini AlreadyExists => libc::EEXIST, 61*8a420dd1SPaolo Bonzini InvalidInput => libc::EINVAL, 62*8a420dd1SPaolo Bonzini BrokenPipe => libc::EPIPE, 63*8a420dd1SPaolo Bonzini AddrInUse => libc::EADDRINUSE, 64*8a420dd1SPaolo Bonzini AddrNotAvailable => libc::EADDRNOTAVAIL, 65*8a420dd1SPaolo Bonzini ConnectionAborted => libc::ECONNABORTED, 66*8a420dd1SPaolo Bonzini ConnectionRefused => libc::ECONNREFUSED, 67*8a420dd1SPaolo Bonzini ConnectionReset => libc::ECONNRESET, 68*8a420dd1SPaolo Bonzini NotConnected => libc::ENOTCONN, 69*8a420dd1SPaolo Bonzini Unsupported => libc::ENOTSUP, 70*8a420dd1SPaolo Bonzini TimedOut => libc::ETIMEDOUT, 71*8a420dd1SPaolo Bonzini _ => libc::EIO, 72*8a420dd1SPaolo Bonzini }; 73*8a420dd1SPaolo Bonzini Errno(errno as u16) 74*8a420dd1SPaolo Bonzini } 75*8a420dd1SPaolo Bonzini } 76*8a420dd1SPaolo Bonzini 77*8a420dd1SPaolo Bonzini impl From<Errno> for io::Error { 78*8a420dd1SPaolo Bonzini #[cfg(unix)] 79*8a420dd1SPaolo Bonzini fn from(value: Errno) -> io::Error { 80*8a420dd1SPaolo Bonzini let Errno(errno) = value; 81*8a420dd1SPaolo Bonzini io::Error::from_raw_os_error(errno.into()) 82*8a420dd1SPaolo Bonzini } 83*8a420dd1SPaolo Bonzini 84*8a420dd1SPaolo Bonzini #[cfg(windows)] 85*8a420dd1SPaolo Bonzini fn from(value: Errno) -> io::Error { 86*8a420dd1SPaolo Bonzini let error_kind: ErrorKind = value.into(); 87*8a420dd1SPaolo Bonzini error_kind.into() 88*8a420dd1SPaolo Bonzini } 89*8a420dd1SPaolo Bonzini } 90*8a420dd1SPaolo Bonzini 91*8a420dd1SPaolo Bonzini impl From<io::Error> for Errno { 92*8a420dd1SPaolo Bonzini fn from(value: io::Error) -> Errno { 93*8a420dd1SPaolo Bonzini if cfg!(unix) { 94*8a420dd1SPaolo Bonzini if let Some(errno) = value.raw_os_error() { 95*8a420dd1SPaolo Bonzini return Errno(u16::try_from(errno).unwrap()); 96*8a420dd1SPaolo Bonzini } 97*8a420dd1SPaolo Bonzini } 98*8a420dd1SPaolo Bonzini value.kind().into() 99*8a420dd1SPaolo Bonzini } 100*8a420dd1SPaolo Bonzini } 101*8a420dd1SPaolo Bonzini 102*8a420dd1SPaolo Bonzini /// Internal traits; used to enable [`into_io_result`] and [`into_neg_errno`] 103*8a420dd1SPaolo Bonzini /// for the "right" set of types. 104*8a420dd1SPaolo Bonzini mod traits { 105*8a420dd1SPaolo Bonzini use super::Errno; 106*8a420dd1SPaolo Bonzini 107*8a420dd1SPaolo Bonzini /// A signed type that can be converted into an 108*8a420dd1SPaolo Bonzini /// [`io::Result`](std::io::Result) 109*8a420dd1SPaolo Bonzini pub trait GetErrno { 110*8a420dd1SPaolo Bonzini /// Unsigned variant of `Self`, used as the type for the `Ok` case. 111*8a420dd1SPaolo Bonzini type Out; 112*8a420dd1SPaolo Bonzini 113*8a420dd1SPaolo Bonzini /// Return `Ok(self)` if positive, `Err(Errno(-self))` if negative 114*8a420dd1SPaolo Bonzini fn into_errno_result(self) -> Result<Self::Out, Errno>; 115*8a420dd1SPaolo Bonzini } 116*8a420dd1SPaolo Bonzini 117*8a420dd1SPaolo Bonzini /// A type that can be taken out of an [`io::Result`](std::io::Result) and 118*8a420dd1SPaolo Bonzini /// converted into "positive success/negative `errno`" convention. 119*8a420dd1SPaolo Bonzini pub trait MergeErrno { 120*8a420dd1SPaolo Bonzini /// Signed variant of `Self`, used as the return type of 121*8a420dd1SPaolo Bonzini /// [`into_neg_errno`](super::into_neg_errno). 122*8a420dd1SPaolo Bonzini type Out: From<u16> + std::ops::Neg<Output = Self::Out>; 123*8a420dd1SPaolo Bonzini 124*8a420dd1SPaolo Bonzini /// Return `self`, asserting that it is in range 125*8a420dd1SPaolo Bonzini fn map_ok(self) -> Self::Out; 126*8a420dd1SPaolo Bonzini } 127*8a420dd1SPaolo Bonzini 128*8a420dd1SPaolo Bonzini macro_rules! get_errno { 129*8a420dd1SPaolo Bonzini ($t:ty, $out:ty) => { 130*8a420dd1SPaolo Bonzini impl GetErrno for $t { 131*8a420dd1SPaolo Bonzini type Out = $out; 132*8a420dd1SPaolo Bonzini fn into_errno_result(self) -> Result<Self::Out, Errno> { 133*8a420dd1SPaolo Bonzini match self { 134*8a420dd1SPaolo Bonzini 0.. => Ok(self as $out), 135*8a420dd1SPaolo Bonzini -65535..=-1 => Err(Errno(-self as u16)), 136*8a420dd1SPaolo Bonzini _ => panic!("{self} is not a negative errno"), 137*8a420dd1SPaolo Bonzini } 138*8a420dd1SPaolo Bonzini } 139*8a420dd1SPaolo Bonzini } 140*8a420dd1SPaolo Bonzini }; 141*8a420dd1SPaolo Bonzini } 142*8a420dd1SPaolo Bonzini 143*8a420dd1SPaolo Bonzini get_errno!(i32, u32); 144*8a420dd1SPaolo Bonzini get_errno!(i64, u64); 145*8a420dd1SPaolo Bonzini get_errno!(isize, usize); 146*8a420dd1SPaolo Bonzini 147*8a420dd1SPaolo Bonzini macro_rules! merge_errno { 148*8a420dd1SPaolo Bonzini ($t:ty, $out:ty) => { 149*8a420dd1SPaolo Bonzini impl MergeErrno for $t { 150*8a420dd1SPaolo Bonzini type Out = $out; 151*8a420dd1SPaolo Bonzini fn map_ok(self) -> Self::Out { 152*8a420dd1SPaolo Bonzini self.try_into().unwrap() 153*8a420dd1SPaolo Bonzini } 154*8a420dd1SPaolo Bonzini } 155*8a420dd1SPaolo Bonzini }; 156*8a420dd1SPaolo Bonzini } 157*8a420dd1SPaolo Bonzini 158*8a420dd1SPaolo Bonzini merge_errno!(u8, i32); 159*8a420dd1SPaolo Bonzini merge_errno!(u16, i32); 160*8a420dd1SPaolo Bonzini merge_errno!(u32, i32); 161*8a420dd1SPaolo Bonzini merge_errno!(u64, i64); 162*8a420dd1SPaolo Bonzini 163*8a420dd1SPaolo Bonzini impl MergeErrno for () { 164*8a420dd1SPaolo Bonzini type Out = i32; 165*8a420dd1SPaolo Bonzini fn map_ok(self) -> i32 { 166*8a420dd1SPaolo Bonzini 0 167*8a420dd1SPaolo Bonzini } 168*8a420dd1SPaolo Bonzini } 169*8a420dd1SPaolo Bonzini } 170*8a420dd1SPaolo Bonzini 171*8a420dd1SPaolo Bonzini use traits::{GetErrno, MergeErrno}; 172*8a420dd1SPaolo Bonzini 173*8a420dd1SPaolo Bonzini /// Convert an integer value into a [`io::Result`]. 174*8a420dd1SPaolo Bonzini /// 175*8a420dd1SPaolo Bonzini /// Positive values are turned into an `Ok` result; negative values 176*8a420dd1SPaolo Bonzini /// are interpreted as negated `errno` and turned into an `Err`. 177*8a420dd1SPaolo Bonzini /// 178*8a420dd1SPaolo Bonzini /// ``` 179*8a420dd1SPaolo Bonzini /// # use qemu_api::errno::into_io_result; 180*8a420dd1SPaolo Bonzini /// # use std::io::ErrorKind; 181*8a420dd1SPaolo Bonzini /// let ok = into_io_result(1i32).unwrap(); 182*8a420dd1SPaolo Bonzini /// assert_eq!(ok, 1u32); 183*8a420dd1SPaolo Bonzini /// 184*8a420dd1SPaolo Bonzini /// let err = into_io_result(-1i32).unwrap_err(); // -EPERM 185*8a420dd1SPaolo Bonzini /// assert_eq!(err.kind(), ErrorKind::PermissionDenied); 186*8a420dd1SPaolo Bonzini /// ``` 187*8a420dd1SPaolo Bonzini /// 188*8a420dd1SPaolo Bonzini /// # Panics 189*8a420dd1SPaolo Bonzini /// 190*8a420dd1SPaolo Bonzini /// Since the result is an unsigned integer, negative values must 191*8a420dd1SPaolo Bonzini /// be close to 0; values that are too far away are considered 192*8a420dd1SPaolo Bonzini /// likely overflows and will panic: 193*8a420dd1SPaolo Bonzini /// 194*8a420dd1SPaolo Bonzini /// ```should_panic 195*8a420dd1SPaolo Bonzini /// # use qemu_api::errno::into_io_result; 196*8a420dd1SPaolo Bonzini /// # #[allow(dead_code)] 197*8a420dd1SPaolo Bonzini /// let err = into_io_result(-0x1234_5678i32); // panic 198*8a420dd1SPaolo Bonzini /// ``` 199*8a420dd1SPaolo Bonzini pub fn into_io_result<T: GetErrno>(value: T) -> io::Result<T::Out> { 200*8a420dd1SPaolo Bonzini value.into_errno_result().map_err(Into::into) 201*8a420dd1SPaolo Bonzini } 202*8a420dd1SPaolo Bonzini 203*8a420dd1SPaolo Bonzini /// Convert a [`Result`] into an integer value, using negative `errno` 204*8a420dd1SPaolo Bonzini /// values to report errors. 205*8a420dd1SPaolo Bonzini /// 206*8a420dd1SPaolo Bonzini /// ``` 207*8a420dd1SPaolo Bonzini /// # use qemu_api::errno::into_neg_errno; 208*8a420dd1SPaolo Bonzini /// # use std::io::{self, ErrorKind}; 209*8a420dd1SPaolo Bonzini /// let ok: io::Result<()> = Ok(()); 210*8a420dd1SPaolo Bonzini /// assert_eq!(into_neg_errno(ok), 0); 211*8a420dd1SPaolo Bonzini /// 212*8a420dd1SPaolo Bonzini /// let err: io::Result<()> = Err(ErrorKind::InvalidInput.into()); 213*8a420dd1SPaolo Bonzini /// assert_eq!(into_neg_errno(err), -22); // -EINVAL 214*8a420dd1SPaolo Bonzini /// ``` 215*8a420dd1SPaolo Bonzini /// 216*8a420dd1SPaolo Bonzini /// Since this module also provides the ability to convert [`io::Error`] 217*8a420dd1SPaolo Bonzini /// to an `errno` value, [`io::Result`] is the most commonly used type 218*8a420dd1SPaolo Bonzini /// for the argument of this function: 219*8a420dd1SPaolo Bonzini /// 220*8a420dd1SPaolo Bonzini /// # Panics 221*8a420dd1SPaolo Bonzini /// 222*8a420dd1SPaolo Bonzini /// Since the result is a signed integer, integer `Ok` values must remain 223*8a420dd1SPaolo Bonzini /// positive: 224*8a420dd1SPaolo Bonzini /// 225*8a420dd1SPaolo Bonzini /// ```should_panic 226*8a420dd1SPaolo Bonzini /// # use qemu_api::errno::into_neg_errno; 227*8a420dd1SPaolo Bonzini /// # use std::io; 228*8a420dd1SPaolo Bonzini /// let err: io::Result<u32> = Ok(0x8899_AABB); 229*8a420dd1SPaolo Bonzini /// into_neg_errno(err) // panic 230*8a420dd1SPaolo Bonzini /// # ; 231*8a420dd1SPaolo Bonzini /// ``` 232*8a420dd1SPaolo Bonzini pub fn into_neg_errno<T: MergeErrno, E: Into<Errno>>(value: Result<T, E>) -> T::Out { 233*8a420dd1SPaolo Bonzini match value { 234*8a420dd1SPaolo Bonzini Ok(x) => x.map_ok(), 235*8a420dd1SPaolo Bonzini Err(err) => -T::Out::from(err.into().0), 236*8a420dd1SPaolo Bonzini } 237*8a420dd1SPaolo Bonzini } 238*8a420dd1SPaolo Bonzini 239*8a420dd1SPaolo Bonzini #[cfg(test)] 240*8a420dd1SPaolo Bonzini mod tests { 241*8a420dd1SPaolo Bonzini use std::io::ErrorKind; 242*8a420dd1SPaolo Bonzini 243*8a420dd1SPaolo Bonzini use super::*; 244*8a420dd1SPaolo Bonzini use crate::assert_match; 245*8a420dd1SPaolo Bonzini 246*8a420dd1SPaolo Bonzini #[test] 247*8a420dd1SPaolo Bonzini pub fn test_from_u8() { 248*8a420dd1SPaolo Bonzini let ok: io::Result<_> = Ok(42u8); 249*8a420dd1SPaolo Bonzini assert_eq!(into_neg_errno(ok), 42); 250*8a420dd1SPaolo Bonzini 251*8a420dd1SPaolo Bonzini let err: io::Result<u8> = Err(io::ErrorKind::PermissionDenied.into()); 252*8a420dd1SPaolo Bonzini assert_eq!(into_neg_errno(err), -1); 253*8a420dd1SPaolo Bonzini 254*8a420dd1SPaolo Bonzini if cfg!(unix) { 255*8a420dd1SPaolo Bonzini let os_err: io::Result<u8> = Err(io::Error::from_raw_os_error(10)); 256*8a420dd1SPaolo Bonzini assert_eq!(into_neg_errno(os_err), -10); 257*8a420dd1SPaolo Bonzini } 258*8a420dd1SPaolo Bonzini } 259*8a420dd1SPaolo Bonzini 260*8a420dd1SPaolo Bonzini #[test] 261*8a420dd1SPaolo Bonzini pub fn test_from_u16() { 262*8a420dd1SPaolo Bonzini let ok: io::Result<_> = Ok(1234u16); 263*8a420dd1SPaolo Bonzini assert_eq!(into_neg_errno(ok), 1234); 264*8a420dd1SPaolo Bonzini 265*8a420dd1SPaolo Bonzini let err: io::Result<u16> = Err(io::ErrorKind::PermissionDenied.into()); 266*8a420dd1SPaolo Bonzini assert_eq!(into_neg_errno(err), -1); 267*8a420dd1SPaolo Bonzini 268*8a420dd1SPaolo Bonzini if cfg!(unix) { 269*8a420dd1SPaolo Bonzini let os_err: io::Result<u16> = Err(io::Error::from_raw_os_error(10)); 270*8a420dd1SPaolo Bonzini assert_eq!(into_neg_errno(os_err), -10); 271*8a420dd1SPaolo Bonzini } 272*8a420dd1SPaolo Bonzini } 273*8a420dd1SPaolo Bonzini 274*8a420dd1SPaolo Bonzini #[test] 275*8a420dd1SPaolo Bonzini pub fn test_i32() { 276*8a420dd1SPaolo Bonzini assert_match!(into_io_result(1234i32), Ok(1234)); 277*8a420dd1SPaolo Bonzini 278*8a420dd1SPaolo Bonzini let err = into_io_result(-1i32).unwrap_err(); 279*8a420dd1SPaolo Bonzini #[cfg(unix)] 280*8a420dd1SPaolo Bonzini assert_match!(err.raw_os_error(), Some(1)); 281*8a420dd1SPaolo Bonzini assert_match!(err.kind(), ErrorKind::PermissionDenied); 282*8a420dd1SPaolo Bonzini } 283*8a420dd1SPaolo Bonzini 284*8a420dd1SPaolo Bonzini #[test] 285*8a420dd1SPaolo Bonzini pub fn test_from_u32() { 286*8a420dd1SPaolo Bonzini let ok: io::Result<_> = Ok(1234u32); 287*8a420dd1SPaolo Bonzini assert_eq!(into_neg_errno(ok), 1234); 288*8a420dd1SPaolo Bonzini 289*8a420dd1SPaolo Bonzini let err: io::Result<u32> = Err(io::ErrorKind::PermissionDenied.into()); 290*8a420dd1SPaolo Bonzini assert_eq!(into_neg_errno(err), -1); 291*8a420dd1SPaolo Bonzini 292*8a420dd1SPaolo Bonzini if cfg!(unix) { 293*8a420dd1SPaolo Bonzini let os_err: io::Result<u32> = Err(io::Error::from_raw_os_error(10)); 294*8a420dd1SPaolo Bonzini assert_eq!(into_neg_errno(os_err), -10); 295*8a420dd1SPaolo Bonzini } 296*8a420dd1SPaolo Bonzini } 297*8a420dd1SPaolo Bonzini 298*8a420dd1SPaolo Bonzini #[test] 299*8a420dd1SPaolo Bonzini pub fn test_i64() { 300*8a420dd1SPaolo Bonzini assert_match!(into_io_result(1234i64), Ok(1234)); 301*8a420dd1SPaolo Bonzini 302*8a420dd1SPaolo Bonzini let err = into_io_result(-22i64).unwrap_err(); 303*8a420dd1SPaolo Bonzini #[cfg(unix)] 304*8a420dd1SPaolo Bonzini assert_match!(err.raw_os_error(), Some(22)); 305*8a420dd1SPaolo Bonzini assert_match!(err.kind(), ErrorKind::InvalidInput); 306*8a420dd1SPaolo Bonzini } 307*8a420dd1SPaolo Bonzini 308*8a420dd1SPaolo Bonzini #[test] 309*8a420dd1SPaolo Bonzini pub fn test_from_u64() { 310*8a420dd1SPaolo Bonzini let ok: io::Result<_> = Ok(1234u64); 311*8a420dd1SPaolo Bonzini assert_eq!(into_neg_errno(ok), 1234); 312*8a420dd1SPaolo Bonzini 313*8a420dd1SPaolo Bonzini let err: io::Result<u64> = Err(io::ErrorKind::InvalidInput.into()); 314*8a420dd1SPaolo Bonzini assert_eq!(into_neg_errno(err), -22); 315*8a420dd1SPaolo Bonzini 316*8a420dd1SPaolo Bonzini if cfg!(unix) { 317*8a420dd1SPaolo Bonzini let os_err: io::Result<u64> = Err(io::Error::from_raw_os_error(6)); 318*8a420dd1SPaolo Bonzini assert_eq!(into_neg_errno(os_err), -6); 319*8a420dd1SPaolo Bonzini } 320*8a420dd1SPaolo Bonzini } 321*8a420dd1SPaolo Bonzini 322*8a420dd1SPaolo Bonzini #[test] 323*8a420dd1SPaolo Bonzini pub fn test_isize() { 324*8a420dd1SPaolo Bonzini assert_match!(into_io_result(1234isize), Ok(1234)); 325*8a420dd1SPaolo Bonzini 326*8a420dd1SPaolo Bonzini let err = into_io_result(-4isize).unwrap_err(); 327*8a420dd1SPaolo Bonzini #[cfg(unix)] 328*8a420dd1SPaolo Bonzini assert_match!(err.raw_os_error(), Some(4)); 329*8a420dd1SPaolo Bonzini assert_match!(err.kind(), ErrorKind::Interrupted); 330*8a420dd1SPaolo Bonzini } 331*8a420dd1SPaolo Bonzini 332*8a420dd1SPaolo Bonzini #[test] 333*8a420dd1SPaolo Bonzini pub fn test_from_unit() { 334*8a420dd1SPaolo Bonzini let ok: io::Result<_> = Ok(()); 335*8a420dd1SPaolo Bonzini assert_eq!(into_neg_errno(ok), 0); 336*8a420dd1SPaolo Bonzini 337*8a420dd1SPaolo Bonzini let err: io::Result<()> = Err(io::ErrorKind::OutOfMemory.into()); 338*8a420dd1SPaolo Bonzini assert_eq!(into_neg_errno(err), -12); 339*8a420dd1SPaolo Bonzini 340*8a420dd1SPaolo Bonzini if cfg!(unix) { 341*8a420dd1SPaolo Bonzini let os_err: io::Result<()> = Err(io::Error::from_raw_os_error(2)); 342*8a420dd1SPaolo Bonzini assert_eq!(into_neg_errno(os_err), -2); 343*8a420dd1SPaolo Bonzini } 344*8a420dd1SPaolo Bonzini } 345*8a420dd1SPaolo Bonzini } 346