use std::os::fd::{BorrowedFd, IntoRawFd, OwnedFd, RawFd};
use std::{fmt, io};
use crate::SubmissionQueue;
#[cfg(any(target_os = "android", target_os = "linux"))]
pub use crate::sys::fd::{ToDirect, ToFd};
#[allow(clippy::module_name_repetitions)]
pub struct AsyncFd {
fd: RawFd,
#[cfg(any(
target_os = "dragonfly",
target_os = "freebsd",
target_os = "ios",
target_os = "macos",
target_os = "netbsd",
target_os = "openbsd",
target_os = "tvos",
target_os = "visionos",
target_os = "watchos",
))]
pub(crate) state: crate::sys::fd::State,
pub(crate) sq: SubmissionQueue,
}
impl AsyncFd {
pub fn new(fd: OwnedFd, sq: SubmissionQueue) -> AsyncFd {
unsafe { AsyncFd::from_raw_fd(fd.into_raw_fd(), sq) }
}
pub unsafe fn from_raw_fd(fd: RawFd, sq: SubmissionQueue) -> AsyncFd {
unsafe { AsyncFd::from_raw(fd, Kind::File, sq) }
}
pub(crate) unsafe fn from_raw(fd: RawFd, kind: Kind, sq: SubmissionQueue) -> AsyncFd {
#[cfg(any(target_os = "android", target_os = "linux"))]
let fd = if let Kind::Direct = kind {
fd | (1 << 31)
} else {
fd
};
#[cfg(any(
target_os = "dragonfly",
target_os = "freebsd",
target_os = "ios",
target_os = "macos",
target_os = "netbsd",
target_os = "openbsd",
target_os = "tvos",
target_os = "visionos",
target_os = "watchos",
))]
let Kind::File = kind;
AsyncFd {
fd,
#[cfg(any(
target_os = "dragonfly",
target_os = "freebsd",
target_os = "ios",
target_os = "macos",
target_os = "netbsd",
target_os = "openbsd",
target_os = "tvos",
target_os = "visionos",
target_os = "watchos",
))]
state: crate::sys::fd::State::new(),
sq,
}
}
pub fn kind(&self) -> Kind {
#[cfg(any(target_os = "android", target_os = "linux"))]
if self.fd.is_negative() {
return Kind::Direct;
}
Kind::File
}
pub fn as_fd(&self) -> Option<BorrowedFd<'_>> {
#[cfg(any(target_os = "android", target_os = "linux"))]
if let Kind::Direct = self.kind() {
return None;
}
unsafe { Some(BorrowedFd::borrow_raw(self.fd())) }
}
#[doc(alias = "dup")]
#[doc(alias = "dup2")]
#[doc(alias = "F_DUPFD")]
#[doc(alias = "F_DUPFD_CLOEXEC")]
pub fn try_clone(&self) -> io::Result<AsyncFd> {
let fd = self.as_fd().ok_or(io::ErrorKind::Unsupported)?;
let fd = fd.try_clone_to_owned()?;
Ok(AsyncFd::new(fd, self.sq.clone()))
}
pub(crate) fn fd(&self) -> RawFd {
self.fd & !(1 << 31)
}
#[cfg(any(
target_os = "dragonfly",
target_os = "freebsd",
target_os = "ios",
target_os = "macos",
target_os = "netbsd",
target_os = "openbsd",
target_os = "tvos",
target_os = "visionos",
target_os = "watchos",
))]
pub(crate) const fn state(&self) -> &crate::sys::fd::State {
&self.state
}
pub(crate) const fn sq(&self) -> &SubmissionQueue {
&self.sq
}
}
impl Unpin for AsyncFd {}
#[allow(clippy::missing_fields_in_debug)] impl fmt::Debug for AsyncFd {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let mut f = f.debug_struct("AsyncFd");
f.field("fd", &self.fd()).field("kind", &self.kind());
#[cfg(any(
target_os = "dragonfly",
target_os = "freebsd",
target_os = "ios",
target_os = "macos",
target_os = "netbsd",
target_os = "openbsd",
target_os = "tvos",
target_os = "visionos",
target_os = "watchos",
))]
f.field("state", &self.state);
f.finish()
}
}
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
#[non_exhaustive]
pub enum Kind {
File,
#[cfg(any(target_os = "android", target_os = "linux"))]
Direct,
}
impl Kind {
#[allow(clippy::semicolon_if_nothing_returned, clippy::unused_self)]
pub(crate) fn cloexec_flag(self) -> libc::c_int {
#[cfg(any(target_os = "android", target_os = "linux"))]
if let Kind::Direct = self {
return 0; }
#[cfg(any(target_os = "android", target_os = "linux"))]
#[allow(clippy::items_after_statements)]
const _: () = assert!(libc::SOCK_CLOEXEC == libc::O_CLOEXEC);
libc::O_CLOEXEC
}
}