use std::iter::FusedIterator;
use std::os::unix::fs::FileTypeExt;
use compio::fs::File;
use compio::fs::pipe::{Receiver, Sender};
use compio::net::{TcpListener, TcpStream, UdpSocket, UnixListener, UnixStream};
use crate::{AddressFamily, Error, SockType};
#[must_use]
#[derive(Debug)]
pub enum Fd {
UnixStream(UnixStream),
UnixListener(UnixListener),
TcpStream(TcpStream),
TcpListener(TcpListener),
UdpSocket(UdpSocket),
Receiver(Receiver),
Sender(Sender),
File(File),
Other(crate::Fd),
}
#[must_use]
#[derive(Debug)]
pub struct ListenFds(crate::ListenFds);
#[inline]
pub fn listen_fds() -> ListenFds {
crate::listen_fds().into()
}
impl TryFrom<crate::Fd> for Fd {
type Error = Error;
fn try_from(fd: crate::Fd) -> Result<Self, Self::Error> {
Ok(if fd.is_socket() {
let family = fd.socket_domain()?;
match fd.socket_type()? {
SockType::Stream | SockType::SeqPacket => match (family, fd.is_listening()?) {
(AddressFamily::Unix, false) => Fd::UnixStream(fd.into()),
(AddressFamily::Unix, true) => Fd::UnixListener(fd.into()),
(_, false) => Fd::TcpStream(fd.into()),
(_, true) => Fd::TcpListener(fd.into()),
},
SockType::Datagram => Fd::UdpSocket(fd.into()),
_ => Fd::Other(fd),
}
} else if fd.is_fifo() {
if fd.is_writeable()? {
Fd::Sender(fd.into())
} else {
Fd::Receiver(fd.into())
}
} else if fd.is_char_device() {
Fd::File(fd.into())
} else {
Fd::Other(fd)
})
}
}
impl From<crate::ListenFds> for ListenFds {
#[inline]
fn from(fds: crate::ListenFds) -> Self {
Self(fds)
}
}
impl Iterator for ListenFds {
type Item = Result<Fd, Error>;
#[inline]
fn next(&mut self) -> Option<Self::Item> {
self.0.next().map(|fd| fd?.try_into())
}
}
impl DoubleEndedIterator for ListenFds {
#[inline]
fn next_back(&mut self) -> Option<Self::Item> {
self.0.next_back().map(|fd| fd?.try_into())
}
}
impl ExactSizeIterator for ListenFds {}
impl FusedIterator for ListenFds {}