microsd 0.1.0

Light‐weight systemd auxiliars
Documentation
use std::iter::FusedIterator;
use std::ops::Range;
use std::os::fd::RawFd;

use nix::unistd::close;

use crate::Error;
use crate::fd::Fd;

/// Listen file descriptor iterator for undifferentiated [`Fd`].
#[must_use]
#[derive(Debug)]
pub struct ListenFds(Range<RawFd>);

impl ListenFds {
	pub(crate) const START: RawFd = 3;

	/// Construct new [`ListenFds`] instance from a file descriptor number.
	///
	/// # Safety
	///
	/// This function is only safe to use if `num` unowned system file
	/// descriptors are available starting from descriptor number `3`
	/// ([`SD_LISTEN_FDS_START`](https://www.freedesktop.org/software/systemd/man/latest/SD_LISTEN_FDS_START.html)).
	///
	/// It is intended to be used with the number provided through the
	/// `LISTEN_FDS` environment variable by the session manager.
	#[inline]
	pub const unsafe fn new(num: u32) -> Self {
		Self(Range { start: Self::START, end: Self::START + num as RawFd })
	}
}

impl Drop for ListenFds {
	fn drop(&mut self) {
		// Close remaining file descriptors
		for fd in &mut self.0 {
			let res = close(fd);
			debug_assert!(res.is_ok());
		}
	}
}

impl Iterator for ListenFds {
	type Item = Result<Fd, Error>;

	#[inline]
	fn next(&mut self) -> Option<Self::Item> {
		self.0.next().map(|fd| unsafe { Fd::try_from(fd) })
	}

	#[inline]
	fn size_hint(&self) -> (usize, Option<usize>) {
		self.0.size_hint()
	}
}

impl DoubleEndedIterator for ListenFds {
	#[inline]
	fn next_back(&mut self) -> Option<Self::Item> {
		self.0.next_back().map(|fd| unsafe { Fd::try_from(fd) })
	}
}

impl ExactSizeIterator for ListenFds {}
impl FusedIterator for ListenFds {}