use std::os::raw::c_int;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct Fd(pub c_int);
#[derive(Clone, Copy)]
pub struct EncodedFd<T> {
pub(crate) raw: u32,
pub(crate) convert_fd: T,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct InvalidFd;
pub trait ConvertFd: Sync {
fn convert_fd(&self, raw: u32) -> Result<Fd, InvalidFd>;
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct Identity;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct NoConvert;
#[derive(Clone, Copy)]
pub struct ConvertFdFn<F: Fn(u32) -> Result<Fd, InvalidFd>>(pub F);
impl<T: ConvertFd> EncodedFd<T> {
pub fn new(raw: u32, convert_fd: T) -> EncodedFd<T> {
EncodedFd { raw, convert_fd }
}
pub fn raw_encoded_number(&self) -> u32 {
self.raw
}
pub fn to_fd(&self) -> Result<Fd, u32> {
self.convert_fd
.convert_fd(self.raw)
.map_err(|InvalidFd| self.raw)
}
}
impl ConvertFd for Identity {
fn convert_fd(&self, fd: u32) -> Result<Fd, InvalidFd> {
Ok(Fd(fd as c_int))
}
}
impl ConvertFd for NoConvert {
fn convert_fd(&self, _: u32) -> Result<Fd, InvalidFd> {
Err(InvalidFd)
}
}
impl<F> ConvertFd for ConvertFdFn<F>
where
F: Fn(u32) -> Result<Fd, InvalidFd> + Sync,
{
fn convert_fd(&self, fd: u32) -> Result<Fd, InvalidFd> {
self.0(fd)
}
}
impl<'a, T> ConvertFd for &'a T
where
T: ConvertFd + 'a + ?Sized,
{
fn convert_fd(&self, fd: u32) -> Result<Fd, InvalidFd> {
(*self).convert_fd(fd)
}
}
pub trait FdMapping {
fn map(&mut self, fd: Fd) -> u32;
}
impl FdMapping for Vec<Fd> {
fn map(&mut self, new_fd: Fd) -> u32 {
for (i, fd) in self.iter().enumerate() {
if fd.0 == new_fd.0 {
return i as u32;
}
}
let new_i = self.len() as u32;
self.push(new_fd);
new_i
}
}
impl<T> std::fmt::Debug for EncodedFd<T> {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
write!(f, "EncodedFd(0x{:08X})", self.raw)
}
}