#![allow(clippy::undocumented_unsafe_blocks)]
use core::{ffi::c_int, fmt, marker::PhantomData, mem::ManuallyDrop};
use crate::sys;
pub type RawFd = c_int;
const _: () = {
#[cfg(not(target_pointer_width = "16"))]
assert!(core::mem::size_of::<RawFd>() == core::mem::size_of::<u32>());
#[cfg(target_pointer_width = "16")]
assert!(core::mem::size_of::<RawFd>() == core::mem::size_of::<u16>());
};
#[derive(Clone, Copy)]
#[repr(transparent)]
pub struct BorrowedFd<'fd> {
fd: RawFd,
_phantom: PhantomData<&'fd OwnedFd>,
}
#[repr(transparent)]
pub struct OwnedFd {
fd: RawFd,
}
impl BorrowedFd<'_> {
#[inline]
pub const unsafe fn borrow_raw(fd: RawFd) -> Self {
assert!(fd != -1);
Self { fd, _phantom: PhantomData }
}
#[allow(clippy::trivially_copy_pass_by_ref)] #[inline]
pub const fn as_raw_fd(&self) -> RawFd {
self.fd
}
}
impl OwnedFd {
#[inline]
pub const unsafe fn from_raw_fd(fd: RawFd) -> Self {
assert!(fd != -1);
Self { fd }
}
#[inline]
pub const fn as_raw_fd(&self) -> RawFd {
self.fd
}
#[inline]
#[must_use = "losing the raw file descriptor may leak resources"]
pub fn into_raw_fd(self) -> RawFd {
let this = ManuallyDrop::new(self);
this.fd
}
}
impl Drop for OwnedFd {
#[inline]
fn drop(&mut self) {
#[cfg(feature = "stdio")]
if !sys::stdio::should_close(self) {
return;
}
let _ = unsafe { sys::close(self.as_raw_fd()) };
}
}
impl fmt::Debug for BorrowedFd<'_> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("BorrowedFd").field("fd", &self.fd).finish()
}
}
impl fmt::Debug for OwnedFd {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("OwnedFd").field("fd", &self.fd).finish()
}
}
pub trait AsFd {
fn as_fd(&self) -> BorrowedFd<'_>;
}
impl<T: ?Sized + AsFd> AsFd for &T {
#[inline]
fn as_fd(&self) -> BorrowedFd<'_> {
T::as_fd(self)
}
}
impl<T: ?Sized + AsFd> AsFd for &mut T {
#[inline]
fn as_fd(&self) -> BorrowedFd<'_> {
T::as_fd(self)
}
}
impl AsFd for BorrowedFd<'_> {
#[inline]
fn as_fd(&self) -> BorrowedFd<'_> {
*self
}
}
impl AsFd for OwnedFd {
#[inline]
fn as_fd(&self) -> BorrowedFd<'_> {
unsafe { BorrowedFd::borrow_raw(self.fd) }
}
}
#[cfg(feature = "alloc")]
impl<T: ?Sized + AsFd> AsFd for alloc::boxed::Box<T> {
#[inline]
fn as_fd(&self) -> BorrowedFd<'_> {
(**self).as_fd()
}
}
#[cfg(feature = "alloc")]
impl<T: ?Sized + AsFd> AsFd for alloc::rc::Rc<T> {
#[inline]
fn as_fd(&self) -> BorrowedFd<'_> {
(**self).as_fd()
}
}
#[cfg(target_has_atomic = "ptr")]
#[cfg(feature = "alloc")]
#[cfg_attr(docsrs, doc(cfg(feature = "alloc")))]
impl<T: ?Sized + AsFd> AsFd for alloc::sync::Arc<T> {
#[inline]
fn as_fd(&self) -> BorrowedFd<'_> {
(**self).as_fd()
}
}
#[cfg(any(feature = "stdio", feature = "fs"))]
macro_rules! impl_as_fd {
($($ty:ty),* $(,)?) => {$(
impl crate::fd::AsFd for $ty {
#[inline]
fn as_fd(&self) -> crate::fd::BorrowedFd<'_> {
self.0.as_fd()
}
}
)*};
}
#[cfg(feature = "fs")]
macro_rules! impl_from_fd {
($($ty:ty),* $(,)?) => {$(
impl From<$ty> for OwnedFd {
#[inline]
fn from(this: $ty) -> Self {
this.0
}
}
impl From<OwnedFd> for $ty {
#[inline]
fn from(owned_fd: OwnedFd) -> Self {
Self(owned_fd)
}
}
)*};
}