microsd 0.2.0

Light‐weight systemd auxiliars
Documentation
//! Convenience wrappers for [`compio`] types.
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};

/// File descriptor wrapper for [`compio`] types.
#[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),
}

/// Listen file descriptor iterator adapter for [`compio`] types.
#[must_use]
#[derive(Debug)]
pub struct ListenFds(crate::ListenFds);

/// Retrieve listen file descriptors as [`compio`] types.
#[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()),
				},
				// Representing UNIX datagram sockets as UdpSocket might break certain operations
				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 {}