#![cfg(windows)]
use crate::{Cvt, NtCvt, Sealed, WsaCvt};
use std::{
io::{Error, Result},
os::{
raw::{c_int, c_long, c_uchar},
windows::raw::HANDLE,
},
};
macro_rules! impl_for_bool {
($(#[$doc:meta] $T:ty)+) => {
$(
impl Sealed for $T {
type Output = ();
}
#[$doc]
impl Cvt for $T {
#[inline(always)]
fn cvt(self) -> Result<Self::Output> {
if self == 0 {
Err(Error::last_os_error())
} else {
Ok(())
}
}
}
)+
};
}
impl_for_bool! {
c_int
c_uchar
}
impl Sealed for HANDLE {
type Output = Self;
}
impl Cvt for HANDLE {
#[inline(always)]
fn cvt(self) -> Result<Self::Output> {
if self.is_null() || self as isize == -1 {
Err(Error::last_os_error())
} else {
Ok(self)
}
}
}
#[link(kind = "dylib", name = "ntdll")]
extern "system" {
fn RtlNtStatusToDosError(status: i32) -> u32;
}
#[inline(always)]
fn nt_status_to_error(status: i32) -> Error {
#[allow(clippy::cast_possible_wrap)]
Error::from_raw_os_error(unsafe { RtlNtStatusToDosError(status) } as _)
}
impl NtCvt for c_long {
#[inline(always)]
fn nt_cvt(self) -> Result<Self::Output> {
if self >= 0 {
Ok(())
} else {
Err(nt_status_to_error(self))
}
}
}
extern "system" {
fn WSAGetLastError() -> c_int;
}
#[inline(always)]
fn wsa_last_error() -> Error {
Error::from_raw_os_error(unsafe { WSAGetLastError() })
}
impl WsaCvt for c_int {
#[inline(always)]
fn wsa_cvt(self) -> Result<Self::Output> {
if self == -1 {
Err(wsa_last_error())
} else {
Ok(())
}
}
}
impl Sealed for usize {
type Output = Self;
}
impl WsaCvt for usize {
#[inline(always)]
fn wsa_cvt(self) -> Result<Self::Output> {
if self == !0 {
Err(wsa_last_error())
} else {
Ok(self)
}
}
}
impl WsaCvt for HANDLE {
#[inline(always)]
fn wsa_cvt(self) -> Result<Self::Output> {
if self.is_null() || self as isize == -1 {
Err(wsa_last_error())
} else {
Ok(self)
}
}
}
#[cfg(test)]
mod tests {
use crate::{Cvt, NtCvt, WsaCvt};
use std::{
ffi::c_void,
io::{Error, ErrorKind},
os::{
raw::{c_int, c_uchar},
windows::raw::HANDLE,
},
ptr::null_mut,
};
#[test]
fn cvt() {
c_int::MAX.cvt().unwrap();
c_uchar::MAX.cvt().unwrap();
assert_eq!((1 as HANDLE).cvt().unwrap(), 1 as _);
let code = Error::last_os_error().raw_os_error().unwrap();
assert_eq!(
c_int::default().cvt().unwrap_err().raw_os_error().unwrap(),
code
);
assert_eq!(
c_uchar::default()
.cvt()
.unwrap_err()
.raw_os_error()
.unwrap(),
code
);
assert_eq!(
null_mut::<c_void>()
.cvt()
.unwrap_err()
.raw_os_error()
.unwrap(),
code
);
assert_eq!(
(-1_isize as HANDLE)
.cvt()
.unwrap_err()
.raw_os_error()
.unwrap(),
code
);
}
#[allow(overflowing_literals)]
const STATUS_INVALID_PARAMETER: i32 = 0xC000_000D;
#[test]
fn nt_status_to_error() {
assert_eq!(
super::nt_status_to_error(STATUS_INVALID_PARAMETER).kind(),
ErrorKind::InvalidInput
);
}
#[test]
fn nt_cvt() {
i32::MAX.nt_cvt().unwrap();
0.nt_cvt().unwrap();
(-1).nt_cvt().unwrap_err();
assert_eq!(
STATUS_INVALID_PARAMETER.nt_cvt().unwrap_err().kind(),
ErrorKind::InvalidInput
);
}
extern "system" {
fn WSASetLastError(code: c_int);
}
#[test]
fn wsa_last_error() {
unsafe {
WSASetLastError(-1);
}
assert_eq!(super::wsa_last_error().raw_os_error().unwrap(), -1);
}
#[test]
fn wsa_cvt() {
0.wsa_cvt().unwrap();
assert_eq!(0_usize.wsa_cvt().unwrap(), 0);
assert_eq!((1 as HANDLE).wsa_cvt().unwrap(), 1 as _);
let code = Error::last_os_error().raw_os_error().unwrap();
assert_eq!((-1).wsa_cvt().unwrap_err().raw_os_error().unwrap(), code);
assert_eq!(
(!0_usize).wsa_cvt().unwrap_err().raw_os_error().unwrap(),
code
);
assert_eq!(
null_mut::<c_void>()
.wsa_cvt()
.unwrap_err()
.raw_os_error()
.unwrap(),
code
);
assert_eq!(
(-1_isize as HANDLE)
.cvt()
.unwrap_err()
.raw_os_error()
.unwrap(),
code
);
}
}