#[cfg(feature = "std")]
use std::os::fd::AsRawFd;
#[cfg(feature = "std")]
use std::{io, mem};
#[cfg(feature = "std")]
use crate::{AsUninitBytes, Iovec, IovecMut};
#[repr(transparent)]
#[cfg_attr(feature = "nightly", rustc_layout_scalar_valid_range_start(0x0000_0000))]
#[cfg_attr(feature = "nightly", rustc_layout_scalar_valid_range_end(0x7fff_ffff))]
#[cfg_attr(feature = "nightly", rustc_nonnull_optimization_guaranteed)]
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
pub struct Fd(i32);
#[cold]
#[inline]
const fn badf() -> Option<Fd> {
None
}
impl Fd {
pub const fn new(fd: i32) -> Option<Self> {
if fd < 0 {
return badf();
}
#[allow(unused_unsafe)]
Some(unsafe { Self(fd) })
}
#[inline(always)]
pub const unsafe fn new_unchecked(fd: i32) -> Self {
Self(fd)
}
#[inline(always)]
pub fn get(self) -> i32 {
self.0
}
}
impl From<Fd> for i32 {
#[inline(always)]
fn from(value: Fd) -> Self {
value.0
}
}
#[cfg(feature = "std")]
impl AsRawFd for Fd {
fn as_raw_fd(&self) -> i32 {
self.0
}
}
#[cfg(feature = "std")]
impl io::Write for Fd {
#[inline]
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
Fd::write(*self, buf).map_err(Into::into)
}
#[inline]
fn write_vectored(&mut self, bufs: &[io::IoSlice]) -> io::Result<usize> {
self
.writev(unsafe { mem::transmute::<&[io::IoSlice], &[Iovec]>(bufs) })
.map_err(Into::into)
}
#[cfg(feature = "nightly")]
#[inline(always)]
fn is_write_vectored(&self) -> bool {
true
}
#[inline(always)]
fn flush(&mut self) -> io::Result<()> {
Ok(())
}
}
#[cfg(feature = "std")]
impl io::Read for Fd {
#[inline]
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
Fd::read(*self, buf.as_uninit_bytes_mut()).map_err(Into::into)
}
#[inline]
fn read_vectored(&mut self, bufs: &mut [io::IoSliceMut]) -> io::Result<usize> {
self
.readv(unsafe { mem::transmute::<&mut [io::IoSliceMut], &mut [IovecMut]>(bufs) })
.map_err(Into::into)
}
#[cfg(feature = "nightly")]
#[inline(always)]
fn is_read_vectored(&self) -> bool {
true
}
}
pub trait AsFd {
fn as_fd(&self) -> Fd;
}
#[cold]
#[track_caller]
#[inline(never)]
fn panic_badf() -> ! {
panic!("bad file descriptor");
}
#[cfg(feature = "std")]
impl<T: AsRawFd> AsFd for T {
#[inline]
fn as_fd(&self) -> Fd {
let fd = self.as_raw_fd();
if fd < 0 {
panic_badf();
}
#[allow(unused_unsafe)]
unsafe {
Fd(fd)
}
}
}
#[cfg(not(feature = "std"))]
impl AsFd for i32 {
#[inline]
fn as_fd(&self) -> Fd {
if *self < 0 {
panic_badf();
}
#[allow(unused_unsafe)]
unsafe {
Fd(*self)
}
}
}